summaryrefslogtreecommitdiffstats
path: root/js/src/vm/SymbolType.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm/SymbolType.h')
-rw-r--r--js/src/vm/SymbolType.h153
1 files changed, 153 insertions, 0 deletions
diff --git a/js/src/vm/SymbolType.h b/js/src/vm/SymbolType.h
new file mode 100644
index 0000000000..2a66e6c30f
--- /dev/null
+++ b/js/src/vm/SymbolType.h
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * 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_SymbolType_h
+#define vm_SymbolType_h
+
+#include <stdio.h>
+
+#include "gc/Barrier.h"
+#include "gc/Tracer.h"
+#include "js/AllocPolicy.h"
+#include "js/GCHashTable.h"
+#include "js/RootingAPI.h"
+#include "js/shadow/Symbol.h" // JS::shadow::Symbol
+#include "js/Symbol.h"
+#include "js/TypeDecls.h"
+#include "vm/StringType.h"
+
+namespace js {
+class JS_PUBLIC_API GenericPrinter;
+}
+
+namespace JS {
+
+class Symbol
+ : public js::gc::CellWithTenuredGCPointer<js::gc::TenuredCell, JSAtom> {
+ friend class js::gc::CellAllocator;
+
+ public:
+ // User description of symbol, stored in the cell header.
+ JSAtom* description() const { return headerPtr(); }
+
+ private:
+ SymbolCode code_;
+
+ // Each Symbol gets its own hash code so that we don't have to use
+ // addresses as hash codes (a security hazard).
+ js::HashNumber hash_;
+
+ Symbol(SymbolCode code, js::HashNumber hash, Handle<JSAtom*> desc)
+ : CellWithTenuredGCPointer(desc), code_(code), hash_(hash) {}
+
+ Symbol(const Symbol&) = delete;
+ void operator=(const Symbol&) = delete;
+
+ static Symbol* newInternal(JSContext* cx, SymbolCode code,
+ js::HashNumber hash, Handle<JSAtom*> description);
+
+ static void staticAsserts() {
+ static_assert(uint32_t(SymbolCode::WellKnownAPILimit) ==
+ JS::shadow::Symbol::WellKnownAPILimit,
+ "JS::shadow::Symbol::WellKnownAPILimit must match "
+ "SymbolCode::WellKnownAPILimit");
+ static_assert(
+ offsetof(Symbol, code_) == offsetof(JS::shadow::Symbol, code_),
+ "JS::shadow::Symbol::code_ offset must match SymbolCode::code_");
+ }
+
+ public:
+ static Symbol* new_(JSContext* cx, SymbolCode code,
+ js::HandleString description);
+ static Symbol* newWellKnown(JSContext* cx, SymbolCode code,
+ Handle<js::PropertyName*> description);
+ static Symbol* for_(JSContext* cx, js::HandleString description);
+
+ SymbolCode code() const { return code_; }
+ js::HashNumber hash() const { return hash_; }
+
+ bool isWellKnownSymbol() const {
+ return uint32_t(code_) < WellKnownSymbolLimit;
+ }
+
+ // An "interesting symbol" is a well-known symbol, like @@toStringTag,
+ // that's often looked up on random objects but is usually not present. We
+ // optimize this by setting a flag on the object's BaseShape when such
+ // symbol properties are added, so we can optimize lookups on objects that
+ // don't have the BaseShape flag.
+ bool isInterestingSymbol() const {
+ return code_ == SymbolCode::toStringTag ||
+ code_ == SymbolCode::toPrimitive ||
+ code_ == SymbolCode::isConcatSpreadable;
+ }
+
+ // Symbol created for the #PrivateName syntax.
+ bool isPrivateName() const { return code_ == SymbolCode::PrivateNameSymbol; }
+
+ static const JS::TraceKind TraceKind = JS::TraceKind::Symbol;
+
+ void traceChildren(JSTracer* trc);
+ void finalize(JS::GCContext* gcx) {}
+
+ // Override base class implementation to tell GC about well-known symbols.
+ bool isPermanentAndMayBeShared() const { return isWellKnownSymbol(); }
+
+ size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+ return mallocSizeOf(this);
+ }
+
+#if defined(DEBUG) || defined(JS_JITSPEW)
+ void dump(); // Debugger-friendly stderr dump.
+ void dump(js::GenericPrinter& out);
+#endif
+
+ static constexpr size_t offsetOfHash() { return offsetof(Symbol, hash_); }
+};
+
+} /* namespace JS */
+
+namespace js {
+
+/* Hash policy used by the SymbolRegistry. */
+struct HashSymbolsByDescription {
+ using Key = JS::Symbol*;
+ using Lookup = JSAtom*;
+
+ static HashNumber hash(Lookup l) { return HashNumber(l->hash()); }
+ static bool match(Key sym, Lookup l) { return sym->description() == l; }
+};
+
+/*
+ * [SMDOC] Symbol.for() registry (ES6 GlobalSymbolRegistry)
+ *
+ * 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<WeakHeapPtr<JS::Symbol*>, HashSymbolsByDescription,
+ SystemAllocPolicy> {
+ public:
+ SymbolRegistry() = default;
+};
+
+// ES6 rev 27 (2014 Aug 24) 19.4.3.3
+bool SymbolDescriptiveString(JSContext* cx, JS::Symbol* sym,
+ JS::MutableHandleValue result);
+
+} /* namespace js */
+
+#endif /* vm_SymbolType_h */