summaryrefslogtreecommitdiffstats
path: root/js/src/vm
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm')
-rw-r--r--js/src/vm/Scope.cpp20
-rw-r--r--js/src/vm/Scope.h120
2 files changed, 100 insertions, 40 deletions
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);
};