blob: c201ed127c5005487974460fb74e14d27f427ff5 [file] [log] [blame]
/* -*- 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 <stdio.h>
#include "jsalloc.h"
#include "jsapi.h"
#include "gc/Barrier.h"
#include "gc/Marking.h"
#include "js/GCHashTable.h"
#include "js/RootingAPI.h"
#include "js/TypeDecls.h"
namespace JS {
class Symbol : public js::gc::TenuredCell
{
private:
SymbolCode code_;
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_;
Symbol(SymbolCode code, JSAtom* desc)
: code_(code), description_(desc)
{
// Silence warnings about unused2 being... unused.
(void)unused2_;
}
Symbol(const Symbol&) = delete;
void operator=(const Symbol&) = delete;
static Symbol*
newInternal(js::ExclusiveContext* cx, SymbolCode code, JSAtom* description);
public:
static Symbol* new_(js::ExclusiveContext* cx, SymbolCode code, JSString* description);
static Symbol* for_(js::ExclusiveContext* cx, js::HandleString description);
JSAtom* description() const { return description_; }
SymbolCode code() const { return code_; }
bool isWellKnownSymbol() const { return uint32_t(code_) < WellKnownSymbolLimit; }
static inline js::ThingRootKind rootKind() { return js::THING_ROOT_SYMBOL; }
inline void traceChildren(JSTracer* trc) {
if (description_)
js::TraceManuallyBarrieredEdge(trc, &description_, "description");
}
inline void finalize(js::FreeOp*) {}
static MOZ_ALWAYS_INLINE void writeBarrierPre(Symbol* thing) {
if (thing && !thing->isWellKnownSymbol())
thing->asTenured().writeBarrierPre(thing);
}
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
return mallocSizeOf(this);
}
#ifdef DEBUG
void dump(FILE* fp = stderr);
#endif
};
} /* namespace JS */
namespace js {
/* Hash policy used by the SymbolRegistry. */
struct HashSymbolsByDescription
{
typedef JS::Symbol* Key;
typedef JSAtom* Lookup;
static HashNumber hash(Lookup l) {
return HashNumber(reinterpret_cast<uintptr_t>(l));
}
static bool match(Key sym, Lookup l) {
return sym->description() == l;
}
};
/*
* The runtime-wide symbol registry, used to implement Symbol.for().
*
* ES6 draft rev 25 (2014 May 22) calls this the GlobalSymbolRegistry List. In
* our implementation, it is not global. There is one per JSRuntime. The
* symbols in the symbol registry, like all symbols, are allocated in the atoms
* compartment and can be directly referenced from any compartment. They are
* never shared across runtimes.
*
* The memory management strategy here is modeled after js::AtomSet. It's like
* a WeakSet. The registry itself does not keep any symbols alive; when a
* symbol in the registry is collected, the registry entry is removed. No GC
* nondeterminism is exposed to scripts, because there is no API for
* enumerating the symbol registry, querying its size, etc.
*/
class SymbolRegistry : public GCHashSet<ReadBarrieredSymbol,
HashSymbolsByDescription,
SystemAllocPolicy>
{
public:
SymbolRegistry() {}
};
} /* namespace js */
namespace js {
// ES6 rev 27 (2014 Aug 24) 19.4.3.3
bool
SymbolDescriptiveString(JSContext* cx, JS::Symbol* sym, JS::MutableHandleValue result);
bool
IsSymbolOrSymbolWrapper(JS::Value v);
JS::Symbol*
ToSymbolPrimitive(JS::Value v);
} /* namespace js */
#endif /* vm_Symbol_h */