summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--js/src/ds/LifoAlloc.h16
-rw-r--r--js/src/frontend/Parser.cpp8
-rw-r--r--js/src/vm/Scope.cpp4
-rw-r--r--js/src/vm/Scope.h75
4 files changed, 72 insertions, 31 deletions
diff --git a/js/src/ds/LifoAlloc.h b/js/src/ds/LifoAlloc.h
index f349cd476..b4e9c3418 100644
--- a/js/src/ds/LifoAlloc.h
+++ b/js/src/ds/LifoAlloc.h
@@ -15,6 +15,8 @@
#include "mozilla/TemplateLib.h"
#include "mozilla/TypeTraits.h"
+#include <new>
+
// This data structure supports stacky LIFO allocation (mark/release and
// LifoAllocScope). It does not maintain one contiguous segment; instead, it
// maintains a bunch of linked memory segments. In order to prevent malloc/free
@@ -285,6 +287,20 @@ class LifoAlloc
return allocImpl(n);
}
+ template<typename T, typename... Args>
+ MOZ_ALWAYS_INLINE T*
+ allocInSize(size_t n, Args&&... args)
+ {
+ MOZ_ASSERT(n >= sizeof(T), "must request enough space to store a T");
+ static_assert(alignof(T) <= detail::LIFO_ALLOC_ALIGN,
+ "LifoAlloc must provide enough alignment to store T");
+ void* ptr = alloc(n);
+ if (!ptr)
+ return nullptr;
+
+ return new (ptr) T(mozilla::Forward<Args>(args)...);
+ }
+
MOZ_ALWAYS_INLINE
void* allocInfallible(size_t n) {
AutoEnterOOMUnsafeRegion oomUnsafe;
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 343621194..7bfab87a3 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1453,13 +1453,11 @@ template <typename Scope>
static typename Scope::Data*
NewEmptyBindingData(ExclusiveContext* cx, LifoAlloc& alloc, uint32_t numBindings)
{
+ using Data = typename Scope::Data;
size_t allocSize = Scope::sizeOfData(numBindings);
- auto* bindings = static_cast<typename Scope::Data*>(alloc.alloc(allocSize));
- if (!bindings) {
+ auto* bindings = alloc.allocInSize<Data>(allocSize, numBindings);
+ if (!bindings)
ReportOutOfMemory(cx);
- return nullptr;
- }
- PodZero(bindings);
return bindings;
}
diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp
index 25e389d8a..8bb1702ea 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);
}
diff --git a/js/src/vm/Scope.h b/js/src/vm/Scope.h
index 387eb30eb..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"
@@ -139,6 +140,14 @@ class TrailingNamesArray
}
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]; }
@@ -370,17 +379,20 @@ 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.
TrailingNamesArray trailingNames;
+ explicit Data(size_t nameCount) : trailingNames(nameCount) {}
+ Data() = delete;
+
void trace(JSTracer* trc);
};
@@ -466,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.
//
@@ -485,18 +497,21 @@ 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.
TrailingNamesArray trailingNames;
+ explicit Data(size_t nameCount) : trailingNames(nameCount) {}
+ Data() = delete;
+
void trace(JSTracer* trc);
};
@@ -581,16 +596,19 @@ 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.
TrailingNamesArray trailingNames;
+ explicit Data(size_t nameCount) : trailingNames(nameCount) {}
+ Data() = delete;
+
void trace(JSTracer* trc);
};
@@ -671,15 +689,18 @@ 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.
TrailingNamesArray trailingNames;
+ explicit Data(size_t nameCount) : trailingNames(nameCount) {}
+ Data() = delete;
+
void trace(JSTracer* trc);
};
@@ -769,17 +790,20 @@ 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.
TrailingNamesArray trailingNames;
+ explicit Data(size_t nameCount) : trailingNames(nameCount) {}
+ Data() = delete;
+
void trace(JSTracer* trc);
};
@@ -860,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.
//
@@ -868,19 +892,22 @@ 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.
TrailingNamesArray trailingNames;
+ explicit Data(size_t nameCount) : trailingNames(nameCount) {}
+ Data() = delete;
+
void trace(JSTracer* trc);
};