xref: /llvm-project/llvm/unittests/DebugInfo/LogicalView/LocationRangesTest.cpp (revision 7fbcc24409efdb37cec79ad461ef383f6ffc5ef2)
1 //===- llvm/unittest/DebugInfo/LogicalView/LocationRangesTest.cpp ---------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
10 #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
11 #include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
12 #include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
13 #include "llvm/DebugInfo/LogicalView/Core/LVType.h"
14 #include "llvm/Support/ScopedPrinter.h"
15 #include "llvm/Support/ToolOutputFile.h"
16 #include "llvm/Testing/Support/Error.h"
17 
18 #include "gtest/gtest.h"
19 
20 using namespace llvm;
21 using namespace llvm::logicalview;
22 
23 namespace {
24 
25 class ReaderTest : public LVReader {
26 protected:
27   void add(LVSymbol *Symbol, LVLine *LowerLine, LVLine *UpperLine);
28   void add(LVScope *Parent, LVElement *Element);
29   void set(LVElement *Element, StringRef Name, LVOffset Offset,
30            uint32_t LineNumber = 0, LVElement *Type = nullptr);
31   void set(LVLocation *Location, LVLine *LowerLine, LVLine *UpperLine,
32            LVAddress LowerAddress, LVAddress UpperAddress);
33 
34 public:
ReaderTest(ScopedPrinter & W)35   ReaderTest(ScopedPrinter &W) : LVReader("", "", W) { setInstance(this); }
36 
createScopes()37   Error createScopes() { return LVReader::createScopes(); }
38 };
39 
40 // Helper function to add a logical element to a given scope.
add(LVScope * Parent,LVElement * Child)41 void ReaderTest::add(LVScope *Parent, LVElement *Child) {
42   Parent->addElement(Child);
43   EXPECT_EQ(Child->getParent(), Parent);
44   EXPECT_EQ(Child->getLevel(), Parent->getLevel() + 1);
45 }
46 
47 // Helper function to set the initial values for a given logical element.
set(LVElement * Element,StringRef Name,LVOffset Offset,uint32_t LineNumber,LVElement * Type)48 void ReaderTest::set(LVElement *Element, StringRef Name, LVOffset Offset,
49                      uint32_t LineNumber, LVElement *Type) {
50   Element->setName(Name);
51   Element->setOffset(Offset);
52   Element->setLineNumber(LineNumber);
53   Element->setType(Type);
54   EXPECT_EQ(Element->getName(), Name);
55   EXPECT_EQ(Element->getOffset(), Offset);
56   EXPECT_EQ(Element->getLineNumber(), LineNumber);
57   EXPECT_EQ(Element->getType(), Type);
58 }
59 
60 // Helper function to set the initial values for a given logical location.
set(LVLocation * Location,LVLine * LowerLine,LVLine * UpperLine,LVAddress LowerAddress,LVAddress UpperAddress)61 void ReaderTest::set(LVLocation *Location, LVLine *LowerLine, LVLine *UpperLine,
62                      LVAddress LowerAddress, LVAddress UpperAddress) {
63   Location->setLowerLine(LowerLine);
64   Location->setUpperLine(UpperLine);
65   Location->setLowerAddress(LowerAddress);
66   Location->setUpperAddress(UpperAddress);
67   EXPECT_EQ(Location->getLowerLine(), LowerLine);
68   EXPECT_EQ(Location->getUpperLine(), UpperLine);
69   EXPECT_EQ(Location->getLowerAddress(), LowerAddress);
70   EXPECT_EQ(Location->getUpperAddress(), UpperAddress);
71 }
72 
73 // Helper function to add a logical location to a logical symbol.
add(LVSymbol * Symbol,LVLine * LowerLine,LVLine * UpperLine)74 void ReaderTest::add(LVSymbol *Symbol, LVLine *LowerLine, LVLine *UpperLine) {
75   dwarf::Attribute Attr = dwarf::DW_AT_location;
76 
77   Symbol->addLocation(Attr, LowerLine->getAddress(), UpperLine->getAddress(),
78                       /*SectionOffset=*/0, /*LocDesOffset=*/0);
79 }
80 
81 class ReaderTestLocations : public ReaderTest {
82 #define CREATE(VARIABLE, CREATE_FUNCTION)                                      \
83   VARIABLE = CREATE_FUNCTION();                                                \
84   EXPECT_NE(VARIABLE, nullptr);
85 
86   // Types.
87   LVType *IntegerType = nullptr;
88 
89   // Scopes.
90   LVScope *NestedScope = nullptr;
91   LVScopeFunction *Function = nullptr;
92 
93   // Symbols.
94   LVSymbol *LocalVariable = nullptr;
95   LVSymbol *NestedVariable = nullptr;
96   LVSymbol *Parameter = nullptr;
97 
98   // Lines.
99   LVLine *LineOne = nullptr;
100   LVLine *LineTwo = nullptr;
101   LVLine *LineThree = nullptr;
102   LVLine *LineFour = nullptr;
103   LVLine *LineFive = nullptr;
104   LVLine *LineSix = nullptr;
105 
106   // Locations.
107   LVLocation *LocationOne = nullptr;
108   LVLocation *LocationTwo = nullptr;
109   LVLocation *LocationThree = nullptr;
110   LVLocation *LocationFour = nullptr;
111   LVLocation *LocationFive = nullptr;
112   LVLocation *LocationSix = nullptr;
113 
114 public:
ReaderTestLocations(ScopedPrinter & W)115   ReaderTestLocations(ScopedPrinter &W) : ReaderTest(W) {}
116 
117   void createElements();
118   void addElements();
119   void initElements();
120 };
121 
122 // Create the logical elements.
createElements()123 void ReaderTestLocations::createElements() {
124   // Create scope root.
125   Error Err = createScopes();
126   ASSERT_THAT_ERROR(std::move(Err), Succeeded());
127   Root = getScopesRoot();
128   EXPECT_NE(Root, nullptr);
129 
130   // Create the logical types.
131   CREATE(IntegerType, createType);
132 
133   // Create the logical scopes.
134   CREATE(NestedScope, createScope);
135   CREATE(CompileUnit, createScopeCompileUnit);
136   CREATE(Function, createScopeFunction);
137 
138   // Create the logical symbols.
139   CREATE(LocalVariable, createSymbol);
140   CREATE(NestedVariable, createSymbol);
141   CREATE(Parameter, createSymbol);
142 
143   // Create the logical lines.
144   CREATE(LineOne, createLine);
145   CREATE(LineTwo, createLine);
146   CREATE(LineThree, createLine);
147   CREATE(LineFour, createLine);
148   CREATE(LineFive, createLine);
149   CREATE(LineSix, createLine);
150 
151   // Create the logical locations.
152   CREATE(LocationOne, createLocation);
153   CREATE(LocationTwo, createLocation);
154   CREATE(LocationThree, createLocation);
155   CREATE(LocationFour, createLocation);
156   CREATE(LocationFive, createLocation);
157   CREATE(LocationSix, createLocation);
158 }
159 
160 // Create the logical view adding the created logical elements.
addElements()161 void ReaderTestLocations::addElements() {
162   setCompileUnit(CompileUnit);
163 
164   // Root
165   //   CompileUnit
166   //     IntegerType
167   //     Function
168   //       LocationOne
169   //       LocationTwo
170   //       LocationFive
171   //       LocationSix
172   //       Parameter
173   //       LocalVariable
174   //       LineOne
175   //       LineTwo
176   //       NestedScope
177   //         LocationThree
178   //         LocationFour
179   //         NestedVariable
180   //         LineThree
181   //         LineFour
182   //       LineFive
183   //       LineSix
184 
185   // Add elements to Root.
186   add(Root, CompileUnit);
187 
188   // Add elements to CompileUnit.
189   add(CompileUnit, IntegerType);
190   add(CompileUnit, Function);
191 
192   // Add elements to Function.
193   add(Function, Parameter);
194   add(Function, LocalVariable);
195   add(Function, LineOne);
196   add(Function, LineTwo);
197   add(Function, LineFive);
198   add(Function, LineSix);
199   add(Function, NestedScope);
200 
201   // Add elements to NestedScope.
202   add(NestedScope, NestedVariable);
203   add(NestedScope, LineThree);
204   add(NestedScope, LineFour);
205 }
206 
207 // Set initial values to logical elements.
initElements()208 void ReaderTestLocations::initElements() {
209   // Types.
210   set(IntegerType, "int", 0x1000);
211 
212   // Scopes.
213   set(CompileUnit, "foo.cpp", 0x2000);
214   set(Function, "foo", 0x2010, 100, IntegerType);
215   set(NestedScope, "", 0x2020, 300);
216 
217   // Symbols.
218   set(Parameter, "Param", 0x3000, 110, IntegerType);
219   set(LocalVariable, "LocalVariable", 0x3000, 120, IntegerType);
220   set(NestedVariable, "NestedVariable", 0x3010, 310, IntegerType);
221 
222   // Lines.
223   set(LineOne, "", 0x5000, 100);
224   set(LineTwo, "", 0x5200, 200);
225   set(LineThree, "", 0x5400, 300);
226   set(LineFour, "", 0x5600, 400);
227   set(LineFive, "", 0x5800, 500);
228   set(LineSix, "", 0x6000, 600);
229 
230   // Locations.
231   set(LocationOne, LineOne, LineOne, 0x5000, 0x5100);
232   EXPECT_STREQ(LocationOne->getIntervalInfo().c_str(),
233                " Lines 100:100 [0x0000005000:0x0000005100]");
234 
235   set(LocationTwo, LineTwo, LineTwo, 0x5200, 0x5300);
236   EXPECT_STREQ(LocationTwo->getIntervalInfo().c_str(),
237                " Lines 200:200 [0x0000005200:0x0000005300]");
238 
239   set(LocationThree, LineThree, LineThree, 0x5400, 0x5500);
240   EXPECT_STREQ(LocationThree->getIntervalInfo().c_str(),
241                " Lines 300:300 [0x0000005400:0x0000005500]");
242 
243   set(LocationFour, LineFour, LineFour, 0x5600, 0x5700);
244   LocationFour->setIsAddressRange();
245   EXPECT_STREQ(LocationFour->getIntervalInfo().c_str(),
246                "{Range} Lines 400:400 [0x0000005600:0x0000005700]");
247 
248   set(LocationFive, LineFive, LineFive, 0x5800, 0x5900);
249   LocationFive->setIsAddressRange();
250   EXPECT_STREQ(LocationFive->getIntervalInfo().c_str(),
251                "{Range} Lines 500:500 [0x0000005800:0x0000005900]");
252 
253   set(LocationSix, LineSix, LineSix, 0x6000, 0x6100);
254   LocationSix->setIsAddressRange();
255   EXPECT_STREQ(LocationSix->getIntervalInfo().c_str(),
256                "{Range} Lines 600:600 [0x0000006000:0x0000006100]");
257 
258   // Add ranges to Function.
259   // Function: LocationOne, LocationTwo, LocationFive, LocationSix
260   Function->addObject(LocationOne);
261   Function->addObject(LocationTwo);
262   Function->addObject(LocationFive);
263   Function->addObject(LocationSix);
264   EXPECT_EQ(Function->rangeCount(), 4u);
265 
266   // Add ranges to NestedScope.
267   // NestedScope: LocationThree, LocationFour
268   NestedScope->addObject(LocationThree);
269   NestedScope->addObject(LocationFour);
270   EXPECT_EQ(NestedScope->rangeCount(), 2u);
271 
272   // Get all ranges.
273   LVRange Ranges;
274   CompileUnit->getRanges(Ranges);
275   Ranges.startSearch();
276   EXPECT_EQ(Ranges.getEntry(0x4000), nullptr);
277 
278   EXPECT_EQ(Ranges.getEntry(0x5060), Function);
279   EXPECT_EQ(Ranges.getEntry(0x5850), Function);
280   EXPECT_EQ(Ranges.getEntry(0x5010, 0x5090), Function);
281   EXPECT_EQ(Ranges.getEntry(0x5210, 0x5290), Function);
282   EXPECT_EQ(Ranges.getEntry(0x5810, 0x5890), Function);
283   EXPECT_EQ(Ranges.getEntry(0x6010, 0x6090), Function);
284 
285   EXPECT_EQ(Ranges.getEntry(0x5400), NestedScope);
286   EXPECT_EQ(Ranges.getEntry(0x5650), NestedScope);
287   EXPECT_EQ(Ranges.getEntry(0x5410, 0x5490), NestedScope);
288   EXPECT_EQ(Ranges.getEntry(0x5610, 0x5690), NestedScope);
289 
290   EXPECT_EQ(Ranges.getEntry(0x8000), nullptr);
291   Ranges.endSearch();
292 
293   // Add locations to symbols.
294   // Parameter:       [LineOne, LineSix]
295   // LocalVariable:   [LineTwo, LineSix], [LineFour, LineFive]
296   // NestedVariable:  [LineThree, LineFour]
297   add(Parameter, LineOne, LineSix);
298   add(LocalVariable, LineTwo, LineSix);
299   add(LocalVariable, LineFour, LineFive);
300   add(NestedVariable, LineThree, LineFour);
301 
302   LVLocation *Location;
303   LVLocations Locations;
304   Parameter->getLocations(Locations);
305   ASSERT_EQ(Locations.size(), 1u);
306   Location = Locations[0];
307   EXPECT_EQ(Location->getLowerAddress(), LineOne->getAddress());
308   EXPECT_EQ(Location->getUpperAddress(), LineSix->getAddress());
309 
310   Locations.clear();
311   LocalVariable->getLocations(Locations);
312   ASSERT_EQ(Locations.size(), 2u);
313   Location = Locations[0];
314   EXPECT_EQ(Location->getLowerAddress(), LineTwo->getAddress());
315   EXPECT_EQ(Location->getUpperAddress(), LineSix->getAddress());
316   Location = Locations[1];
317   EXPECT_EQ(Location->getLowerAddress(), LineFour->getAddress());
318   EXPECT_EQ(Location->getUpperAddress(), LineFive->getAddress());
319 
320   Locations.clear();
321   NestedVariable->getLocations(Locations);
322   ASSERT_EQ(Locations.size(), 1u);
323   Location = Locations[0];
324   EXPECT_EQ(Location->getLowerAddress(), LineThree->getAddress());
325   EXPECT_EQ(Location->getUpperAddress(), LineFour->getAddress());
326 }
327 
328 class ReaderTestCoverage : public ReaderTest {
329   // Types.
330   LVType *IntegerType = nullptr;
331 
332   // Scopes.
333   LVScopeFunction *Function = nullptr;
334   LVScopeFunctionInlined *InlinedFunction = nullptr;
335 
336   // Symbols.
337   LVSymbol *Variable = nullptr;
338   LVSymbol *Parameter = nullptr;
339 
340   // Lines.
341   LVLine *LineOne = nullptr;
342   LVLine *LineTwo = nullptr;
343   LVLine *LineThree = nullptr;
344   LVLine *LineFour = nullptr;
345   LVLine *LineFive = nullptr;
346   LVLine *LineSix = nullptr;
347 
348   // Locations.
349   LVLocation *LocationOne = nullptr;
350   LVLocation *LocationTwo = nullptr;
351   LVLocation *LocationFive = nullptr;
352   LVLocation *LocationSix = nullptr;
353 
354 public:
ReaderTestCoverage(ScopedPrinter & W)355   ReaderTestCoverage(ScopedPrinter &W) : ReaderTest(W) {}
356 
357   void createElements();
358   void addElements();
359   void initElements();
360 };
361 
362 // Create the logical elements.
createElements()363 void ReaderTestCoverage::createElements() {
364   // Create scope root.
365   Error Err = createScopes();
366   ASSERT_THAT_ERROR(std::move(Err), Succeeded());
367   Root = getScopesRoot();
368   EXPECT_NE(Root, nullptr);
369 
370   // Create the logical types.
371   IntegerType = createType();
372   EXPECT_NE(IntegerType, nullptr);
373 
374   // Create the logical scopes.
375   CompileUnit = createScopeCompileUnit();
376   EXPECT_NE(CompileUnit, nullptr);
377   Function = createScopeFunction();
378   EXPECT_NE(Function, nullptr);
379   InlinedFunction = createScopeFunctionInlined();
380   EXPECT_NE(InlinedFunction, nullptr);
381 
382   // Create the logical symbols.
383   Variable = createSymbol();
384   EXPECT_NE(Variable, nullptr);
385   Parameter = createSymbol();
386   EXPECT_NE(Parameter, nullptr);
387 
388   // Create the logical lines.
389   LineOne = createLine();
390   EXPECT_NE(LineOne, nullptr);
391   LineTwo = createLine();
392   EXPECT_NE(LineTwo, nullptr);
393   LineThree = createLine();
394   EXPECT_NE(LineThree, nullptr);
395   LineFour = createLine();
396   EXPECT_NE(LineFour, nullptr);
397   LineFive = createLine();
398   EXPECT_NE(LineFive, nullptr);
399   LineSix = createLine();
400   EXPECT_NE(LineSix, nullptr);
401 
402   // Create the logical locations.
403   LocationOne = createLocation();
404   EXPECT_NE(LocationOne, nullptr);
405   LocationTwo = createLocation();
406   EXPECT_NE(LocationTwo, nullptr);
407   LocationFive = createLocation();
408   EXPECT_NE(LocationFive, nullptr);
409   LocationSix = createLocation();
410   EXPECT_NE(LocationSix, nullptr);
411 }
412 
413 // Create the logical view adding the created logical elements.
addElements()414 void ReaderTestCoverage::addElements() {
415   setCompileUnit(CompileUnit);
416 
417   // Root
418   //   CompileUnit
419   //     IntegerType
420   //     Function
421   //       Ranges
422   //         [LineOne, LineOne]
423   //         [LineTwo, LineSix]
424   //         [LineSix, LineSix]
425   //       LineOne
426   //       LineTwo
427   //       InlinedFunction
428   //         Ranges
429   //           [LineFive, LineFive]
430   //         Parameter
431   //           Location
432   //             [LineThree, LineThree]
433   //         Variable
434   //           Location
435   //             [LineFour, LineFive]
436   //             [LineFive, LineSix]
437   //         LineThree
438   //         LineFour
439   //         LineFive
440   //       LineSix
441 
442   // Add elements to Root.
443   add(Root, CompileUnit);
444 
445   // Add elements to CompileUnit.
446   add(CompileUnit, IntegerType);
447   add(CompileUnit, Function);
448 
449   // Add elements to Function.
450   add(Function, InlinedFunction);
451   add(Function, LineOne);
452   add(Function, LineTwo);
453   add(Function, LineSix);
454 
455   // Add elements to function InlinedFunction.
456   add(InlinedFunction, Parameter);
457   add(InlinedFunction, Variable);
458   add(InlinedFunction, LineThree);
459   add(InlinedFunction, LineFour);
460   add(InlinedFunction, LineFive);
461 }
462 
463 // Set initial values to logical elements.
initElements()464 void ReaderTestCoverage::initElements() {
465   // Types.
466   set(IntegerType, "int", 0x1000);
467 
468   // Scopes.
469   set(CompileUnit, "foo.cpp", 0x2000);
470   set(Function, "foo", 0x2500, 100, IntegerType);
471   set(InlinedFunction, "InlinedFunction", 0x3000, 300);
472 
473   // Symbols.
474   set(Parameter, "Parameter", 0x3100, 310, IntegerType);
475   set(Variable, "Variable", 0x3200, 320, IntegerType);
476 
477   // Lines.
478   set(LineOne, "", 0x5000, 100);
479   set(LineTwo, "", 0x5200, 200);
480   set(LineThree, "", 0x5400, 300);
481   set(LineFour, "", 0x5600, 400);
482   set(LineFive, "", 0x5800, 500);
483   set(LineSix, "", 0x6000, 600);
484 
485   // Locations.
486   set(LocationOne, LineOne, LineOne, 0x5000, 0x5199);
487   EXPECT_STREQ(LocationOne->getIntervalInfo().c_str(),
488                " Lines 100:100 [0x0000005000:0x0000005199]");
489 
490   set(LocationTwo, LineTwo, LineSix, 0x5200, 0x6100);
491   EXPECT_STREQ(LocationTwo->getIntervalInfo().c_str(),
492                " Lines 200:600 [0x0000005200:0x0000006100]");
493 
494   set(LocationFive, LineFive, LineFive, 0x5800, 0x5900);
495   EXPECT_STREQ(LocationFive->getIntervalInfo().c_str(),
496                " Lines 500:500 [0x0000005800:0x0000005900]");
497 
498   set(LocationSix, LineSix, LineSix, 0x6000, 0x6100);
499   EXPECT_STREQ(LocationSix->getIntervalInfo().c_str(),
500                " Lines 600:600 [0x0000006000:0x0000006100]");
501 
502   // Add ranges to Function.
503   // Function: LocationOne, LocationTwo, LocationSix
504   Function->addObject(LocationOne);
505   Function->addObject(LocationTwo);
506   Function->addObject(LocationSix);
507   EXPECT_EQ(Function->rangeCount(), 3u);
508 
509   // Add ranges to Inlined.
510   // Inlined: LocationFive
511   InlinedFunction->addObject(LocationFive);
512   EXPECT_EQ(InlinedFunction->rangeCount(), 1u);
513 
514   // Add locations to symbols.
515   // Parameter: [LineThree, LineThree]
516   // Variable:  [LineFour, LineFive], [LineFive, LineSix]
517   add(Parameter, LineThree, LineThree);
518   add(Variable, LineFour, LineFive);
519   add(Variable, LineFive, LineSix);
520 
521   CompileUnit->processRangeLocationCoverage();
522 
523   LVLocation *Location;
524   LVLocations Locations;
525   Parameter->getLocations(Locations);
526   ASSERT_EQ(Locations.size(), 1u);
527   Location = Locations[0];
528   EXPECT_EQ(Location->getLowerAddress(), LineThree->getAddress());
529   EXPECT_EQ(Location->getUpperAddress(), LineThree->getAddress());
530 
531   Locations.clear();
532   Variable->getLocations(Locations);
533   ASSERT_EQ(Locations.size(), 2u);
534   Location = Locations[0];
535   EXPECT_EQ(Location->getLowerAddress(), LineFour->getAddress());
536   EXPECT_EQ(Location->getUpperAddress(), LineFive->getAddress());
537   Location = Locations[1];
538   EXPECT_EQ(Location->getLowerAddress(), LineFive->getAddress());
539   EXPECT_EQ(Location->getUpperAddress(), LineSix->getAddress());
540 
541   // Test the changes done to 'LVScope::outermostParent' to use the
542   // ranges allocated int the current scope during the scopes traversal.
543   // These are the pre-conditions for the symbol:
544   // - Its parent must be an inlined function.
545   // - Have more than one location description.
546 
547   // Before the changes: Parameter: CoveragePercentage = 100.00
548   // After the changes:  Parameter: CoveragePercentage = 100.00
549   EXPECT_FLOAT_EQ(Parameter->getCoveragePercentage(), 100.00f);
550 
551   // Before the changes: Variable: CoveragePercentage = 1000.00
552   // After the changes:  Variable: CoveragePercentage = 56.83
553   EXPECT_FLOAT_EQ(Variable->getCoveragePercentage(), 56.83f);
554 }
555 
TEST(LogicalViewTest,LocationRanges)556 TEST(LogicalViewTest, LocationRanges) {
557   ScopedPrinter W(outs());
558   ReaderTestLocations Reader(W);
559 
560   // Reader options.
561   LVOptions ReaderOptions;
562   ReaderOptions.setAttributeOffset();
563   ReaderOptions.setPrintAll();
564   ReaderOptions.resolveDependencies();
565   options().setOptions(&ReaderOptions);
566 
567   Reader.createElements();
568   Reader.addElements();
569   Reader.initElements();
570 }
571 
TEST(LogicalViewTest,LocationCoverage)572 TEST(LogicalViewTest, LocationCoverage) {
573   ScopedPrinter W(outs());
574   ReaderTestCoverage Reader(W);
575 
576   // Reader options.
577   LVOptions ReaderOptions;
578   ReaderOptions.setAttributeOffset();
579   ReaderOptions.setAttributeRange();
580   ReaderOptions.setAttributeLocation();
581   ReaderOptions.setPrintAll();
582   ReaderOptions.resolveDependencies();
583   options().setOptions(&ReaderOptions);
584 
585   Reader.createElements();
586   Reader.addElements();
587   Reader.initElements();
588 }
589 
590 } // namespace
591