2 * Copyright 2016 WebAssembly Community Group participants
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "wabt/generate-names.h"
24 #include "wabt/cast.h"
25 #include "wabt/expr-visitor.h"
32 class NameGenerator
: public ExprVisitor::DelegateNop
{
34 NameGenerator(NameOpts opts
);
36 Result
VisitModule(Module
* module
);
38 // Implementation of ExprVisitor::DelegateNop.
39 Result
BeginBlockExpr(BlockExpr
* expr
) override
;
40 Result
BeginTryExpr(TryExpr
* expr
) override
;
41 Result
BeginLoopExpr(LoopExpr
* expr
) override
;
42 Result
BeginIfExpr(IfExpr
* expr
) override
;
45 static bool HasName(const std::string
& str
);
47 // Generate a name with the given prefix, followed by the index and
48 // optionally a disambiguating number. If index == kInvalidIndex, the index
50 void GenerateName(const char* prefix
,
52 unsigned disambiguator
,
53 std::string
* out_str
);
55 // Like GenerateName, but only generates a name if |out_str| is empty.
56 void MaybeGenerateName(const char* prefix
, Index index
, std::string
* out_str
);
58 // Generate a name via GenerateName and bind it to the given binding hash. If
59 // the name already exists, the name will be disambiguated until it can be
61 void GenerateAndBindName(BindingHash
* bindings
,
64 std::string
* out_str
);
66 // Like GenerateAndBindName, but only generates a name if |out_str| is empty.
67 void MaybeGenerateAndBindName(BindingHash
* bindings
,
70 std::string
* out_str
);
72 // Like MaybeGenerateAndBindName but uses the name directly, without
73 // appending the index. If the name already exists, a disambiguating suffix
75 void MaybeUseAndBindName(BindingHash
* bindings
,
78 std::string
* out_str
);
80 void GenerateAndBindLocalNames(Func
* func
);
83 Result
VisitAll(const std::vector
<T
*>& items
,
84 Result (NameGenerator::*func
)(Index
, T
*));
86 Result
VisitFunc(Index func_index
, Func
* func
);
87 Result
VisitGlobal(Index global_index
, Global
* global
);
88 Result
VisitType(Index func_type_index
, TypeEntry
* type
);
89 Result
VisitTable(Index table_index
, Table
* table
);
90 Result
VisitMemory(Index memory_index
, Memory
* memory
);
91 Result
VisitTag(Index tag_index
, Tag
* tag
);
92 Result
VisitDataSegment(Index data_segment_index
, DataSegment
* data_segment
);
93 Result
VisitElemSegment(Index elem_segment_index
, ElemSegment
* elem_segment
);
94 Result
VisitImport(Import
* import
);
95 Result
VisitExport(Export
* export_
);
97 Module
* module_
= nullptr;
99 Index label_count_
= 0;
101 Index num_func_imports_
= 0;
102 Index num_table_imports_
= 0;
103 Index num_memory_imports_
= 0;
104 Index num_global_imports_
= 0;
105 Index num_tag_imports_
= 0;
110 NameGenerator::NameGenerator(NameOpts opts
) : visitor_(this), opts_(opts
) {}
113 bool NameGenerator::HasName(const std::string
& str
) {
117 void NameGenerator::GenerateName(const char* prefix
,
119 unsigned disambiguator
,
123 if (index
!= kInvalidIndex
) {
124 if (opts_
& NameOpts::AlphaNames
) {
125 // For params and locals, do not use a prefix char.
126 if (!strcmp(prefix
, "p") || !strcmp(prefix
, "l")) {
131 *str
+= IndexToAlphaName(index
);
133 *str
+= std::to_string(index
);
136 if (disambiguator
!= 0) {
137 *str
+= '_' + std::to_string(disambiguator
);
141 void NameGenerator::MaybeGenerateName(const char* prefix
,
144 if (!HasName(*str
)) {
145 // There's no bindings hash, so the name can't be a duplicate. Therefore it
146 // doesn't need a disambiguating number.
147 GenerateName(prefix
, index
, 0, str
);
151 void NameGenerator::GenerateAndBindName(BindingHash
* bindings
,
155 unsigned disambiguator
= 0;
157 GenerateName(prefix
, index
, disambiguator
, str
);
158 if (bindings
->find(*str
) == bindings
->end()) {
159 bindings
->emplace(*str
, Binding(index
));
167 void NameGenerator::MaybeGenerateAndBindName(BindingHash
* bindings
,
171 if (!HasName(*str
)) {
172 GenerateAndBindName(bindings
, prefix
, index
, str
);
176 void NameGenerator::MaybeUseAndBindName(BindingHash
* bindings
,
180 if (!HasName(*str
)) {
181 unsigned disambiguator
= 0;
183 GenerateName(name
, kInvalidIndex
, disambiguator
, str
);
184 if (bindings
->find(*str
) == bindings
->end()) {
185 bindings
->emplace(*str
, Binding(index
));
194 void NameGenerator::GenerateAndBindLocalNames(Func
* func
) {
195 std::vector
<std::string
> index_to_name
;
196 MakeTypeBindingReverseMapping(func
->GetNumParamsAndLocals(), func
->bindings
,
198 for (size_t i
= 0; i
< index_to_name
.size(); ++i
) {
199 const std::string
& old_name
= index_to_name
[i
];
200 if (!old_name
.empty()) {
204 const char* prefix
= i
< func
->GetNumParams() ? "p" : "l";
205 std::string new_name
;
206 GenerateAndBindName(&func
->bindings
, prefix
, i
, &new_name
);
207 index_to_name
[i
] = new_name
;
211 Result
NameGenerator::BeginBlockExpr(BlockExpr
* expr
) {
212 MaybeGenerateName("B", label_count_
++, &expr
->block
.label
);
216 Result
NameGenerator::BeginTryExpr(TryExpr
* expr
) {
217 MaybeGenerateName("T", label_count_
++, &expr
->block
.label
);
221 Result
NameGenerator::BeginLoopExpr(LoopExpr
* expr
) {
222 MaybeGenerateName("L", label_count_
++, &expr
->block
.label
);
226 Result
NameGenerator::BeginIfExpr(IfExpr
* expr
) {
227 MaybeGenerateName("I", label_count_
++, &expr
->true_
.label
);
231 Result
NameGenerator::VisitFunc(Index func_index
, Func
* func
) {
232 MaybeGenerateAndBindName(&module_
->func_bindings
, "f", func_index
,
234 GenerateAndBindLocalNames(func
);
237 CHECK_RESULT(visitor_
.VisitFunc(func
));
241 Result
NameGenerator::VisitGlobal(Index global_index
, Global
* global
) {
242 MaybeGenerateAndBindName(&module_
->global_bindings
, "g", global_index
,
247 Result
NameGenerator::VisitType(Index type_index
, TypeEntry
* type
) {
248 MaybeGenerateAndBindName(&module_
->type_bindings
, "t", type_index
,
253 Result
NameGenerator::VisitTable(Index table_index
, Table
* table
) {
254 MaybeGenerateAndBindName(&module_
->table_bindings
, "T", table_index
,
259 Result
NameGenerator::VisitMemory(Index memory_index
, Memory
* memory
) {
260 MaybeGenerateAndBindName(&module_
->memory_bindings
, "M", memory_index
,
265 Result
NameGenerator::VisitTag(Index tag_index
, Tag
* tag
) {
266 MaybeGenerateAndBindName(&module_
->tag_bindings
, "e", tag_index
, &tag
->name
);
270 Result
NameGenerator::VisitDataSegment(Index data_segment_index
,
271 DataSegment
* data_segment
) {
272 MaybeGenerateAndBindName(&module_
->data_segment_bindings
, "d",
273 data_segment_index
, &data_segment
->name
);
277 Result
NameGenerator::VisitElemSegment(Index elem_segment_index
,
278 ElemSegment
* elem_segment
) {
279 MaybeGenerateAndBindName(&module_
->elem_segment_bindings
, "e",
280 elem_segment_index
, &elem_segment
->name
);
284 Result
NameGenerator::VisitImport(Import
* import
) {
285 BindingHash
* bindings
= nullptr;
286 std::string
* name
= nullptr;
287 Index index
= kInvalidIndex
;
289 switch (import
->kind()) {
290 case ExternalKind::Func
:
291 if (auto* func_import
= cast
<FuncImport
>(import
)) {
292 bindings
= &module_
->func_bindings
;
293 name
= &func_import
->func
.name
;
294 index
= num_func_imports_
++;
298 case ExternalKind::Table
:
299 if (auto* table_import
= cast
<TableImport
>(import
)) {
300 bindings
= &module_
->table_bindings
;
301 name
= &table_import
->table
.name
;
302 index
= num_table_imports_
++;
306 case ExternalKind::Memory
:
307 if (auto* memory_import
= cast
<MemoryImport
>(import
)) {
308 bindings
= &module_
->memory_bindings
;
309 name
= &memory_import
->memory
.name
;
310 index
= num_memory_imports_
++;
314 case ExternalKind::Global
:
315 if (auto* global_import
= cast
<GlobalImport
>(import
)) {
316 bindings
= &module_
->global_bindings
;
317 name
= &global_import
->global
.name
;
318 index
= num_global_imports_
++;
322 case ExternalKind::Tag
:
323 if (auto* tag_import
= cast
<TagImport
>(import
)) {
324 bindings
= &module_
->tag_bindings
;
325 name
= &tag_import
->tag
.name
;
326 index
= num_tag_imports_
++;
331 if (bindings
&& name
) {
332 assert(index
!= kInvalidIndex
);
333 std::string new_name
= import
->module_name
+ '.' + import
->field_name
;
334 MaybeUseAndBindName(bindings
, new_name
.c_str(), index
, name
);
340 Result
NameGenerator::VisitExport(Export
* export_
) {
341 BindingHash
* bindings
= nullptr;
342 std::string
* name
= nullptr;
343 Index index
= kInvalidIndex
;
345 switch (export_
->kind
) {
346 case ExternalKind::Func
:
347 if (Func
* func
= module_
->GetFunc(export_
->var
)) {
348 index
= module_
->GetFuncIndex(export_
->var
);
349 bindings
= &module_
->func_bindings
;
354 case ExternalKind::Table
:
355 if (Table
* table
= module_
->GetTable(export_
->var
)) {
356 index
= module_
->GetTableIndex(export_
->var
);
357 bindings
= &module_
->table_bindings
;
362 case ExternalKind::Memory
:
363 if (Memory
* memory
= module_
->GetMemory(export_
->var
)) {
364 index
= module_
->GetMemoryIndex(export_
->var
);
365 bindings
= &module_
->memory_bindings
;
366 name
= &memory
->name
;
370 case ExternalKind::Global
:
371 if (Global
* global
= module_
->GetGlobal(export_
->var
)) {
372 index
= module_
->GetGlobalIndex(export_
->var
);
373 bindings
= &module_
->global_bindings
;
374 name
= &global
->name
;
378 case ExternalKind::Tag
:
379 if (Tag
* tag
= module_
->GetTag(export_
->var
)) {
380 index
= module_
->GetTagIndex(export_
->var
);
381 bindings
= &module_
->tag_bindings
;
387 if (bindings
&& name
) {
388 MaybeUseAndBindName(bindings
, export_
->name
.c_str(), index
, name
);
394 template <typename T
>
395 Result
NameGenerator::VisitAll(const std::vector
<T
*>& items
,
396 Result (NameGenerator::*func
)(Index
, T
*)) {
397 for (Index i
= 0; i
< items
.size(); ++i
) {
398 CHECK_RESULT((this->*func
)(i
, items
[i
]));
403 Result
NameGenerator::VisitModule(Module
* module
) {
405 // Visit imports and exports first to give better names, derived from the
406 // import/export name.
407 for (auto* import
: module
->imports
) {
408 CHECK_RESULT(VisitImport(import
));
410 for (auto* export_
: module
->exports
) {
411 CHECK_RESULT(VisitExport(export_
));
414 VisitAll(module
->globals
, &NameGenerator::VisitGlobal
);
415 VisitAll(module
->types
, &NameGenerator::VisitType
);
416 VisitAll(module
->funcs
, &NameGenerator::VisitFunc
);
417 VisitAll(module
->tables
, &NameGenerator::VisitTable
);
418 VisitAll(module
->memories
, &NameGenerator::VisitMemory
);
419 VisitAll(module
->tags
, &NameGenerator::VisitTag
);
420 VisitAll(module
->data_segments
, &NameGenerator::VisitDataSegment
);
421 VisitAll(module
->elem_segments
, &NameGenerator::VisitElemSegment
);
426 } // end anonymous namespace
428 Result
GenerateNames(Module
* module
, NameOpts opts
) {
429 NameGenerator
generator(opts
);
430 return generator
.VisitModule(module
);