mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 645416, part 3 - Symbol layout and GC support for allocating them. r=terrence.
Layout: js/src/vm/Symbol.h defines the new class JS::Symbol. JS::Symbol is the same size as JSString on all platforms, because the allocator does not support smaller allocations. Allocation: Since the purpose of symbols is to serve as property keys, they are always allocated in the atoms compartment. We take a lock when allocating. This could probably be replaced with a main-thread-only assertion. However, if atom allocation is not already a bottleneck, symbol allocation probably never will be. Symbols are given their own finalize-class in the GC. This means we allocate a page per zone for symbols, even though they are only ever allocated in the atoms zone. Terrence thought this could be easily fixed later. It should be; we never touch the page, but a 32-bit virtual address space does not just have infinite pages to spare. A jsapi-test exercises the new symbol allocation code. A few oddities in jsapi-tests are fixed in passing. Discussion after review led to some new assertions about minimum object size in AllocateObject and AllocateNonObject. --HG-- extra : rebase_source : 45abb651d3b1b493d77a5dd0eb554f96b058c63a
This commit is contained in:
parent
8ba7b56464
commit
42a78a347e
@ -124,6 +124,14 @@ AsCell(JSFlatString *flat)
|
||||
return cell;
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE js::gc::Cell *
|
||||
AsCell(JS::Symbol *sym)
|
||||
{
|
||||
js::gc::Cell *cell = reinterpret_cast<js::gc::Cell *>(sym);
|
||||
AssertGCThingHasType(cell, JSTRACE_SYMBOL);
|
||||
return cell;
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE js::gc::Cell *
|
||||
AsCell(JSScript *script)
|
||||
{
|
||||
|
@ -400,6 +400,7 @@ struct RuntimeSizes
|
||||
struct ZoneStats
|
||||
{
|
||||
#define FOR_EACH_SIZE(macro) \
|
||||
macro(Other, IsLiveGCThing, symbolsGCHeap) \
|
||||
macro(Other, NotLiveGCThing, gcHeapArenaAdmin) \
|
||||
macro(Other, NotLiveGCThing, unusedGCThings) \
|
||||
macro(Other, IsLiveGCThing, lazyScriptsGCHeap) \
|
||||
|
@ -49,6 +49,7 @@ typedef Handle<jsid> HandleId;
|
||||
typedef Handle<JSObject*> HandleObject;
|
||||
typedef Handle<JSScript*> HandleScript;
|
||||
typedef Handle<JSString*> HandleString;
|
||||
typedef Handle<JS::Symbol*> HandleSymbol;
|
||||
typedef Handle<Value> HandleValue;
|
||||
|
||||
typedef MutableHandle<JSFunction*> MutableHandleFunction;
|
||||
@ -56,12 +57,14 @@ typedef MutableHandle<jsid> MutableHandleId;
|
||||
typedef MutableHandle<JSObject*> MutableHandleObject;
|
||||
typedef MutableHandle<JSScript*> MutableHandleScript;
|
||||
typedef MutableHandle<JSString*> MutableHandleString;
|
||||
typedef MutableHandle<JS::Symbol*> MutableHandleSymbol;
|
||||
typedef MutableHandle<Value> MutableHandleValue;
|
||||
|
||||
typedef Rooted<JSObject*> RootedObject;
|
||||
typedef Rooted<JSFunction*> RootedFunction;
|
||||
typedef Rooted<JSScript*> RootedScript;
|
||||
typedef Rooted<JSString*> RootedString;
|
||||
typedef Rooted<JS::Symbol*> RootedSymbol;
|
||||
typedef Rooted<jsid> RootedId;
|
||||
typedef Rooted<JS::Value> RootedValue;
|
||||
|
||||
@ -70,6 +73,7 @@ typedef PersistentRooted<jsid> PersistentRootedId;
|
||||
typedef PersistentRooted<JSObject*> PersistentRootedObject;
|
||||
typedef PersistentRooted<JSScript*> PersistentRootedScript;
|
||||
typedef PersistentRooted<JSString*> PersistentRootedString;
|
||||
typedef PersistentRooted<JS::Symbol*> PersistentRootedSymbol;
|
||||
typedef PersistentRooted<Value> PersistentRootedValue;
|
||||
|
||||
} // namespace JS
|
||||
|
@ -599,7 +599,13 @@ JSVAL_TO_GCTHING_IMPL(jsval_layout l)
|
||||
static inline uint32_t
|
||||
JSVAL_TRACE_KIND_IMPL(jsval_layout l)
|
||||
{
|
||||
return (uint32_t)(bool)JSVAL_IS_STRING_IMPL(l);
|
||||
static_assert((JSVAL_TAG_STRING & 0x03) == JSTRACE_STRING,
|
||||
"Value type tags must correspond with JSGCTraceKinds.");
|
||||
static_assert((JSVAL_TAG_SYMBOL & 0x03) == JSTRACE_SYMBOL,
|
||||
"Value type tags must correspond with JSGCTraceKinds.");
|
||||
static_assert((JSVAL_TAG_OBJECT & 0x03) == JSTRACE_OBJECT,
|
||||
"Value type tags must correspond with JSGCTraceKinds.");
|
||||
return l.s.tag & 0x03;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@ -834,7 +840,13 @@ JSVAL_TO_GCTHING_IMPL(jsval_layout l)
|
||||
static inline uint32_t
|
||||
JSVAL_TRACE_KIND_IMPL(jsval_layout l)
|
||||
{
|
||||
return (uint32_t)(bool)!(JSVAL_IS_OBJECT_IMPL(l));
|
||||
static_assert((JSVAL_TAG_STRING & 0x03) == JSTRACE_STRING,
|
||||
"Value type tags must correspond with JSGCTraceKinds.");
|
||||
static_assert((JSVAL_TAG_SYMBOL & 0x03) == JSTRACE_SYMBOL,
|
||||
"Value type tags must correspond with JSGCTraceKinds.");
|
||||
static_assert((JSVAL_TAG_OBJECT & 0x03) == JSTRACE_OBJECT,
|
||||
"Value type tags must correspond with JSGCTraceKinds.");
|
||||
return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) & 0x03;
|
||||
}
|
||||
|
||||
static inline jsval_layout
|
||||
|
@ -100,6 +100,7 @@ using JS::RootedId;
|
||||
using JS::RootedObject;
|
||||
using JS::RootedScript;
|
||||
using JS::RootedString;
|
||||
using JS::RootedSymbol;
|
||||
using JS::RootedValue;
|
||||
|
||||
using JS::PersistentRooted;
|
||||
@ -108,6 +109,7 @@ using JS::PersistentRootedId;
|
||||
using JS::PersistentRootedObject;
|
||||
using JS::PersistentRootedScript;
|
||||
using JS::PersistentRootedString;
|
||||
using JS::PersistentRootedSymbol;
|
||||
using JS::PersistentRootedValue;
|
||||
|
||||
using JS::Handle;
|
||||
@ -116,6 +118,7 @@ using JS::HandleId;
|
||||
using JS::HandleObject;
|
||||
using JS::HandleScript;
|
||||
using JS::HandleString;
|
||||
using JS::HandleSymbol;
|
||||
using JS::HandleValue;
|
||||
|
||||
using JS::MutableHandle;
|
||||
@ -124,6 +127,7 @@ using JS::MutableHandleId;
|
||||
using JS::MutableHandleObject;
|
||||
using JS::MutableHandleScript;
|
||||
using JS::MutableHandleString;
|
||||
using JS::MutableHandleSymbol;
|
||||
using JS::MutableHandleValue;
|
||||
|
||||
using JS::NullHandleValue;
|
||||
|
@ -764,6 +764,7 @@ static const struct TraceKindPair {
|
||||
{ "all", -1 },
|
||||
{ "object", JSTRACE_OBJECT },
|
||||
{ "string", JSTRACE_STRING },
|
||||
{ "symbol", JSTRACE_SYMBOL },
|
||||
};
|
||||
|
||||
static bool
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
#include "gc/Zone.h"
|
||||
|
||||
#include "vm/Symbol.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
void
|
||||
@ -21,6 +23,8 @@ ValueReadBarrier(const Value &value)
|
||||
JSObject::readBarrier(&value.toObject());
|
||||
else if (value.isString())
|
||||
JSString::readBarrier(value.toString());
|
||||
else if (value.isSymbol())
|
||||
JS::Symbol::readBarrier(value.toSymbol());
|
||||
else
|
||||
JS_ASSERT(!value.isMarkable());
|
||||
}
|
||||
|
@ -272,6 +272,13 @@ ShadowZoneOfStringFromAnyThread(JSString *str)
|
||||
reinterpret_cast<const js::gc::Cell *>(str)->tenuredZoneFromAnyThread());
|
||||
}
|
||||
|
||||
static inline JS::shadow::Zone *
|
||||
ShadowZoneOfSymbolFromAnyThread(JS::Symbol *sym)
|
||||
{
|
||||
return JS::shadow::Zone::asShadowZone(
|
||||
reinterpret_cast<const js::gc::Cell *>(sym)->tenuredZoneFromAnyThread());
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE JS::Zone *
|
||||
ZoneOfValueFromAnyThread(const JS::Value &value)
|
||||
{
|
||||
|
@ -75,6 +75,7 @@ enum AllocKind {
|
||||
FINALIZE_FAT_INLINE_STRING,
|
||||
FINALIZE_STRING,
|
||||
FINALIZE_EXTERNAL_STRING,
|
||||
FINALIZE_SYMBOL,
|
||||
FINALIZE_JITCODE,
|
||||
FINALIZE_LAST = FINALIZE_JITCODE
|
||||
};
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/ScopeObject.h"
|
||||
#include "vm/Shape.h"
|
||||
#include "vm/Symbol.h"
|
||||
#include "vm/TypedArrayObject.h"
|
||||
|
||||
#include "jscompartmentinlines.h"
|
||||
@ -25,6 +26,7 @@
|
||||
# include "gc/Nursery-inl.h"
|
||||
#endif
|
||||
#include "vm/String-inl.h"
|
||||
#include "vm/Symbol-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::gc;
|
||||
@ -78,7 +80,10 @@ static inline void
|
||||
PushMarkStack(GCMarker *gcmarker, Shape *thing);
|
||||
|
||||
static inline void
|
||||
PushMarkStack(GCMarker *gcmarker, JSString *thing);
|
||||
PushMarkStack(GCMarker *gcmarker, JSString *str);
|
||||
|
||||
static inline void
|
||||
PushMarkStack(GCMarker *gcmarker, JS::Symbol *sym);
|
||||
|
||||
static inline void
|
||||
PushMarkStack(GCMarker *gcmarker, types::TypeObject *thing);
|
||||
@ -87,6 +92,7 @@ namespace js {
|
||||
namespace gc {
|
||||
|
||||
static void MarkChildren(JSTracer *trc, JSString *str);
|
||||
static void MarkChildren(JSTracer *trc, JS::Symbol *sym);
|
||||
static void MarkChildren(JSTracer *trc, JSScript *script);
|
||||
static void MarkChildren(JSTracer *trc, LazyScript *lazy);
|
||||
static void MarkChildren(JSTracer *trc, Shape *shape);
|
||||
@ -569,6 +575,7 @@ DeclMarkerImpl(String, JSString)
|
||||
DeclMarkerImpl(String, JSFlatString)
|
||||
DeclMarkerImpl(String, JSLinearString)
|
||||
DeclMarkerImpl(String, PropertyName)
|
||||
DeclMarkerImpl(Symbol, JS::Symbol)
|
||||
DeclMarkerImpl(TypeObject, js::types::TypeObject)
|
||||
|
||||
} /* namespace gc */
|
||||
@ -590,6 +597,9 @@ gc::MarkKind(JSTracer *trc, void **thingp, JSGCTraceKind kind)
|
||||
case JSTRACE_STRING:
|
||||
MarkInternal(trc, reinterpret_cast<JSString **>(thingp));
|
||||
break;
|
||||
case JSTRACE_SYMBOL:
|
||||
MarkInternal(trc, reinterpret_cast<JS::Symbol **>(thingp));
|
||||
break;
|
||||
case JSTRACE_SCRIPT:
|
||||
MarkInternal(trc, reinterpret_cast<JSScript **>(thingp));
|
||||
break;
|
||||
@ -708,6 +718,8 @@ MarkValueInternal(JSTracer *trc, Value *v)
|
||||
MarkKind(trc, &thing, v->gcKind());
|
||||
if (v->isString())
|
||||
v->setString((JSString *)thing);
|
||||
else if (v->isSymbol())
|
||||
v->setSymbol((JS::Symbol *)thing);
|
||||
else
|
||||
v->setObjectOrNull((JSObject *)thing);
|
||||
} else {
|
||||
@ -929,6 +941,10 @@ gc::IsCellAboutToBeFinalized(Cell **thingp)
|
||||
JS_ASSERT((thing)->zone()->isGCMarking() || \
|
||||
(rt)->isAtomsZone((thing)->zone()));
|
||||
|
||||
// Symbols can also be in the atoms zone.
|
||||
#define JS_COMPARTMENT_ASSERT_SYM(rt, sym) \
|
||||
JS_COMPARTMENT_ASSERT_STR(rt, sym)
|
||||
|
||||
static void
|
||||
PushMarkStack(GCMarker *gcmarker, ObjectImpl *thing)
|
||||
{
|
||||
@ -1199,6 +1215,16 @@ PushMarkStack(GCMarker *gcmarker, JSString *str)
|
||||
ScanString(gcmarker, str);
|
||||
}
|
||||
|
||||
static inline void
|
||||
PushMarkStack(GCMarker *gcmarker, JS::Symbol *sym)
|
||||
{
|
||||
JS_COMPARTMENT_ASSERT_SYM(gcmarker->runtime(), sym);
|
||||
if (sym->markIfUnmarked()) {
|
||||
if (JSString *desc = sym->description())
|
||||
ScanString(gcmarker, desc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gc::MarkChildren(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
@ -1214,6 +1240,12 @@ gc::MarkChildren(JSTracer *trc, JSString *str)
|
||||
str->asRope().markChildren(trc);
|
||||
}
|
||||
|
||||
static void
|
||||
gc::MarkChildren(JSTracer *trc, JS::Symbol *sym)
|
||||
{
|
||||
sym->markChildren(trc);
|
||||
}
|
||||
|
||||
static void
|
||||
gc::MarkChildren(JSTracer *trc, JSScript *script)
|
||||
{
|
||||
@ -1375,6 +1407,10 @@ gc::PushArena(GCMarker *gcmarker, ArenaHeader *aheader)
|
||||
PushArenaTyped<JSString>(gcmarker, aheader);
|
||||
break;
|
||||
|
||||
case JSTRACE_SYMBOL:
|
||||
PushArenaTyped<JS::Symbol>(gcmarker, aheader);
|
||||
break;
|
||||
|
||||
case JSTRACE_SCRIPT:
|
||||
PushArenaTyped<JSScript>(gcmarker, aheader);
|
||||
break;
|
||||
@ -1705,6 +1741,10 @@ js::TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind)
|
||||
MarkChildren(trc, static_cast<JSString *>(thing));
|
||||
break;
|
||||
|
||||
case JSTRACE_SYMBOL:
|
||||
MarkChildren(trc, static_cast<JS::Symbol *>(thing));
|
||||
break;
|
||||
|
||||
case JSTRACE_SCRIPT:
|
||||
MarkChildren(trc, static_cast<JSScript *>(thing));
|
||||
break;
|
||||
|
@ -120,6 +120,7 @@ DeclMarker(String, JSString)
|
||||
DeclMarker(String, JSFlatString)
|
||||
DeclMarker(String, JSLinearString)
|
||||
DeclMarker(String, PropertyName)
|
||||
DeclMarker(Symbol, JS::Symbol)
|
||||
DeclMarker(TypeObject, types::TypeObject)
|
||||
|
||||
#undef DeclMarker
|
||||
@ -388,7 +389,10 @@ TraceKind(const Value &v)
|
||||
JS_ASSERT(v.isMarkable());
|
||||
if (v.isObject())
|
||||
return JSTRACE_OBJECT;
|
||||
return JSTRACE_STRING;
|
||||
if (v.isString())
|
||||
return JSTRACE_STRING;
|
||||
JS_ASSERT(v.isSymbol());
|
||||
return JSTRACE_SYMBOL;
|
||||
}
|
||||
|
||||
inline JSGCTraceKind
|
||||
|
@ -126,6 +126,7 @@ MarkExactStackRoots(T context, JSTracer *trc)
|
||||
MarkExactStackRootsForType<BaseShape *, MarkBaseShapeRoot>(context, trc, "exact-baseshape");
|
||||
MarkExactStackRootsForType<types::TypeObject *, MarkTypeObjectRoot>(context, trc, "exact-typeobject");
|
||||
MarkExactStackRootsForType<JSString *, MarkStringRoot>(context, trc, "exact-string");
|
||||
MarkExactStackRootsForType<JS::Symbol *, MarkSymbolRoot>(context, trc, "exact-symbol");
|
||||
MarkExactStackRootsForType<jit::JitCode *, MarkJitCodeRoot>(context, trc, "exact-jitcode");
|
||||
MarkExactStackRootsForType<JSScript *, MarkScriptRoot>(context, trc, "exact-script");
|
||||
MarkExactStackRootsForType<LazyScript *, MarkLazyScriptRoot>(context, trc, "exact-lazy-script");
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include "gc/GCInternals.h"
|
||||
#include "gc/Marking.h"
|
||||
|
||||
#include "vm/Symbol.h"
|
||||
|
||||
#include "jsgcinlines.h"
|
||||
|
||||
using namespace js;
|
||||
@ -152,6 +154,10 @@ JS_GetTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing,
|
||||
: "string";
|
||||
break;
|
||||
|
||||
case JSTRACE_SYMBOL:
|
||||
name = "symbol";
|
||||
break;
|
||||
|
||||
case JSTRACE_SCRIPT:
|
||||
name = "script";
|
||||
break;
|
||||
@ -222,9 +228,26 @@ JS_GetTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing,
|
||||
bufsize -= n;
|
||||
|
||||
PutEscapedString(buf, bufsize, &str->asLinear(), 0);
|
||||
}
|
||||
else
|
||||
} else {
|
||||
JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JSTRACE_SYMBOL:
|
||||
{
|
||||
JS::Symbol *sym = static_cast<JS::Symbol *>(thing);
|
||||
if (JSString *desc = sym->description()) {
|
||||
if (desc->isLinear()) {
|
||||
*buf++ = ' ';
|
||||
bufsize--;
|
||||
PutEscapedString(buf, bufsize, &desc->asLinear(), 0);
|
||||
} else {
|
||||
JS_snprintf(buf, bufsize, "<nonlinear desc>");
|
||||
}
|
||||
} else {
|
||||
JS_snprintf(buf, bufsize, "<null>");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,19 @@ tests.h:
|
||||
false, failing the test.
|
||||
|
||||
This is like CHECK(sameValue(a, b)) but with a more detailed error
|
||||
message. See sameValue below.
|
||||
message on failure. See sameValue below.
|
||||
|
||||
CHECK_EQUAL(const T &a, const U &b);
|
||||
|
||||
CHECK(a == b), but with a more detailed error message.
|
||||
|
||||
CHECK_NULL(const T *ptr);
|
||||
|
||||
CHECK(ptr == nullptr), but with a more detailed error message.
|
||||
|
||||
(This is here because CHECK_EQUAL(ptr, nullptr) fails to compile on GCC
|
||||
2.5 and before.)
|
||||
|
||||
|
||||
bool knownFail;
|
||||
|
||||
|
@ -68,6 +68,7 @@ UNIFIED_SOURCES += [
|
||||
'testSourcePolicy.cpp',
|
||||
'testStringBuffer.cpp',
|
||||
'testStructuredClone.cpp',
|
||||
'testSymbol.cpp',
|
||||
'testToIntWidth.cpp',
|
||||
'testTrap.cpp',
|
||||
'testTypedArrays.cpp',
|
||||
|
@ -83,7 +83,7 @@ doResolve(JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp)
|
||||
{
|
||||
CHECK_EQUAL(resolveExitCount, 0);
|
||||
AutoIncrCounters incr(this);
|
||||
CHECK_EQUAL(obj, obj1 || obj == obj2);
|
||||
CHECK(obj == obj1 || obj == obj2);
|
||||
|
||||
CHECK(JSID_IS_STRING(id));
|
||||
|
||||
|
28
js/src/jsapi-tests/testSymbol.cpp
Normal file
28
js/src/jsapi-tests/testSymbol.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
/* 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 "jsapi-tests/tests.h"
|
||||
|
||||
BEGIN_TEST(testSymbol_New)
|
||||
{
|
||||
using namespace JS;
|
||||
|
||||
RootedString desc(cx, nullptr);
|
||||
RootedSymbol sym1(cx);
|
||||
CHECK(sym1 = NewSymbol(cx, desc));
|
||||
CHECK_NULL(GetSymbolDescription(sym1));
|
||||
RootedValue v(cx, SymbolValue(sym1));
|
||||
CHECK_EQUAL(JS_TypeOfValue(cx, v), JSTYPE_SYMBOL);
|
||||
|
||||
RootedSymbol sym2(cx);
|
||||
CHECK(sym2 = NewSymbol(cx, desc));
|
||||
CHECK(sym1 != sym2);
|
||||
|
||||
CHECK(desc = JS_NewStringCopyZ(cx, "ponies"));
|
||||
CHECK(sym2 = NewSymbol(cx, desc));
|
||||
CHECK_SAME(StringValue(GetSymbolDescription(sym2)), StringValue(desc));
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testSymbol_New)
|
@ -182,7 +182,7 @@ JSObject *newCCW(HandleObject sourceZone, HandleObject destZone)
|
||||
RootedObject object(cx);
|
||||
{
|
||||
JSAutoCompartment ac(cx, destZone);
|
||||
object = JS_NewObject(cx, nullptr, NullPtr(), NullPtr());
|
||||
object = JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr());
|
||||
if (!object)
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -155,8 +155,11 @@ class JSAPITest
|
||||
return JSAPITestString(JS_VersionToString(v));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool checkEqual(const T &actual, const T &expected,
|
||||
// Note that in some still-supported GCC versions (we think anything before
|
||||
// GCC 4.6), this template does not work when the second argument is
|
||||
// nullptr. It infers type U = long int. Use CHECK_NULL instead.
|
||||
template <typename T, typename U>
|
||||
bool checkEqual(const T &actual, const U &expected,
|
||||
const char *actualExpr, const char *expectedExpr,
|
||||
const char *filename, int lineno) {
|
||||
return (actual == expected) ||
|
||||
@ -165,24 +168,27 @@ class JSAPITest
|
||||
", got (" + actualExpr + ") = " + toSource(actual), filename, lineno);
|
||||
}
|
||||
|
||||
// There are many cases where the static types of 'actual' and 'expected'
|
||||
// are not identical, and C++ is understandably cautious about automatic
|
||||
// coercions. So catch those cases and forcibly coerce, then use the
|
||||
// identical-type specialization. This may do bad things if the types are
|
||||
// actually *not* compatible.
|
||||
template<typename T, typename U>
|
||||
bool checkEqual(const T &actual, const U &expected,
|
||||
const char *actualExpr, const char *expectedExpr,
|
||||
const char *filename, int lineno) {
|
||||
return checkEqual(U(actual), expected, actualExpr, expectedExpr, filename, lineno);
|
||||
}
|
||||
|
||||
#define CHECK_EQUAL(actual, expected) \
|
||||
do { \
|
||||
if (!checkEqual(actual, expected, #actual, #expected, __FILE__, __LINE__)) \
|
||||
return false; \
|
||||
} while (false)
|
||||
|
||||
template <typename T>
|
||||
bool checkNull(const T *actual, const char *actualExpr,
|
||||
const char *filename, int lineno) {
|
||||
return (actual == nullptr) ||
|
||||
fail(JSAPITestString("CHECK_NULL failed: expected nullptr, got (") +
|
||||
actualExpr + ") = " + toSource(actual),
|
||||
filename, lineno);
|
||||
}
|
||||
|
||||
#define CHECK_NULL(actual) \
|
||||
do { \
|
||||
if (!checkNull(actual, #actual, __FILE__, __LINE__)) \
|
||||
return false; \
|
||||
} while (false)
|
||||
|
||||
bool checkSame(jsval actualArg, jsval expectedArg,
|
||||
const char *actualExpr, const char *expectedExpr,
|
||||
const char *filename, int lineno) {
|
||||
|
@ -76,6 +76,7 @@
|
||||
#include "vm/SharedArrayObject.h"
|
||||
#include "vm/StopIterationObject.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
#include "vm/Symbol.h"
|
||||
#include "vm/TypedArrayObject.h"
|
||||
#include "vm/WeakMapObject.h"
|
||||
#include "vm/WrapperObject.h"
|
||||
@ -5616,6 +5617,23 @@ JS_EncodeStringToBuffer(JSContext *cx, JSString *str, char *buffer, size_t lengt
|
||||
return necessaryLength;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JS::Symbol *)
|
||||
JS::NewSymbol(JSContext *cx, HandleString description)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
if (description)
|
||||
assertSameCompartment(cx, description);
|
||||
|
||||
return Symbol::new_(cx, description);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSString *)
|
||||
JS::GetSymbolDescription(HandleSymbol symbol)
|
||||
{
|
||||
return symbol->description();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_Stringify(JSContext *cx, MutableHandleValue vp, HandleObject replacer,
|
||||
HandleValue space, JSONWriteCallback callback, void *data)
|
||||
|
@ -4351,6 +4351,34 @@ AddonIdOfObject(JSObject *obj);
|
||||
|
||||
} // namespace JS
|
||||
|
||||
/************************************************************************/
|
||||
/*
|
||||
* Symbols
|
||||
*/
|
||||
|
||||
namespace JS {
|
||||
|
||||
/*
|
||||
* Create a new Symbol with the given description. This function never returns
|
||||
* a Symbol that is in the Runtime-wide symbol registry.
|
||||
*
|
||||
* If description is null, the new Symbol's [[Description]] attribute is
|
||||
* undefined.
|
||||
*/
|
||||
JS_PUBLIC_API(Symbol *)
|
||||
NewSymbol(JSContext *cx, HandleString description);
|
||||
|
||||
/*
|
||||
* Get the [[Description]] attribute of the given symbol.
|
||||
*
|
||||
* This function is infallible. If it returns null, that means the symbol's
|
||||
* [[Description]] is undefined.
|
||||
*/
|
||||
JS_PUBLIC_API(JSString *)
|
||||
GetSymbolDescription(HandleSymbol symbol);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
/************************************************************************/
|
||||
/*
|
||||
* JSON functions
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/String-inl.h"
|
||||
#include "vm/Symbol-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::gc;
|
||||
@ -380,6 +381,9 @@ AtomizeAndCopyChars(ExclusiveContext *cx, const CharT *tbchars, size_t length, I
|
||||
|
||||
JSFlatString *flat = js_NewStringCopyN<NoGC>(cx, tbchars, length);
|
||||
if (!flat) {
|
||||
// Grudgingly forgo last-ditch GC. The alternative would be to release
|
||||
// the lock, manually GC here, and retry from the top. If you fix this,
|
||||
// please also fix or comment the similar case in Symbol::new_.
|
||||
js_ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "vm/HelperThreads.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/ProxyObject.h"
|
||||
#include "vm/Symbol.h"
|
||||
|
||||
#include "gc/ForkJoinNursery-inl.h"
|
||||
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
#include "gc/Barrier.h"
|
||||
|
||||
#include "jscntxtinlines.h"
|
||||
|
||||
inline void
|
||||
JSCompartment::initGlobal(js::GlobalObject &global)
|
||||
{
|
||||
|
@ -980,6 +980,8 @@ JS::IncrementalReferenceBarrier(void *ptr, JSGCTraceKind kind)
|
||||
JSObject::writeBarrierPre(static_cast<JSObject*>(cell));
|
||||
else if (kind == JSTRACE_STRING)
|
||||
JSString::writeBarrierPre(static_cast<JSString*>(cell));
|
||||
else if (kind == JSTRACE_SYMBOL)
|
||||
JS::Symbol::writeBarrierPre(static_cast<JS::Symbol*>(cell));
|
||||
else if (kind == JSTRACE_SCRIPT)
|
||||
JSScript::writeBarrierPre(static_cast<JSScript*>(cell));
|
||||
else if (kind == JSTRACE_LAZY_SCRIPT)
|
||||
|
@ -213,6 +213,7 @@
|
||||
#include "vm/ProxyObject.h"
|
||||
#include "vm/Shape.h"
|
||||
#include "vm/String.h"
|
||||
#include "vm/Symbol.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
#include "vm/WrapperObject.h"
|
||||
|
||||
@ -277,6 +278,7 @@ const uint32_t Arena::ThingSizes[] = {
|
||||
sizeof(JSFatInlineString), /* FINALIZE_FAT_INLINE_STRING */
|
||||
sizeof(JSString), /* FINALIZE_STRING */
|
||||
sizeof(JSExternalString), /* FINALIZE_EXTERNAL_STRING */
|
||||
sizeof(JS::Symbol), /* FINALIZE_SYMBOL */
|
||||
sizeof(jit::JitCode), /* FINALIZE_JITCODE */
|
||||
};
|
||||
|
||||
@ -303,6 +305,7 @@ const uint32_t Arena::FirstThingOffsets[] = {
|
||||
OFFSET(JSFatInlineString), /* FINALIZE_FAT_INLINE_STRING */
|
||||
OFFSET(JSString), /* FINALIZE_STRING */
|
||||
OFFSET(JSExternalString), /* FINALIZE_EXTERNAL_STRING */
|
||||
OFFSET(JS::Symbol), /* FINALIZE_SYMBOL */
|
||||
OFFSET(jit::JitCode), /* FINALIZE_JITCODE */
|
||||
};
|
||||
|
||||
@ -314,6 +317,7 @@ js::gc::TraceKindAsAscii(JSGCTraceKind kind)
|
||||
switch(kind) {
|
||||
case JSTRACE_OBJECT: return "JSTRACE_OBJECT";
|
||||
case JSTRACE_STRING: return "JSTRACE_STRING";
|
||||
case JSTRACE_SYMBOL: return "JSTRACE_SYMBOL";
|
||||
case JSTRACE_SCRIPT: return "JSTRACE_SCRIPT";
|
||||
case JSTRACE_LAZY_SCRIPT: return "JSTRACE_SCRIPT";
|
||||
case JSTRACE_JITCODE: return "JSTRACE_JITCODE";
|
||||
@ -373,9 +377,10 @@ static const AllocKind BackgroundPhaseObjects[] = {
|
||||
FINALIZE_OBJECT16_BACKGROUND
|
||||
};
|
||||
|
||||
static const AllocKind BackgroundPhaseStrings[] = {
|
||||
static const AllocKind BackgroundPhaseStringsAndSymbols[] = {
|
||||
FINALIZE_FAT_INLINE_STRING,
|
||||
FINALIZE_STRING
|
||||
FINALIZE_STRING,
|
||||
FINALIZE_SYMBOL
|
||||
};
|
||||
|
||||
static const AllocKind BackgroundPhaseShapes[] = {
|
||||
@ -386,14 +391,14 @@ static const AllocKind BackgroundPhaseShapes[] = {
|
||||
|
||||
static const AllocKind * const BackgroundPhases[] = {
|
||||
BackgroundPhaseObjects,
|
||||
BackgroundPhaseStrings,
|
||||
BackgroundPhaseStringsAndSymbols,
|
||||
BackgroundPhaseShapes
|
||||
};
|
||||
static const int BackgroundPhaseCount = sizeof(BackgroundPhases) / sizeof(AllocKind*);
|
||||
|
||||
static const int BackgroundPhaseLength[] = {
|
||||
sizeof(BackgroundPhaseObjects) / sizeof(AllocKind),
|
||||
sizeof(BackgroundPhaseStrings) / sizeof(AllocKind),
|
||||
sizeof(BackgroundPhaseStringsAndSymbols) / sizeof(AllocKind),
|
||||
sizeof(BackgroundPhaseShapes) / sizeof(AllocKind)
|
||||
};
|
||||
|
||||
@ -598,6 +603,8 @@ FinalizeArenas(FreeOp *fop,
|
||||
return FinalizeTypedArenas<JSFatInlineString>(fop, src, dest, thingKind, budget);
|
||||
case FINALIZE_EXTERNAL_STRING:
|
||||
return FinalizeTypedArenas<JSExternalString>(fop, src, dest, thingKind, budget);
|
||||
case FINALIZE_SYMBOL:
|
||||
return FinalizeTypedArenas<JS::Symbol>(fop, src, dest, thingKind, budget);
|
||||
case FINALIZE_JITCODE:
|
||||
#ifdef JS_ION
|
||||
{
|
||||
@ -2007,12 +2014,13 @@ ArenaLists::queueObjectsForSweep(FreeOp *fop)
|
||||
}
|
||||
|
||||
void
|
||||
ArenaLists::queueStringsForSweep(FreeOp *fop)
|
||||
ArenaLists::queueStringsAndSymbolsForSweep(FreeOp *fop)
|
||||
{
|
||||
gcstats::AutoPhase ap(fop->runtime()->gc.stats, gcstats::PHASE_SWEEP_STRING);
|
||||
|
||||
queueForBackgroundSweep(fop, FINALIZE_FAT_INLINE_STRING);
|
||||
queueForBackgroundSweep(fop, FINALIZE_STRING);
|
||||
queueForBackgroundSweep(fop, FINALIZE_SYMBOL);
|
||||
|
||||
queueForForegroundSweep(fop, FINALIZE_EXTERNAL_STRING);
|
||||
}
|
||||
@ -4135,7 +4143,7 @@ GCRuntime::beginSweepingZoneGroup()
|
||||
}
|
||||
for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) {
|
||||
gcstats::AutoSCC scc(stats, zoneGroupIndex);
|
||||
zone->allocator.arenas.queueStringsForSweep(&fop);
|
||||
zone->allocator.arenas.queueStringsAndSymbolsForSweep(&fop);
|
||||
}
|
||||
for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) {
|
||||
gcstats::AutoSCC scc(stats, zoneGroupIndex);
|
||||
|
@ -25,6 +25,10 @@ struct JSCompartment;
|
||||
class JSFlatString;
|
||||
class JSLinearString;
|
||||
|
||||
namespace JS {
|
||||
class Symbol;
|
||||
} /* namespace JS */
|
||||
|
||||
namespace js {
|
||||
|
||||
class ArgumentsObject;
|
||||
@ -121,6 +125,7 @@ MapAllocToTraceKind(AllocKind kind)
|
||||
JSTRACE_STRING, /* FINALIZE_FAT_INLINE_STRING */
|
||||
JSTRACE_STRING, /* FINALIZE_STRING */
|
||||
JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING */
|
||||
JSTRACE_SYMBOL, /* FINALIZE_SYMBOL */
|
||||
JSTRACE_JITCODE, /* FINALIZE_JITCODE */
|
||||
};
|
||||
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(map) == FINALIZE_LIMIT);
|
||||
@ -148,6 +153,7 @@ template <> struct MapTypeToTraceKind<JSAtom> { static const JSGCTrace
|
||||
template <> struct MapTypeToTraceKind<JSString> { static const JSGCTraceKind kind = JSTRACE_STRING; };
|
||||
template <> struct MapTypeToTraceKind<JSFlatString> { static const JSGCTraceKind kind = JSTRACE_STRING; };
|
||||
template <> struct MapTypeToTraceKind<JSLinearString> { static const JSGCTraceKind kind = JSTRACE_STRING; };
|
||||
template <> struct MapTypeToTraceKind<JS::Symbol> { static const JSGCTraceKind kind = JSTRACE_SYMBOL; };
|
||||
template <> struct MapTypeToTraceKind<PropertyName> { static const JSGCTraceKind kind = JSTRACE_STRING; };
|
||||
template <> struct MapTypeToTraceKind<jit::JitCode> { static const JSGCTraceKind kind = JSTRACE_JITCODE; };
|
||||
|
||||
@ -165,6 +171,7 @@ template <> struct MapTypeToFinalizeKind<types::TypeObject> { static const Alloc
|
||||
template <> struct MapTypeToFinalizeKind<JSFatInlineString> { static const AllocKind kind = FINALIZE_FAT_INLINE_STRING; };
|
||||
template <> struct MapTypeToFinalizeKind<JSString> { static const AllocKind kind = FINALIZE_STRING; };
|
||||
template <> struct MapTypeToFinalizeKind<JSExternalString> { static const AllocKind kind = FINALIZE_EXTERNAL_STRING; };
|
||||
template <> struct MapTypeToFinalizeKind<JS::Symbol> { static const AllocKind kind = FINALIZE_SYMBOL; };
|
||||
template <> struct MapTypeToFinalizeKind<jit::JitCode> { static const AllocKind kind = FINALIZE_JITCODE; };
|
||||
|
||||
#if defined(JSGC_GENERATIONAL) || defined(DEBUG)
|
||||
@ -193,6 +200,7 @@ IsNurseryAllocable(AllocKind kind)
|
||||
false, /* FINALIZE_FAT_INLINE_STRING */
|
||||
false, /* FINALIZE_STRING */
|
||||
false, /* FINALIZE_EXTERNAL_STRING */
|
||||
false, /* FINALIZE_SYMBOL */
|
||||
false, /* FINALIZE_JITCODE */
|
||||
};
|
||||
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(map) == FINALIZE_LIMIT);
|
||||
@ -229,6 +237,7 @@ IsFJNurseryAllocable(AllocKind kind)
|
||||
false, /* FINALIZE_FAT_INLINE_STRING */
|
||||
false, /* FINALIZE_STRING */
|
||||
false, /* FINALIZE_EXTERNAL_STRING */
|
||||
false, /* FINALIZE_SYMBOL */
|
||||
false, /* FINALIZE_JITCODE */
|
||||
};
|
||||
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(map) == FINALIZE_LIMIT);
|
||||
@ -261,6 +270,7 @@ IsBackgroundFinalized(AllocKind kind)
|
||||
true, /* FINALIZE_FAT_INLINE_STRING */
|
||||
true, /* FINALIZE_STRING */
|
||||
false, /* FINALIZE_EXTERNAL_STRING */
|
||||
true, /* FINALIZE_SYMBOL */
|
||||
false, /* FINALIZE_JITCODE */
|
||||
};
|
||||
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(map) == FINALIZE_LIMIT);
|
||||
@ -799,7 +809,7 @@ class ArenaLists
|
||||
}
|
||||
|
||||
void queueObjectsForSweep(FreeOp *fop);
|
||||
void queueStringsForSweep(FreeOp *fop);
|
||||
void queueStringsAndSymbolsForSweep(FreeOp *fop);
|
||||
void queueShapesForSweep(FreeOp *fop);
|
||||
void queueScriptsForSweep(FreeOp *fop);
|
||||
void queueJitCodeForSweep(FreeOp *fop);
|
||||
|
@ -547,6 +547,7 @@ CheckAllocatorState(ThreadSafeContext *cx, AllocKind kind)
|
||||
JS_ASSERT_IF(rt->isAtomsCompartment(ncx->compartment()),
|
||||
kind == FINALIZE_STRING ||
|
||||
kind == FINALIZE_FAT_INLINE_STRING ||
|
||||
kind == FINALIZE_SYMBOL ||
|
||||
kind == FINALIZE_JITCODE);
|
||||
JS_ASSERT(!rt->isHeapBusy());
|
||||
JS_ASSERT(rt->gc.isAllocAllowed());
|
||||
@ -606,6 +607,10 @@ AllocateObject(ThreadSafeContext *cx, AllocKind kind, size_t nDynamicSlots, Init
|
||||
size_t thingSize = Arena::thingSize(kind);
|
||||
|
||||
JS_ASSERT(thingSize == Arena::thingSize(kind));
|
||||
JS_ASSERT(thingSize >= sizeof(JSObject));
|
||||
static_assert(sizeof(JSObject) >= CellSize,
|
||||
"All allocations must be at least the allocator-imposed minimum size.");
|
||||
|
||||
if (!CheckAllocatorState<allowGC>(cx, kind))
|
||||
return nullptr;
|
||||
|
||||
@ -652,6 +657,9 @@ template <typename T, AllowGC allowGC>
|
||||
inline T *
|
||||
AllocateNonObject(ThreadSafeContext *cx)
|
||||
{
|
||||
static_assert(sizeof(T) >= CellSize,
|
||||
"All allocations must be at least the allocator-imposed minimum size.");
|
||||
|
||||
AllocKind kind = MapTypeToFinalizeKind<T>::kind;
|
||||
size_t thingSize = sizeof(T);
|
||||
|
||||
|
@ -71,6 +71,7 @@ enum JSType {
|
||||
JSTYPE_NUMBER, /* number */
|
||||
JSTYPE_BOOLEAN, /* boolean */
|
||||
JSTYPE_NULL, /* null */
|
||||
JSTYPE_SYMBOL, /* symbol */
|
||||
JSTYPE_LIMIT
|
||||
};
|
||||
|
||||
@ -104,6 +105,7 @@ enum JSIterateOp {
|
||||
enum JSGCTraceKind {
|
||||
JSTRACE_OBJECT,
|
||||
JSTRACE_STRING,
|
||||
JSTRACE_SYMBOL,
|
||||
JSTRACE_SCRIPT,
|
||||
|
||||
/*
|
||||
@ -343,6 +345,7 @@ enum ThingRootKind
|
||||
THING_ROOT_BASE_SHAPE,
|
||||
THING_ROOT_TYPE_OBJECT,
|
||||
THING_ROOT_STRING,
|
||||
THING_ROOT_SYMBOL,
|
||||
THING_ROOT_JIT_CODE,
|
||||
THING_ROOT_SCRIPT,
|
||||
THING_ROOT_LAZY_SCRIPT,
|
||||
@ -386,6 +389,7 @@ template <> struct RootKind<JSObject *> : SpecificRootKind<JSObject *, THING_ROO
|
||||
template <> struct RootKind<JSFlatString *> : SpecificRootKind<JSFlatString *, THING_ROOT_STRING> {};
|
||||
template <> struct RootKind<JSFunction *> : SpecificRootKind<JSFunction *, THING_ROOT_OBJECT> {};
|
||||
template <> struct RootKind<JSString *> : SpecificRootKind<JSString *, THING_ROOT_STRING> {};
|
||||
template <> struct RootKind<JS::Symbol *> : SpecificRootKind<JS::Symbol *, THING_ROOT_SYMBOL> {};
|
||||
template <> struct RootKind<JSScript *> : SpecificRootKind<JSScript *, THING_ROOT_SCRIPT> {};
|
||||
template <> struct RootKind<jsid> : SpecificRootKind<jsid, THING_ROOT_ID> {};
|
||||
template <> struct RootKind<JS::Value> : SpecificRootKind<JS::Value, THING_ROOT_VALUE> {};
|
||||
|
@ -197,6 +197,7 @@ UNIFIED_SOURCES += [
|
||||
'vm/String.cpp',
|
||||
'vm/StringBuffer.cpp',
|
||||
'vm/StructuredClone.cpp',
|
||||
'vm/Symbol.cpp',
|
||||
'vm/ThreadPool.cpp',
|
||||
'vm/TypedArrayObject.cpp',
|
||||
'vm/UbiNode.cpp',
|
||||
|
@ -209,6 +209,7 @@
|
||||
macro(string, string, "string") \
|
||||
macro(number, number, "number") \
|
||||
macro(boolean, boolean, "boolean") \
|
||||
macro(null, null, "null")
|
||||
macro(null, null, "null") \
|
||||
macro(symbol, symbol, "symbol")
|
||||
|
||||
#endif /* vm_CommonPropertyNames_h */
|
||||
|
@ -813,8 +813,10 @@ js::TypeOfValue(const Value &v)
|
||||
return JSTYPE_VOID;
|
||||
if (v.isObject())
|
||||
return TypeOfObject(&v.toObject());
|
||||
JS_ASSERT(v.isBoolean());
|
||||
return JSTYPE_BOOLEAN;
|
||||
if (v.isBoolean())
|
||||
return JSTYPE_BOOLEAN;
|
||||
JS_ASSERT(v.isSymbol());
|
||||
return JSTYPE_SYMBOL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "vm/Runtime.h"
|
||||
#include "vm/Shape.h"
|
||||
#include "vm/String.h"
|
||||
#include "vm/Symbol.h"
|
||||
#include "vm/WrapperObject.h"
|
||||
|
||||
using mozilla::DebugOnly;
|
||||
@ -400,6 +401,10 @@ StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKin
|
||||
break;
|
||||
}
|
||||
|
||||
case JSTRACE_SYMBOL:
|
||||
zStats->symbolsGCHeap += thingSize;
|
||||
break;
|
||||
|
||||
case JSTRACE_SHAPE: {
|
||||
Shape *shape = static_cast<Shape *>(thing);
|
||||
CompartmentStats *cStats = GetCompartmentStats(shape->compartment());
|
||||
|
25
js/src/vm/Symbol-inl.h
Normal file
25
js/src/vm/Symbol-inl.h
Normal file
@ -0,0 +1,25 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef vm_Symbol_inl_h
|
||||
#define vm_Symbol_inl_h
|
||||
|
||||
#include "vm/Symbol.h"
|
||||
|
||||
#include "gc/Marking.h"
|
||||
|
||||
#include "js/RootingAPI.h"
|
||||
|
||||
#include "jsgcinlines.h"
|
||||
|
||||
inline void
|
||||
JS::Symbol::markChildren(JSTracer *trc)
|
||||
{
|
||||
if (description_)
|
||||
MarkStringUnbarriered(trc, &description_, "description");
|
||||
}
|
||||
|
||||
#endif /* vm_Symbol_inl_h */
|
42
js/src/vm/Symbol.cpp
Normal file
42
js/src/vm/Symbol.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
/* -*- 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 "vm/Symbol.h"
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jscompartment.h"
|
||||
|
||||
#include "gc/Rooting.h"
|
||||
|
||||
#include "jscompartmentinlines.h"
|
||||
#include "jsgcinlines.h"
|
||||
|
||||
using JS::Symbol;
|
||||
using namespace js;
|
||||
|
||||
Symbol *
|
||||
Symbol::new_(ExclusiveContext *cx, JSString *description)
|
||||
{
|
||||
RootedAtom atom(cx);
|
||||
if (description) {
|
||||
atom = AtomizeString(cx, description);
|
||||
if (!atom)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Lock to allocate. If symbol allocation becomes a bottleneck, this can
|
||||
// probably be replaced with an assertion that we're on the main thread.
|
||||
AutoLockForExclusiveAccess lock(cx);
|
||||
AutoCompartment ac(cx, cx->atomsCompartment());
|
||||
|
||||
// Following AtomizeAndCopyChars, we grudgingly forgo last-ditch GC here.
|
||||
Symbol *p = gc::AllocateNonObject<Symbol, NoGC>(cx);
|
||||
if (!p) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
return new (p) Symbol(atom);
|
||||
}
|
46
js/src/vm/Symbol.h
Normal file
46
js/src/vm/Symbol.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef vm_Symbol_h
|
||||
#define vm_Symbol_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "gc/Barrier.h"
|
||||
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
namespace JS {
|
||||
|
||||
class Symbol : public js::gc::BarrieredCell<Symbol>
|
||||
{
|
||||
private:
|
||||
uint32_t unused1_; // This field will be used before long.
|
||||
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
|
||||
// the minimum size on both.
|
||||
uint64_t unused2_;
|
||||
|
||||
explicit Symbol(JSAtom *desc) : description_(desc) {}
|
||||
Symbol(const Symbol &) MOZ_DELETE;
|
||||
void operator=(const Symbol &) MOZ_DELETE;
|
||||
|
||||
public:
|
||||
static Symbol *new_(js::ExclusiveContext *cx, JSString *description);
|
||||
|
||||
JSAtom *description() const { return description_; }
|
||||
|
||||
static inline js::ThingRootKind rootKind() { return js::THING_ROOT_SYMBOL; }
|
||||
inline void markChildren(JSTracer *trc);
|
||||
inline void finalize(js::FreeOp *) {}
|
||||
};
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
#endif /* vm_Symbol_h */
|
@ -1909,6 +1909,10 @@ ReportZoneStats(const JS::ZoneStats &zStats,
|
||||
|
||||
MOZ_ASSERT(!gcTotalOut == zStats.isTotals);
|
||||
|
||||
ZCREPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("symbols/gc-heap"),
|
||||
zStats.symbolsGCHeap,
|
||||
"Symbols.");
|
||||
|
||||
ZCREPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap-arena-admin"),
|
||||
zStats.gcHeapArenaAdmin,
|
||||
"Bookkeeping information and alignment padding within GC arenas.");
|
||||
|
@ -574,6 +574,7 @@ CycleCollectedJSRuntime::DescribeGCThing(bool aIsMarked, void* aThing,
|
||||
static const char trace_types[][11] = {
|
||||
"Object",
|
||||
"String",
|
||||
"Symbol",
|
||||
"Script",
|
||||
"LazyScript",
|
||||
"IonCode",
|
||||
|
Loading…
Reference in New Issue
Block a user