summaryrefslogtreecommitdiffstats
path: root/js/src/vm/Symbol.h
blob: 2872fa3c6e45c5db57343faf36691a27ec81ee21 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/* -*- 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"
#include "js/Utility.h"
#include "vm/String.h"

namespace js {
class AutoLockForExclusiveAccess;
} // namespace js

namespace JS {

class Symbol : public js::gc::TenuredCell
{
  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_;

    JSAtom* description_;

    // The minimum allocation size is sizeof(JSString): 16 bytes on 32-bit
    // architectures and 24 bytes on 64-bit.  A size_t of padding makes Symbol
    // the minimum size on both.
    size_t unused_;

    Symbol(SymbolCode code, js::HashNumber hash, JSAtom* desc)
        : code_(code), hash_(hash), description_(desc)
    {
        // Silence warnings about unused_ being... unused.
        (void)unused_;
    }

    Symbol(const Symbol&) = delete;
    void operator=(const Symbol&) = delete;

    static Symbol*
    newInternal(js::ExclusiveContext* cx, SymbolCode code, js::HashNumber hash,
                JSAtom* description, js::AutoLockForExclusiveAccess& lock);

  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_; }
    js::HashNumber hash() const { return hash_; }

    bool isWellKnownSymbol() const { return uint32_t(code_) < WellKnownSymbolLimit; }

    static const JS::TraceKind TraceKind = JS::TraceKind::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(l->hash());
    }
    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(const JS::Value& v);

JS::Symbol*
ToSymbolPrimitive(const JS::Value& v);

} /* namespace js */

#endif /* vm_Symbol_h */