summaryrefslogtreecommitdiffstats
path: root/js/src/vm
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm')
-rw-r--r--js/src/vm/ArrayBufferObject.h9
-rw-r--r--js/src/vm/Caches.h16
-rw-r--r--js/src/vm/Interpreter.cpp14
-rw-r--r--js/src/vm/Interpreter.h3
-rw-r--r--js/src/vm/ObjectGroup.cpp8
-rw-r--r--js/src/vm/Runtime.cpp14
-rw-r--r--js/src/vm/Runtime.h25
-rw-r--r--js/src/vm/Scope.cpp20
-rw-r--r--js/src/vm/Scope.h120
-rw-r--r--js/src/vm/SelfHosting.cpp18
-rw-r--r--js/src/vm/Stopwatch.cpp48
-rw-r--r--js/src/vm/Stopwatch.h30
-rw-r--r--js/src/vm/String.h11
-rw-r--r--js/src/vm/Time.cpp11
-rw-r--r--js/src/vm/TypeInference.cpp28
-rw-r--r--js/src/vm/TypeInference.h25
-rw-r--r--js/src/vm/TypedArrayCommon.h21
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) {