diff options
Diffstat (limited to 'js/src/vm')
-rw-r--r-- | js/src/vm/ArrayBufferObject.h | 9 | ||||
-rw-r--r-- | js/src/vm/Caches.h | 16 | ||||
-rw-r--r-- | js/src/vm/Interpreter.cpp | 14 | ||||
-rw-r--r-- | js/src/vm/Interpreter.h | 3 | ||||
-rw-r--r-- | js/src/vm/ObjectGroup.cpp | 8 | ||||
-rw-r--r-- | js/src/vm/Runtime.cpp | 14 | ||||
-rw-r--r-- | js/src/vm/Runtime.h | 25 | ||||
-rw-r--r-- | js/src/vm/Scope.cpp | 20 | ||||
-rw-r--r-- | js/src/vm/Scope.h | 120 | ||||
-rw-r--r-- | js/src/vm/SelfHosting.cpp | 18 | ||||
-rw-r--r-- | js/src/vm/Stopwatch.cpp | 48 | ||||
-rw-r--r-- | js/src/vm/Stopwatch.h | 30 | ||||
-rw-r--r-- | js/src/vm/String.h | 11 | ||||
-rw-r--r-- | js/src/vm/Time.cpp | 11 | ||||
-rw-r--r-- | js/src/vm/TypeInference.cpp | 28 | ||||
-rw-r--r-- | js/src/vm/TypeInference.h | 25 | ||||
-rw-r--r-- | js/src/vm/TypedArrayCommon.h | 21 |
17 files changed, 204 insertions, 217 deletions
diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h index 6614f5220..e9c9bc0e0 100644 --- a/js/src/vm/ArrayBufferObject.h +++ b/js/src/vm/ArrayBufferObject.h @@ -457,8 +457,8 @@ ClampDoubleToUint8(const double x); struct uint8_clamped { uint8_t val; - uint8_clamped() { } - uint8_clamped(const uint8_clamped& other) : val(other.val) { } + uint8_clamped() = default; + uint8_clamped(const uint8_clamped& other) = default; // invoke our assignment helpers for constructor conversion explicit uint8_clamped(uint8_t x) { *this = x; } @@ -469,10 +469,7 @@ struct uint8_clamped { explicit uint8_clamped(int32_t x) { *this = x; } explicit uint8_clamped(double x) { *this = x; } - uint8_clamped& operator=(const uint8_clamped& x) { - val = x.val; - return *this; - } + uint8_clamped& operator=(const uint8_clamped& x) = default; uint8_clamped& operator=(uint8_t x) { val = x; diff --git a/js/src/vm/Caches.h b/js/src/vm/Caches.h index 91a78bdc8..b11dd9dcb 100644 --- a/js/src/vm/Caches.h +++ b/js/src/vm/Caches.h @@ -7,6 +7,8 @@ #ifndef vm_Caches_h #define vm_Caches_h +#include <new> + #include "jsatom.h" #include "jsbytecode.h" #include "jsobj.h" @@ -191,14 +193,20 @@ class NewObjectCache char templateObject[MAX_OBJ_SIZE]; }; - Entry entries[41]; // TODO: reconsider size + using EntryArray = Entry[41]; // TODO: reconsider size; + EntryArray entries; public: - typedef int EntryIndex; + using EntryIndex = int; + + NewObjectCache() + : entries{} // zeroes out the array + {} - NewObjectCache() { mozilla::PodZero(this); } - void purge() { mozilla::PodZero(this); } + void purge() { + new (&entries) EntryArray{}; // zeroes out the array + } /* Remove any cached items keyed on moved objects. */ void clearNurseryObjects(JSRuntime* rt); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index b747e4d7a..e6d6630c4 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -718,14 +718,14 @@ js::Execute(JSContext* cx, HandleScript script, JSObject& envChainArg, Value* rv } /* - * ES6 (4-25-16) 12.10.4 InstanceofOperator + * ES6 12.9.4 InstanceofOperator */ extern bool -js::InstanceOfOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp) +JS::InstanceofOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp) { /* Step 1. is handled by caller. */ - /* Step 2. */ + /* Step 2-3. */ RootedValue hasInstance(cx); RootedId id(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().hasInstance)); if (!GetProperty(cx, obj, obj, id, &hasInstance)) @@ -735,7 +735,7 @@ js::InstanceOfOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp) if (!IsCallable(hasInstance)) return ReportIsNotFunction(cx, hasInstance); - /* Step 3. */ + /* Step 4. */ RootedValue rval(cx); if (!Call(cx, hasInstance, obj, v, &rval)) return false; @@ -743,13 +743,13 @@ js::InstanceOfOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp) return true; } - /* Step 4. */ + /* Step 5. */ if (!obj->isCallable()) { RootedValue val(cx, ObjectValue(*obj)); return ReportIsNotFunction(cx, val); } - /* Step 5. */ + /* Step 6. */ return OrdinaryHasInstance(cx, obj, v, bp); } @@ -760,7 +760,7 @@ js::HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp) RootedValue local(cx, v); if (JSHasInstanceOp hasInstance = clasp->getHasInstance()) return hasInstance(cx, obj, &local, bp); - return js::InstanceOfOperator(cx, obj, local, bp); + return JS::InstanceofOperator(cx, obj, local, bp); } static inline bool diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index 330dbef5f..9fefd75cc 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -323,9 +323,6 @@ extern JSType TypeOfValue(const Value& v); extern bool -InstanceOfOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp); - -extern bool HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp); // Unwind environment chain and iterator to match the scope corresponding to diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index d6a8fcaa4..46159a972 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -495,13 +495,7 @@ ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp, if (associated->is<JSFunction>()) { // Canonicalize new functions to use the original one associated with its script. - JSFunction* fun = &associated->as<JSFunction>(); - if (fun->hasScript()) - associated = fun->nonLazyScript()->functionNonDelazifying(); - else if (fun->isInterpretedLazy() && !fun->isSelfHostedBuiltin()) - associated = fun->lazyScript()->functionNonDelazifying(); - else - associated = nullptr; + associated = associated->as<JSFunction>().maybeCanonicalFunction(); // If we have previously cleared the 'new' script information for this // function, don't try to construct another one. diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 174e23594..8eb997c71 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -147,7 +147,6 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime) updateChildRuntimeCount(parentRuntime), #endif interrupt_(false), - telemetryCallback(nullptr), handlingSegFault(false), handlingJitInterrupt_(false), interruptCallbackDisabled(false), @@ -452,19 +451,6 @@ JSRuntime::destroyRuntime() } void -JSRuntime::addTelemetry(int id, uint32_t sample, const char* key) -{ - if (telemetryCallback) - (*telemetryCallback)(id, sample, key); -} - -void -JSRuntime::setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback) -{ - rt->telemetryCallback = callback; -} - -void JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* rtSizes) { // Several tables in the runtime enumerated below can be used off thread. diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 735adadf2..e60371e38 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -11,11 +11,11 @@ #include "mozilla/Attributes.h" #include "mozilla/LinkedList.h" #include "mozilla/MemoryReporting.h" -#include "mozilla/PodOperations.h" #include "mozilla/Scoped.h" #include "mozilla/ThreadLocal.h" #include "mozilla/Vector.h" +#include <algorithm> #include <setjmp.h> #include "jsatom.h" @@ -577,17 +577,7 @@ struct JSRuntime : public JS::shadow::Runtime, #endif mozilla::Atomic<uint32_t, mozilla::Relaxed> interrupt_; - - /* Call this to accumulate telemetry data. */ - JSAccumulateTelemetryDataCallback telemetryCallback; public: - // Accumulates data for Firefox telemetry. |id| is the ID of a JS_TELEMETRY_* - // histogram. |key| provides an additional key to identify the histogram. - // |sample| is the data to add to the histogram. - void addTelemetry(int id, uint32_t sample, const char* key = nullptr); - - void setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback); - enum InterruptMode { RequestInterruptUrgent, RequestInterruptCanWait @@ -1504,20 +1494,21 @@ PerThreadData::exclusiveThreadsPresent() static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(Value* vec, size_t len) { - mozilla::PodZero(vec, len); + // Don't PodZero here because JS::Value is non-trivial. + for (size_t i = 0; i < len; i++) + vec[i].setDouble(+0.0); } static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(Value* beg, Value* end) { - mozilla::PodZero(beg, end - beg); + MakeRangeGCSafe(beg, end - beg); } static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(jsid* beg, jsid* end) { - for (jsid* id = beg; id != end; ++id) - *id = INT_TO_JSID(0); + std::fill(beg, end, INT_TO_JSID(0)); } static MOZ_ALWAYS_INLINE void @@ -1529,13 +1520,13 @@ MakeRangeGCSafe(jsid* vec, size_t len) static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(Shape** beg, Shape** end) { - mozilla::PodZero(beg, end - beg); + std::fill(beg, end, nullptr); } static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(Shape** vec, size_t len) { - mozilla::PodZero(vec, len); + MakeRangeGCSafe(vec, vec + len); } static MOZ_ALWAYS_INLINE void diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp index 112b34586..a71c03695 100644 --- a/js/src/vm/Scope.cpp +++ b/js/src/vm/Scope.cpp @@ -191,12 +191,12 @@ template <typename ConcreteScope> static UniquePtr<typename ConcreteScope::Data> NewEmptyScopeData(ExclusiveContext* cx, uint32_t length = 0) { - uint8_t* bytes = cx->zone()->pod_calloc<uint8_t>(ConcreteScope::sizeOfData(length)); + uint8_t* bytes = cx->zone()->pod_malloc<uint8_t>(ConcreteScope::sizeOfData(length)); if (!bytes) ReportOutOfMemory(cx); auto data = reinterpret_cast<typename ConcreteScope::Data*>(bytes); if (data) - new (data) typename ConcreteScope::Data(); + new (data) typename ConcreteScope::Data(length); return UniquePtr<typename ConcreteScope::Data>(data); } @@ -273,7 +273,7 @@ Scope::XDRSizedBindingNames(XDRState<mode>* xdr, Handle<ConcreteScope*> scope, } for (uint32_t i = 0; i < length; i++) { - if (!XDRBindingName(xdr, &data->names[i])) { + if (!XDRBindingName(xdr, &data->trailingNames[i])) { if (mode == XDR_DECODE) { DeleteScopeData(data.get()); data.set(nullptr); @@ -1250,7 +1250,7 @@ BindingIter::init(LexicalScope::Data& data, uint32_t firstFrameSlot, uint8_t fla init(0, 0, 0, 0, 0, 0, CanHaveEnvironmentSlots | flags, firstFrameSlot, JSSLOT_FREE(&LexicalEnvironmentObject::class_), - data.names, data.length); + data.trailingNames.start(), data.length); } else { // imports - [0, 0) // positional formals - [0, 0) @@ -1262,7 +1262,7 @@ BindingIter::init(LexicalScope::Data& data, uint32_t firstFrameSlot, uint8_t fla init(0, 0, 0, 0, 0, data.constStart, CanHaveFrameSlots | CanHaveEnvironmentSlots | flags, firstFrameSlot, JSSLOT_FREE(&LexicalEnvironmentObject::class_), - data.names, data.length); + data.trailingNames.start(), data.length); } } @@ -1283,7 +1283,7 @@ BindingIter::init(FunctionScope::Data& data, uint8_t flags) init(0, data.nonPositionalFormalStart, data.varStart, data.varStart, data.length, data.length, flags, 0, JSSLOT_FREE(&CallObject::class_), - data.names, data.length); + data.trailingNames.start(), data.length); } void @@ -1299,7 +1299,7 @@ BindingIter::init(VarScope::Data& data, uint32_t firstFrameSlot) init(0, 0, 0, 0, data.length, data.length, CanHaveFrameSlots | CanHaveEnvironmentSlots, firstFrameSlot, JSSLOT_FREE(&VarEnvironmentObject::class_), - data.names, data.length); + data.trailingNames.start(), data.length); } void @@ -1315,7 +1315,7 @@ BindingIter::init(GlobalScope::Data& data) init(0, 0, 0, data.varStart, data.letStart, data.constStart, CannotHaveSlots, UINT32_MAX, UINT32_MAX, - data.names, data.length); + data.trailingNames.start(), data.length); } void @@ -1343,7 +1343,7 @@ BindingIter::init(EvalScope::Data& data, bool strict) // consts - [data.length, data.length) init(0, 0, 0, data.varStart, data.length, data.length, flags, firstFrameSlot, firstEnvironmentSlot, - data.names, data.length); + data.trailingNames.start(), data.length); } void @@ -1359,7 +1359,7 @@ BindingIter::init(ModuleScope::Data& data) init(data.varStart, data.varStart, data.varStart, data.varStart, data.letStart, data.constStart, CanHaveFrameSlots | CanHaveEnvironmentSlots, 0, JSSLOT_FREE(&ModuleEnvironmentObject::class_), - data.names, data.length); + data.trailingNames.start(), data.length); } PositionalFormalParameterIter::PositionalFormalParameterIter(JSScript* script) diff --git a/js/src/vm/Scope.h b/js/src/vm/Scope.h index 5304d6713..1d04fd9f6 100644 --- a/js/src/vm/Scope.h +++ b/js/src/vm/Scope.h @@ -12,6 +12,7 @@ #include "jsobj.h" #include "jsopcode.h" +#include "jsutil.h" #include "gc/Heap.h" #include "gc/Policy.h" @@ -111,6 +112,47 @@ class BindingName void trace(JSTracer* trc); }; +/** + * The various {Global,Module,...}Scope::Data classes consist of always-present + * bits, then a trailing array of BindingNames. The various Data classes all + * end in a TrailingNamesArray that contains sized/aligned space for *one* + * BindingName. Data instances that contain N BindingNames, are then allocated + * in sizeof(Data) + (space for (N - 1) BindingNames). Because this class's + * |data_| field is properly sized/aligned, the N-BindingName array can start + * at |data_|. + * + * This is concededly a very low-level representation, but we want to only + * allocate once for data+bindings both, and this does so approximately as + * elegantly as C++ allows. + */ +class TrailingNamesArray +{ + private: + alignas(BindingName) unsigned char data_[sizeof(BindingName)]; + + private: + // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a + // -Werror compile error) to reinterpret_cast<> |data_| to |T*|, even + // through |void*|. Placing the latter cast in these separate functions + // breaks the chain such that affected GCC versions no longer warn/error. + void* ptr() { + return data_; + } + + public: + // Explicitly ensure no one accidentally allocates scope data without + // poisoning its trailing names. + TrailingNamesArray() = delete; + + explicit TrailingNamesArray(size_t nameCount) { + if (nameCount) + JS_POISON(&data_, 0xCC, sizeof(BindingName) * nameCount); + } + BindingName* start() { return reinterpret_cast<BindingName*>(ptr()); } + + BindingName& operator[](size_t i) { return start()[i]; } +}; + class BindingLocation { public: @@ -337,16 +379,19 @@ class LexicalScope : public Scope // // lets - [0, constStart) // consts - [constStart, length) - uint32_t constStart; - uint32_t length; + uint32_t constStart = 0; + uint32_t length = 0; // Frame slots [0, nextFrameSlot) are live when this is the innermost // scope. - uint32_t nextFrameSlot; + uint32_t nextFrameSlot = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; + + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; void trace(JSTracer* trc); }; @@ -433,11 +478,11 @@ class FunctionScope : public Scope // The canonical function of the scope, as during a scope walk we // often query properties of the JSFunction (e.g., is the function an // arrow). - GCPtrFunction canonicalFunction; + GCPtrFunction canonicalFunction = {}; // If parameter expressions are present, parameters act like lexical // bindings. - bool hasParameterExprs; + bool hasParameterExprs = false; // Bindings are sorted by kind in both frames and environments. // @@ -452,17 +497,20 @@ class FunctionScope : public Scope // positional formals - [0, nonPositionalFormalStart) // other formals - [nonPositionalParamStart, varStart) // vars - [varStart, length) - uint16_t nonPositionalFormalStart; - uint16_t varStart; - uint32_t length; + uint16_t nonPositionalFormalStart = 0; + uint16_t varStart = 0; + uint32_t length = 0; // Frame slots [0, nextFrameSlot) are live when this is the innermost // scope. - uint32_t nextFrameSlot; + uint32_t nextFrameSlot = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; + + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; void trace(JSTracer* trc); }; @@ -548,15 +596,18 @@ class VarScope : public Scope struct Data { // All bindings are vars. - uint32_t length; + uint32_t length = 0; // Frame slots [firstFrameSlot(), nextFrameSlot) are live when this is // the innermost scope. - uint32_t nextFrameSlot; + uint32_t nextFrameSlot = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; + + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; void trace(JSTracer* trc); }; @@ -638,14 +689,17 @@ class GlobalScope : public Scope // vars - [varStart, letStart) // lets - [letStart, constStart) // consts - [constStart, length) - uint32_t varStart; - uint32_t letStart; - uint32_t constStart; - uint32_t length; + uint32_t varStart = 0; + uint32_t letStart = 0; + uint32_t constStart = 0; + uint32_t length = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; + + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; void trace(JSTracer* trc); }; @@ -736,16 +790,19 @@ class EvalScope : public Scope // // top-level funcs - [0, varStart) // vars - [varStart, length) - uint32_t varStart; - uint32_t length; + uint32_t varStart = 0; + uint32_t length = 0; // Frame slots [0, nextFrameSlot) are live when this is the innermost // scope. - uint32_t nextFrameSlot; + uint32_t nextFrameSlot = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; + + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; void trace(JSTracer* trc); }; @@ -827,7 +884,7 @@ class ModuleScope : public Scope struct Data { // The module of the scope. - GCPtr<ModuleObject*> module; + GCPtr<ModuleObject*> module = {}; // Bindings are sorted by kind. // @@ -835,18 +892,21 @@ class ModuleScope : public Scope // vars - [varStart, letStart) // lets - [letStart, constStart) // consts - [constStart, length) - uint32_t varStart; - uint32_t letStart; - uint32_t constStart; - uint32_t length; + uint32_t varStart = 0; + uint32_t letStart = 0; + uint32_t constStart = 0; + uint32_t length = 0; // Frame slots [0, nextFrameSlot) are live when this is the innermost // scope. - uint32_t nextFrameSlot; + uint32_t nextFrameSlot = 0; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; + + explicit Data(size_t nameCount) : trailingNames(nameCount) {} + Data() = delete; void trace(JSTracer* trc); }; diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 08670c833..328a960b6 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -1904,23 +1904,6 @@ intrinsic_RuntimeDefaultLocale(JSContext* cx, unsigned argc, Value* vp) } static bool -intrinsic_AddContentTelemetry(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - MOZ_ASSERT(args.length() == 2); - - int id = args[0].toInt32(); - MOZ_ASSERT(id < JS_TELEMETRY_END); - MOZ_ASSERT(id >= 0); - - if (!cx->compartment()->isProbablySystemOrAddonCode()) - cx->runtime()->addTelemetry(id, args[1].toInt32()); - - args.rval().setUndefined(); - return true; -} - -static bool intrinsic_ConstructFunction(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); @@ -2273,7 +2256,6 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("DecompileArg", intrinsic_DecompileArg, 2,0), JS_FN("_FinishBoundFunctionInit", intrinsic_FinishBoundFunctionInit, 3,0), JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0), - JS_FN("AddContentTelemetry", intrinsic_AddContentTelemetry, 2,0), JS_INLINABLE_FN("_IsConstructing", intrinsic_IsConstructing, 0,0, IntrinsicIsConstructing), diff --git a/js/src/vm/Stopwatch.cpp b/js/src/vm/Stopwatch.cpp index 28632c2a1..684846f00 100644 --- a/js/src/vm/Stopwatch.cpp +++ b/js/src/vm/Stopwatch.cpp @@ -20,6 +20,7 @@ #include "gc/Zone.h" #include "vm/Runtime.h" + namespace js { bool @@ -136,6 +137,9 @@ PerformanceMonitoring::start() bool PerformanceMonitoring::commit() { + // Maximal initialization size, in elements for the vector of groups. + static const size_t MAX_GROUPS_INIT_CAPACITY = 1024; + #if !defined(MOZ_HAVE_RDTSC) // The AutoStopwatch is only executed if `MOZ_HAVE_RDTSC`. return false; @@ -152,13 +156,24 @@ PerformanceMonitoring::commit() return true; } - PerformanceGroupVector recentGroups; - recentGroups_.swap(recentGroups); + // The move operation is generally constant time, unless + // `recentGroups_.length()` is very small, in which case + // it's fast just because it's small. + PerformanceGroupVector recentGroups(Move(recentGroups_)); + recentGroups_ = PerformanceGroupVector(); // Reconstruct after `Move`. bool success = true; if (stopwatchCommitCallback) success = stopwatchCommitCallback(iteration_, recentGroups, stopwatchCommitClosure); + // Heuristic: we expect to have roughly the same number of groups as in + // the previous iteration. + const size_t capacity = recentGroups.capacity() < MAX_GROUPS_INIT_CAPACITY ? + recentGroups.capacity() : + MAX_GROUPS_INIT_CAPACITY; + success = recentGroups_.reserve(capacity) + && success; + // Reset immediately, to make sure that we're not hit by the end // of a nested event loop (which would cause `commit` to be called // twice in succession). @@ -227,7 +242,7 @@ AutoStopwatch::AutoStopwatch(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IM MOZ_GUARD_OBJECT_NOTIFIER_INIT; JSCompartment* compartment = cx_->compartment(); - if (compartment->scheduledForDestruction) + if (MOZ_UNLIKELY(compartment->scheduledForDestruction)) return; JSRuntime* runtime = cx_->runtime(); @@ -266,11 +281,11 @@ AutoStopwatch::~AutoStopwatch() } JSCompartment* compartment = cx_->compartment(); - if (compartment->scheduledForDestruction) + if (MOZ_UNLIKELY(compartment->scheduledForDestruction)) return; JSRuntime* runtime = cx_->runtime(); - if (iteration_ != runtime->performanceMonitoring.iteration()) { + if (MOZ_UNLIKELY(iteration_ != runtime->performanceMonitoring.iteration())) { // We have entered a nested event loop at some point. // Any information we may have is obsolete. return; @@ -319,11 +334,6 @@ AutoStopwatch::exit() const uint64_t cyclesEnd = getCycles(runtime); cyclesDelta = cyclesEnd - cyclesStart_; // Always >= 0 by definition of `getCycles`. } -#if WINVER >= 0x600 - updateTelemetry(cpuStart_, cpuEnd); -#elif defined(__linux__) - updateTelemetry(cpuStart_, cpuEnd); -#endif // WINVER >= 0x600 || _linux__ } uint64_t CPOWTimeDelta = 0; @@ -335,17 +345,6 @@ AutoStopwatch::exit() return addToGroups(cyclesDelta, CPOWTimeDelta); } -void -AutoStopwatch::updateTelemetry(const cpuid_t& cpuStart_, const cpuid_t& cpuEnd) -{ - JSRuntime* runtime = cx_->runtime(); - - if (isSameCPU(cpuStart_, cpuEnd)) - runtime->performanceMonitoring.testCpuRescheduling.stayed += 1; - else - runtime->performanceMonitoring.testCpuRescheduling.moved += 1; -} - PerformanceGroup* AutoStopwatch::acquireGroup(PerformanceGroup* group) { @@ -638,13 +637,6 @@ GetStopwatchIsMonitoringCPOW(JSContext* cx) } JS_PUBLIC_API(void) -GetPerfMonitoringTestCpuRescheduling(JSContext* cx, uint64_t* stayed, uint64_t* moved) -{ - *stayed = cx->performanceMonitoring.testCpuRescheduling.stayed; - *moved = cx->performanceMonitoring.testCpuRescheduling.moved; -} - -JS_PUBLIC_API(void) AddCPOWPerformanceDelta(JSContext* cx, uint64_t delta) { cx->performanceMonitoring.totalCPOWTime += delta; diff --git a/js/src/vm/Stopwatch.h b/js/src/vm/Stopwatch.h index 38a3eb801..d7f299594 100644 --- a/js/src/vm/Stopwatch.h +++ b/js/src/vm/Stopwatch.h @@ -217,33 +217,6 @@ struct PerformanceMonitoring { */ uint64_t monotonicReadTimestampCounter(); - /** - * Data extracted by the AutoStopwatch to determine how often - * we reschedule the process to a different CPU during the - * execution of JS. - * - * Warning: These values are incremented *only* on platforms - * that offer a syscall/libcall to check on which CPU a - * process is currently executed. - */ - struct TestCpuRescheduling - { - // Incremented once we have finished executing code - // in a group, if the CPU on which we started - // execution is the same as the CPU on which - // we finished. - uint64_t stayed; - // Incremented once we have finished executing code - // in a group, if the CPU on which we started - // execution is different from the CPU on which - // we finished. - uint64_t moved; - TestCpuRescheduling() - : stayed(0), - moved(0) - { } - }; - TestCpuRescheduling testCpuRescheduling; private: PerformanceMonitoring(const PerformanceMonitoring&) = delete; PerformanceMonitoring& operator=(const PerformanceMonitoring&) = delete; @@ -375,9 +348,6 @@ class AutoStopwatch final { // Add recent changes to a single group. Mark the group as changed recently. bool addToGroup(JSRuntime* runtime, uint64_t cyclesDelta, uint64_t CPOWTimeDelta, PerformanceGroup* group); - // Update telemetry statistics. - void updateTelemetry(const cpuid_t& a, const cpuid_t& b); - // Perform a subtraction for a quantity that should be monotonic // but is not guaranteed to be so. // diff --git a/js/src/vm/String.h b/js/src/vm/String.h index 1a0c58575..514e2c205 100644 --- a/js/src/vm/String.h +++ b/js/src/vm/String.h @@ -8,7 +8,6 @@ #define vm_String_h #include "mozilla/MemoryReporting.h" -#include "mozilla/PodOperations.h" #include "mozilla/Range.h" #include "jsapi.h" @@ -1087,19 +1086,17 @@ class StaticStrings static const size_t SMALL_CHAR_LIMIT = 128U; static const size_t NUM_SMALL_CHARS = 64U; - JSAtom* length2StaticTable[NUM_SMALL_CHARS * NUM_SMALL_CHARS]; + JSAtom* length2StaticTable[NUM_SMALL_CHARS * NUM_SMALL_CHARS] = {}; // zeroes public: /* We keep these public for the JITs. */ static const size_t UNIT_STATIC_LIMIT = 256U; - JSAtom* unitStaticTable[UNIT_STATIC_LIMIT]; + JSAtom* unitStaticTable[UNIT_STATIC_LIMIT] = {}; // zeroes static const size_t INT_STATIC_LIMIT = 256U; - JSAtom* intStaticTable[INT_STATIC_LIMIT]; + JSAtom* intStaticTable[INT_STATIC_LIMIT] = {}; // zeroes - StaticStrings() { - mozilla::PodZero(this); - } + StaticStrings() = default; bool init(JSContext* cx); void trace(JSTracer* trc); diff --git a/js/src/vm/Time.cpp b/js/src/vm/Time.cpp index 69e2cc41d..87531c148 100644 --- a/js/src/vm/Time.cpp +++ b/js/src/vm/Time.cpp @@ -11,9 +11,6 @@ #include "mozilla/DebugOnly.h" #include "mozilla/MathAlgorithms.h" -#ifdef SOLARIS -#define _REENTRANT 1 -#endif #include <string.h> #include <time.h> @@ -33,10 +30,6 @@ #ifdef XP_UNIX -#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */ -extern int gettimeofday(struct timeval* tv); -#endif - #include <sys/time.h> #endif /* XP_UNIX */ @@ -49,11 +42,7 @@ PRMJ_Now() { struct timeval tv; -#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */ - gettimeofday(&tv); -#else gettimeofday(&tv, 0); -#endif /* _SVID_GETTOD */ return int64_t(tv.tv_sec) * PRMJ_USEC_PER_SEC + int64_t(tv.tv_usec); } diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 3d09c7464..4775a2dea 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -12,6 +12,8 @@ #include "mozilla/SizePrintfMacros.h" #include "mozilla/Sprintf.h" +#include <new> + #include "jsapi.h" #include "jscntxt.h" #include "jsgc.h" @@ -859,10 +861,8 @@ TypeSet::IsTypeAboutToBeFinalized(TypeSet::Type* v) } bool -TypeSet::clone(LifoAlloc* alloc, TemporaryTypeSet* result) const +TypeSet::cloneIntoUninitialized(LifoAlloc* alloc, TemporaryTypeSet* result) const { - MOZ_ASSERT(result->empty()); - unsigned objectCount = baseObjectCount(); unsigned capacity = (objectCount >= 2) ? TypeHashSet::Capacity(objectCount) : 0; @@ -874,15 +874,15 @@ TypeSet::clone(LifoAlloc* alloc, TemporaryTypeSet* result) const PodCopy(newSet, objectSet, capacity); } - new(result) TemporaryTypeSet(flags, capacity ? newSet : objectSet); + new (result) TemporaryTypeSet(flags, capacity ? newSet : objectSet); return true; } TemporaryTypeSet* TypeSet::clone(LifoAlloc* alloc) const { - TemporaryTypeSet* res = alloc->new_<TemporaryTypeSet>(); - if (!res || !clone(alloc, res)) + TemporaryTypeSet* res = alloc->pod_malloc<TemporaryTypeSet>(); + if (!res || !cloneIntoUninitialized(alloc, res)) return nullptr; return res; } @@ -1150,10 +1150,9 @@ TypeScript::FreezeTypeSets(CompilerConstraintList* constraints, JSScript* script TemporaryTypeSet* types = alloc->newArrayUninitialized<TemporaryTypeSet>(count); if (!types) return false; - PodZero(types, count); for (size_t i = 0; i < count; i++) { - if (!existing[i].clone(alloc, &types[i])) + if (!existing[i].cloneIntoUninitialized(alloc, &types[i])) return false; } @@ -3604,6 +3603,10 @@ TypeNewScript::make(JSContext* cx, ObjectGroup* group, JSFunction* fun) MOZ_ASSERT(!group->newScript()); MOZ_ASSERT(!group->maybeUnboxedLayout()); + // rollbackPartiallyInitializedObjects expects function_ to be + // canonicalized. + MOZ_ASSERT(fun->maybeCanonicalFunction() == fun); + if (group->unknownProperties()) return true; @@ -3959,8 +3962,15 @@ TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* g oomUnsafe.crash("rollbackPartiallyInitializedObjects"); } - if (!iter.isConstructing() || !iter.matchCallee(cx, function)) + if (!iter.isConstructing()) { continue; + } + + MOZ_ASSERT(iter.calleeTemplate()->maybeCanonicalFunction()); + + if (iter.calleeTemplate()->maybeCanonicalFunction() != function) { + continue; + } // Derived class constructors initialize their this-binding later and // we shouldn't run the definite properties analysis on them. diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index 9ba1c3cc8..0f1cd4936 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -498,7 +498,10 @@ class TypeSet // Clone a type set into an arbitrary allocator. TemporaryTypeSet* clone(LifoAlloc* alloc) const; - bool clone(LifoAlloc* alloc, TemporaryTypeSet* result) const; + + // |*result| is not even partly initialized when this function is called: + // this function placement-new's its contents into existence. + bool cloneIntoUninitialized(LifoAlloc* alloc, TemporaryTypeSet* result) const; // Create a new TemporaryTypeSet where undefined and/or null has been filtered out. TemporaryTypeSet* filter(LifoAlloc* alloc, bool filterUndefined, bool filterNull) const; @@ -807,12 +810,10 @@ class PreliminaryObjectArray private: // All objects with the type which have been allocated. The pointers in // this array are weak. - JSObject* objects[COUNT]; + JSObject* objects[COUNT] = {}; // zeroes public: - PreliminaryObjectArray() { - mozilla::PodZero(this); - } + PreliminaryObjectArray() = default; void registerNewObject(JSObject* res); void unregisterObject(JSObject* obj); @@ -906,11 +907,11 @@ class TypeNewScript private: // Scripted function which this information was computed for. - HeapPtr<JSFunction*> function_; + HeapPtr<JSFunction*> function_ = {}; // Any preliminary objects with the type. The analyses are not performed // until this array is cleared. - PreliminaryObjectArray* preliminaryObjects; + PreliminaryObjectArray* preliminaryObjects = nullptr; // After the new script properties analyses have been performed, a template // object to use for newly constructed objects. The shape of this object @@ -918,7 +919,7 @@ class TypeNewScript // allocation kind to use. This is null if the new objects have an unboxed // layout, in which case the UnboxedLayout provides the initial structure // of the object. - HeapPtr<PlainObject*> templateObject_; + HeapPtr<PlainObject*> templateObject_ = {}; // Order in which definite properties become initialized. We need this in // case the definite properties are invalidated (such as by adding a setter @@ -928,21 +929,21 @@ class TypeNewScript // shape. Property assignments in inner frames are preceded by a series of // SETPROP_FRAME entries specifying the stack down to the frame containing // the write. - Initializer* initializerList; + Initializer* initializerList = nullptr; // If there are additional properties found by the acquired properties // analysis which were not found by the definite properties analysis, this // shape contains all such additional properties (plus the definite // properties). When an object of this group acquires this shape, it is // fully initialized and its group can be changed to initializedGroup. - HeapPtr<Shape*> initializedShape_; + HeapPtr<Shape*> initializedShape_ = {}; // Group with definite properties set for all properties found by // both the definite and acquired properties analyses. - HeapPtr<ObjectGroup*> initializedGroup_; + HeapPtr<ObjectGroup*> initializedGroup_ = {}; public: - TypeNewScript() { mozilla::PodZero(this); } + TypeNewScript() = default; ~TypeNewScript() { js_delete(preliminaryObjects); js_free(initializerList); diff --git a/js/src/vm/TypedArrayCommon.h b/js/src/vm/TypedArrayCommon.h index d29c93a65..f59419b28 100644 --- a/js/src/vm/TypedArrayCommon.h +++ b/js/src/vm/TypedArrayCommon.h @@ -11,7 +11,8 @@ #include "mozilla/Assertions.h" #include "mozilla/FloatingPoint.h" -#include "mozilla/PodOperations.h" + +#include <algorithm> #include "jsarray.h" #include "jscntxt.h" @@ -245,12 +246,24 @@ class UnsharedOps template<typename T> static void podCopy(SharedMem<T*> dest, SharedMem<T*> src, size_t nelem) { - mozilla::PodCopy(dest.unwrapUnshared(), src.unwrapUnshared(), nelem); + // std::copy_n better matches the argument values/types of this + // function, but as noted below it allows the input/output ranges to + // overlap. std::copy does not, so use it so the compiler has extra + // ability to optimize. + const auto* first = src.unwrapUnshared(); + const auto* last = first + nelem; + auto* result = dest.unwrapUnshared(); + std::copy(first, last, result); } template<typename T> - static void podMove(SharedMem<T*> dest, SharedMem<T*> src, size_t nelem) { - mozilla::PodMove(dest.unwrapUnshared(), src.unwrapUnshared(), nelem); + static void podMove(SharedMem<T*> dest, SharedMem<T*> src, size_t n) { + // std::copy_n copies from |src| to |dest| starting from |src|, so + // input/output ranges *may* permissibly overlap, as this function + // allows. + const auto* start = src.unwrapUnshared(); + auto* result = dest.unwrapUnshared(); + std::copy_n(start, n, result); } static SharedMem<void*> extract(TypedArrayObject* obj) { |