1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "frontend/BinASTToken.h"
8
9 #include "mozilla/Maybe.h"
10
11 #include <sys/types.h>
12
13 #include "frontend/BinASTRuntimeSupport.h"
14 #include "frontend/TokenStream.h"
15 #include "js/Result.h"
16 #include "vm/JSContext.h"
17
18 namespace js {
19 namespace frontend {
20
21 const BinaryASTSupport::CharSlice BINASTKIND_DESCRIPTIONS[] = {
22 #define WITH_VARIANT(_, SPEC_NAME, _2) \
23 BinaryASTSupport::CharSlice(SPEC_NAME, sizeof(SPEC_NAME) - 1),
24 FOR_EACH_BIN_KIND(WITH_VARIANT)
25 #undef WITH_VARIANT
26 };
27
28 const BinaryASTSupport::CharSlice BINASTFIELD_DESCRIPTIONS[] = {
29 #define WITH_VARIANT(_, SPEC_NAME) \
30 BinaryASTSupport::CharSlice(SPEC_NAME, sizeof(SPEC_NAME) - 1),
31 FOR_EACH_BIN_FIELD(WITH_VARIANT)
32 #undef WITH_VARIANT
33 };
34
35 const BinaryASTSupport::CharSlice BINASTVARIANT_DESCRIPTIONS[] = {
36 #define WITH_VARIANT(_, SPEC_NAME) \
37 BinaryASTSupport::CharSlice(SPEC_NAME, sizeof(SPEC_NAME) - 1),
38 FOR_EACH_BIN_VARIANT(WITH_VARIANT)
39 #undef WITH_VARIANT
40 };
41
42 const BinaryASTSupport::CharSlice BINASTLIST_DESCRIPTIONS[] = {
43 #define NOTHING(_)
44 #define EMIT_NAME(_list_name, _content, SPEC_NAME, _type_name) \
45 BinaryASTSupport::CharSlice(SPEC_NAME, sizeof(SPEC_NAME) - 1),
46 FOR_EACH_BIN_LIST(EMIT_NAME, NOTHING, NOTHING, NOTHING, NOTHING, NOTHING,
47 NOTHING, NOTHING, NOTHING)
48 #undef EMIT_NAME
49 #undef NOTHING
50 };
51
52 const BinaryASTSupport::CharSlice BINASTINTERFACEANDFIELD_DESCRIPTIONS[] = {
53 #define WITH_VARIANT(_, SPEC_NAME) \
54 BinaryASTSupport::CharSlice(SPEC_NAME, sizeof(SPEC_NAME) - 1),
55 FOR_EACH_BIN_INTERFACE_AND_FIELD(WITH_VARIANT)
56 #undef WITH_VARIANT
57 };
58
getBinASTKind(const BinASTKind & variant)59 const BinaryASTSupport::CharSlice& getBinASTKind(const BinASTKind& variant) {
60 return BINASTKIND_DESCRIPTIONS[static_cast<size_t>(variant)];
61 }
62
getBinASTVariant(const BinASTVariant & variant)63 const BinaryASTSupport::CharSlice& getBinASTVariant(
64 const BinASTVariant& variant) {
65 return BINASTVARIANT_DESCRIPTIONS[static_cast<size_t>(variant)];
66 }
67
getBinASTField(const BinASTField & variant)68 const BinaryASTSupport::CharSlice& getBinASTField(const BinASTField& variant) {
69 return BINASTFIELD_DESCRIPTIONS[static_cast<size_t>(variant)];
70 }
71
getBinASTList(const BinASTList & list)72 const BinaryASTSupport::CharSlice& getBinASTList(const BinASTList& list) {
73 return BINASTLIST_DESCRIPTIONS[static_cast<size_t>(list)];
74 }
75
getBinASTInterfaceAndField(const BinASTInterfaceAndField & interfaceAndField)76 const BinaryASTSupport::CharSlice& getBinASTInterfaceAndField(
77 const BinASTInterfaceAndField& interfaceAndField) {
78 return BINASTINTERFACEANDFIELD_DESCRIPTIONS[static_cast<size_t>(
79 interfaceAndField)];
80 }
81
describeBinASTKind(const BinASTKind & kind)82 const char* describeBinASTKind(const BinASTKind& kind) {
83 return getBinASTKind(kind).begin();
84 }
85
describeBinASTField(const BinASTField & field)86 const char* describeBinASTField(const BinASTField& field) {
87 return getBinASTField(field).begin();
88 }
89
describeBinASTVariant(const BinASTVariant & variant)90 const char* describeBinASTVariant(const BinASTVariant& variant) {
91 return getBinASTVariant(variant).begin();
92 }
93
describeBinASTList(const BinASTList & list)94 const char* describeBinASTList(const BinASTList& list) {
95 return getBinASTList(list).begin();
96 }
97
describeBinASTInterfaceAndField(const BinASTInterfaceAndField & interfaceAndField)98 const char* describeBinASTInterfaceAndField(
99 const BinASTInterfaceAndField& interfaceAndField) {
100 return getBinASTInterfaceAndField(interfaceAndField).begin();
101 }
102
getBinASTKindSortKey(const BinASTKind & kind)103 size_t getBinASTKindSortKey(const BinASTKind& kind) {
104 return static_cast<size_t>(kind);
105 }
106
getBinASTVariantSortKey(const BinASTVariant & variant)107 size_t getBinASTVariantSortKey(const BinASTVariant& variant) {
108 return static_cast<size_t>(variant);
109 }
110
111 } // namespace frontend
112
BinaryASTSupport()113 BinaryASTSupport::BinaryASTSupport()
114 : binASTKindMap_(frontend::BINASTKIND_LIMIT),
115 binASTFieldMap_(frontend::BINASTFIELD_LIMIT),
116 binASTVariantMap_(frontend::BINASTVARIANT_LIMIT) {}
117
118 /**
119 * It is expected that all bin tables are initialized on the main thread, and
120 * that any helper threads will find the read-only tables properly initialized,
121 * so that they can do their accesses safely without taking any locks.
122 */
ensureBinTablesInitialized(JSContext * cx)123 bool BinaryASTSupport::ensureBinTablesInitialized(JSContext* cx) {
124 return ensureBinASTKindsInitialized(cx) &&
125 ensureBinASTVariantsInitialized(cx);
126 }
127
ensureBinASTKindsInitialized(JSContext * cx)128 bool BinaryASTSupport::ensureBinASTKindsInitialized(JSContext* cx) {
129 MOZ_ASSERT(!cx->isHelperThreadContext());
130 if (binASTKindMap_.empty()) {
131 for (size_t i = 0; i < frontend::BINASTKIND_LIMIT; ++i) {
132 const BinASTKind variant = static_cast<BinASTKind>(i);
133 const CharSlice& key = getBinASTKind(variant);
134 auto ptr = binASTKindMap_.lookupForAdd(key);
135 MOZ_ASSERT(!ptr);
136 if (MOZ_UNLIKELY(!binASTKindMap_.add(ptr, key, variant))) {
137 ReportOutOfMemory(cx);
138 return false;
139 }
140 }
141 }
142
143 return true;
144 }
145
ensureBinASTVariantsInitialized(JSContext * cx)146 bool BinaryASTSupport::ensureBinASTVariantsInitialized(JSContext* cx) {
147 MOZ_ASSERT(!cx->isHelperThreadContext());
148 if (binASTVariantMap_.empty()) {
149 for (size_t i = 0; i < frontend::BINASTVARIANT_LIMIT; ++i) {
150 const BinASTVariant variant = static_cast<BinASTVariant>(i);
151 const CharSlice& key = getBinASTVariant(variant);
152 auto ptr = binASTVariantMap_.lookupForAdd(key);
153 MOZ_ASSERT(!ptr);
154 if (MOZ_UNLIKELY(!binASTVariantMap_.add(ptr, key, variant))) {
155 ReportOutOfMemory(cx);
156 return false;
157 }
158 }
159 }
160 return true;
161 }
162
binASTKind(JSContext * cx,const CharSlice key)163 JS::Result<const js::frontend::BinASTKind*> BinaryASTSupport::binASTKind(
164 JSContext* cx, const CharSlice key) {
165 MOZ_ASSERT_IF(cx->isHelperThreadContext(), !binASTKindMap_.empty());
166 if (!cx->isHelperThreadContext()) {
167 // Initialize Lazily if on main thread.
168 if (MOZ_UNLIKELY(!ensureBinASTKindsInitialized(cx))) {
169 return cx->alreadyReportedError();
170 }
171 }
172
173 auto ptr = binASTKindMap_.readonlyThreadsafeLookup(key);
174 if (!ptr) {
175 return nullptr;
176 }
177
178 return &ptr->value();
179 }
180
binASTVariant(JSContext * cx,const CharSlice key)181 JS::Result<const js::frontend::BinASTVariant*> BinaryASTSupport::binASTVariant(
182 JSContext* cx, const CharSlice key) {
183 MOZ_ASSERT_IF(cx->isHelperThreadContext(), !binASTVariantMap_.empty());
184 if (!cx->isHelperThreadContext()) {
185 // Initialize lazily if on main thread.
186 if (MOZ_UNLIKELY(!ensureBinASTVariantsInitialized(cx))) {
187 return cx->alreadyReportedError();
188 }
189 }
190
191 auto ptr = binASTVariantMap_.readonlyThreadsafeLookup(key);
192 if (!ptr) {
193 return nullptr;
194 }
195
196 return &ptr->value();
197 }
198
199 } // namespace js
200