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