OLD | NEW |
(Empty) | |
| 1 //===- NaClObjDumpStream.h --------------------------------------*- C++ -*-===// |
| 2 // Models an objdump stream (bitcode records/assembly code). |
| 3 // |
| 4 // The LLVM Compiler Infrastructure |
| 5 // |
| 6 // This file is distributed under the University of Illinois Open Source |
| 7 // License. See LICENSE.TXT for details. |
| 8 // |
| 9 //===----------------------------------------------------------------------===// |
| 10 |
| 11 #ifndef LLVM_BITCODE_NACL_NACLOBJDUMPSTREAM_H |
| 12 #define LLVM_BITCODE_NACL_NACLOBJDUMPSTREAM_H |
| 13 |
| 14 #include "llvm/ADT/STLExtras.h" |
| 15 #include "llvm/Bitcode/NaCl/NaClBitcodeParser.h" |
| 16 #include "llvm/Support/raw_ostream.h" |
| 17 #include <vector> |
| 18 #include <algorithm> |
| 19 |
| 20 namespace llvm { |
| 21 namespace naclbitc { |
| 22 |
| 23 // The default string assumed for a tab. |
| 24 static const char *DefaultTab = " "; |
| 25 |
| 26 /// Class that implements text indenting for pretty printing text. |
| 27 class TextIndenter { |
| 28 public: |
| 29 /// Creates a text indenter that indents using the given tab. |
| 30 TextIndenter(const char* Tab = DefaultTab) |
| 31 : Indent(""), |
| 32 Tab(Tab), |
| 33 TabSize(strlen(Tab)), |
| 34 NumTabs(0) { |
| 35 Values.push_back(Indent); |
| 36 } |
| 37 |
| 38 virtual ~TextIndenter() {} |
| 39 |
| 40 /// Returns the current indentation to use. |
| 41 const std::string &GetIndent() const { |
| 42 return Indent; |
| 43 } |
| 44 |
| 45 /// Returns the indent with the given number of tabs. |
| 46 const std::string &GetIndent(unsigned Count) { |
| 47 if (Count >= Values.size()) { |
| 48 // Indents not yet generated, fill in cache to size needed. |
| 49 std::string Results; |
| 50 if (Values.size() > 0) Results = Values.back(); |
| 51 for (size_t i = Values.size(); i <= Count; ++i) { |
| 52 Results += Tab; |
| 53 Values.push_back(Results); |
| 54 } |
| 55 } |
| 56 return Values[Count]; |
| 57 } |
| 58 |
| 59 /// Increments the current indentation by one tab. |
| 60 void Inc() { |
| 61 ++NumTabs; |
| 62 if (NumTabs < Values.size()) { |
| 63 Indent = Values[NumTabs]; |
| 64 } else { |
| 65 Indent += Tab; |
| 66 Values.push_back(Indent); |
| 67 } |
| 68 } |
| 69 |
| 70 /// Decrements the current indentation by one tab. |
| 71 void Dec() { |
| 72 // Be sure not to underflow! |
| 73 if (NumTabs) { |
| 74 --NumTabs; |
| 75 Indent = Values[NumTabs]; |
| 76 } |
| 77 } |
| 78 |
| 79 /// Returns the current number of tabs in the current indentation. |
| 80 unsigned GetNumTabs() const { |
| 81 return NumTabs; |
| 82 } |
| 83 |
| 84 const char *GetTab() const { |
| 85 return Tab; |
| 86 } |
| 87 |
| 88 size_t GetTabSize() const { |
| 89 return TabSize; |
| 90 } |
| 91 |
| 92 private: |
| 93 // The current indentation to use. |
| 94 std::string Indent; |
| 95 // The set of (previously computed) identations, based on the number |
| 96 // of tabs. |
| 97 std::vector<std::string> Values; |
| 98 // The text defining a tab. |
| 99 const char *Tab; |
| 100 // The size of the tab. |
| 101 size_t TabSize; |
| 102 // The number of tabs currently being used. |
| 103 unsigned NumTabs; |
| 104 }; |
| 105 |
| 106 class TextFormatter; |
| 107 |
| 108 /// This template class maintains a simply pool of directives for |
| 109 /// a text formatter. Assumes that all elements in pool are associated |
| 110 /// with the same formatter. |
| 111 template<class Directive> |
| 112 class DirectiveMemoryPool { |
| 113 public: |
| 114 DirectiveMemoryPool() {} |
| 115 |
| 116 ~DirectiveMemoryPool() { |
| 117 DeleteContainerPointers(FreeList); |
| 118 } |
| 119 |
| 120 Directive *Allocate(TextFormatter *Fmtr) { |
| 121 if (FreeList.empty()) return new Directive(Fmtr); |
| 122 Directive *Element = FreeList.back(); |
| 123 assert(&Element->GetFormatter() == Fmtr |
| 124 && "Directive memory pool formatter mismatch"); |
| 125 FreeList.pop_back(); |
| 126 return Element; |
| 127 } |
| 128 |
| 129 void Free(Directive *Dir) { |
| 130 FreeList.push_back(Dir); |
| 131 } |
| 132 |
| 133 private: |
| 134 std::vector<Directive*> FreeList; |
| 135 }; |
| 136 |
| 137 /// This class defines a simple formatter for a stream that consists |
| 138 /// of a sequence of instructions. In general, this class assumes that |
| 139 /// instructions are a single line. In addition, some instructions |
| 140 /// define a block around a sequence of instructions. Each block of |
| 141 /// instructions is indented to clarify the block structure over that |
| 142 /// set of instructions. |
| 143 /// |
| 144 /// To handle line indentation of blocks, this class inherits class |
| 145 /// TextIndenter. The TextIndenter controls how blocks of lines are |
| 146 /// indented. At the beginning of a block, the user should call method |
| 147 /// Inc. It should then write out the sequence of instructions to be |
| 148 /// indented. Then, after the last indented instruction of the block |
| 149 /// is printed, the user should call method Dec. Nested blocks are |
| 150 /// handled by nesting methods Inc and Dec appropriately. |
| 151 /// |
| 152 /// This class mainly focuses on the tools needed to format an |
| 153 /// instruction, given a specified viewing width. The issue is that |
| 154 /// while instructions should be on a single line, some instructions |
| 155 /// are too wide to fit into the viewing width. Hence, we need a way |
| 156 /// to deal with line overflow. |
| 157 /// |
| 158 /// The way this class handles the line overflow problem is to |
| 159 /// basically force the user to break up the output into a sequence of |
| 160 /// tokens. This is done using two streams. The text stream is used to |
| 161 /// buffer tokens. The base stream is the stream to write tokens to |
| 162 /// once they have been identified and positioned. The goal of the |
| 163 /// formatter is to decide where the instruction text should be cut |
| 164 /// (i.e. between tokens), so that the instruction does not overflow |
| 165 /// the viewing width. It also handles the automatic insertion of line |
| 166 /// indentation into the base stream when needed. |
| 167 /// |
| 168 /// To make it easy to print tokens to the text stream, we use text |
| 169 /// directives. Whenever a text directive is written to the text |
| 170 /// stream, it is assumed that all text written to the text stream |
| 171 /// (since the last directive) is an (indivisible) token. The first |
| 172 /// thing directives do is move the token from the text stream (if |
| 173 /// present) to the base stream. |
| 174 /// |
| 175 /// In addition to defining tokens, text directives can also be |
| 176 /// defined to query the formatter state and apply an appropriate |
| 177 /// action. An example of this is the space text directive. It only |
| 178 /// adds a space if the formatter isn't at the beginning of a new line |
| 179 /// (since a newline can act as whitespace). |
| 180 /// |
| 181 /// The text formatter also has a notion of clustering |
| 182 /// tokens. Clustering forces a consecutive sequence of tokens to |
| 183 /// be treated as a single token, when deciding where to wrap long |
| 184 /// lines. In particular, clustered tokens will not be broken up |
| 185 /// unless there is no other way to print them, because the cluster is |
| 186 /// larger than what can fit in a line. |
| 187 /// |
| 188 /// Clustering is implemented using two passes. In the first pass, the |
| 189 /// sequence of tokens/directives are collected to find the clustered |
| 190 /// text. They are also applied to collect any text internal to the |
| 191 /// directives. Actions that can change (intraline) indenting are |
| 192 /// turned off. |
| 193 /// |
| 194 /// Once the first pass is done, the second pass starts. It begins |
| 195 /// with a check to see if the clustered text can fit on the current |
| 196 /// line, and adds a newline if necessary. Then it replays the |
| 197 /// directives to put the tokens of the cluster into the base stream. |
| 198 /// The replay also changes (intraline) indenting as necessary. |
| 199 /// |
| 200 /// Clusters can be nested. In such cases, they are stripped one layer |
| 201 /// per pass. Nested clusters are replayed after line wrapping of |
| 202 /// outer clusters have been resolved. |
| 203 class TextFormatter : public TextIndenter { |
| 204 public: |
| 205 |
| 206 /// Creates a text formatter to print instructions onto the given |
| 207 /// Base Stream. The viewing width is defined by LineWidth. The |
| 208 /// given tab is the assumed value for tab characters and line |
| 209 /// indents. |
| 210 explicit TextFormatter(raw_ostream &BaseStream, |
| 211 unsigned LineWidth = 80, |
| 212 const char *Tab = DefaultTab); |
| 213 |
| 214 ~TextFormatter() override; |
| 215 |
| 216 /// Returns the user-level text stream of the formatter that tokens |
| 217 /// should be written to. |
| 218 raw_ostream &Tokens() { |
| 219 return TextStream; |
| 220 } |
| 221 |
| 222 /// Changes the line width to the given value. |
| 223 void SetLineWidth(unsigned NewLineWidth) { |
| 224 LineWidth = NewLineWidth; |
| 225 if (MinLineWidth > LineWidth) MinLineWidth = LineWidth; |
| 226 } |
| 227 |
| 228 // Changes the (default) line-wrap, continuation indent. |
| 229 void SetContinuationIndent(const std::string &Indent) { |
| 230 ContinuationIndent = Indent; |
| 231 } |
| 232 |
| 233 /// Base class for all directives. The basic functionality is that it |
| 234 /// has a reference to the text formatter, and is applied by calling |
| 235 /// method apply. This method apply is encorporated into the |
| 236 /// stream operator<<, so that they can be used as part of the |
| 237 /// streamed output. |
| 238 /// |
| 239 /// Method apply extracts any tokens in the text stream. Moves them |
| 240 /// into the base stream. Finally, it calls virtual method MyApply |
| 241 /// to do the actions of the directive. |
| 242 class Directive { |
| 243 Directive(const Directive&) LLVM_DELETED_FUNCTION; |
| 244 void operator=(const Directive&) LLVM_DELETED_FUNCTION; |
| 245 public: |
| 246 /// Creates a directive for the given stream. |
| 247 explicit Directive(TextFormatter *Formatter) |
| 248 : Formatter(Formatter) {} |
| 249 |
| 250 virtual ~Directive() {} |
| 251 |
| 252 /// Returns the formatter associated with the directive. |
| 253 TextFormatter &GetFormatter() const { |
| 254 return *Formatter; |
| 255 } |
| 256 |
| 257 /// Does action of directive. |
| 258 void Apply() const { |
| 259 // Start by writing token if Tokens() buffer (if non-empty). |
| 260 Formatter->WriteToken(); |
| 261 // Apply the directive. |
| 262 MyApply(false); |
| 263 // Save the directive for replay if we are clustering. |
| 264 MaybeSaveForReplay(); |
| 265 } |
| 266 |
| 267 protected: |
| 268 // The formatter associated with the directive. |
| 269 TextFormatter *Formatter; |
| 270 |
| 271 // Like Apply, but called instead of Apply whey doing a replay. |
| 272 void Reapply() const; |
| 273 |
| 274 // Does directive specific action. Replay is true only if the |
| 275 // directive was in a cluster, and it is being called to replay |
| 276 // the directive a second time. |
| 277 virtual void MyApply(bool Replay) const = 0; |
| 278 |
| 279 // Adds the directive to the clustered directives if appropriate |
| 280 // (i.e. inside a cluster). |
| 281 virtual void MaybeSaveForReplay() const { |
| 282 if (IsClustering()) AppendForReplay(this); |
| 283 } |
| 284 |
| 285 // *********************************************************** |
| 286 // Note: The following have been added so that derived classes |
| 287 // have public access to protected text formatter methods. |
| 288 // (Otherwise, you get a compiler error that they are protected |
| 289 // in derived classes). |
| 290 // *********************************************************** |
| 291 |
| 292 bool IsClustering() const { |
| 293 return Formatter->IsClustering(); |
| 294 } |
| 295 |
| 296 unsigned GetClusteringLevel() const { |
| 297 return Formatter->GetClusteringLevel(); |
| 298 } |
| 299 |
| 300 void AppendForReplay(const Directive *D) const { |
| 301 Formatter->AppendForReplay(D); |
| 302 } |
| 303 |
| 304 raw_ostream &Tokens() const { |
| 305 return Formatter->Tokens(); |
| 306 } |
| 307 |
| 308 void WriteToken(const std::string &Token) const { |
| 309 Formatter->WriteToken(Token); |
| 310 } |
| 311 |
| 312 void WriteEndline() const { |
| 313 Formatter->WriteEndline(); |
| 314 } |
| 315 |
| 316 void PopIndent() const { |
| 317 Formatter->PopIndent(); |
| 318 } |
| 319 |
| 320 void PushIndent() const { |
| 321 Formatter->PushIndent(); |
| 322 } |
| 323 |
| 324 bool AddLineWrapIfNeeded(unsigned TextSize) const { |
| 325 return Formatter->AddLineWrapIfNeeded(TextSize); |
| 326 } |
| 327 |
| 328 void StartClustering() const { |
| 329 Formatter->StartClustering(); |
| 330 } |
| 331 |
| 332 void FinishClustering() const { |
| 333 Formatter->FinishClustering(); |
| 334 } |
| 335 }; |
| 336 |
| 337 protected: |
| 338 // The base stream to send formatted text to. |
| 339 raw_ostream &BaseStream; |
| 340 // Buffer that holds token text. |
| 341 std::string TextBuffer; |
| 342 // The user-level stream for (token) text and directives. |
| 343 raw_string_ostream TextStream; |
| 344 // The buffered token waiting to be flushed to the base stream. |
| 345 // std::string BufferedToken; |
| 346 // The expected line width the formatter should try and match. |
| 347 unsigned LineWidth; |
| 348 // The current position (i.e. column of previous character on line) |
| 349 // associated with the current line in the base stream. |
| 350 unsigned LinePosition; |
| 351 // The stack of (intraline) indents added by PushIndent. |
| 352 std::vector<unsigned> IntralineIndents; |
| 353 // The current intraline indent to use. |
| 354 unsigned CurrentIndent; |
| 355 // The minimum line width. Used to limit indents so that there |
| 356 // will always be at least this amount of space on the line. |
| 357 unsigned MinLineWidth; |
| 358 // True if no characters have moved to the base stream for the |
| 359 // instruction being printed. Note: This is different than |
| 360 // LinePosition == 0. The latter can be true, when |
| 361 // AtInstructionBeginning is false, if the current line is a |
| 362 // continuation line caused by line overflow. |
| 363 bool AtInstructionBeginning; |
| 364 // The indent string to use for indenting each line of the instruction. |
| 365 std::string LineIndent; |
| 366 // The indent to add on continuation (i.e. overflow) lines for an |
| 367 // instruction. |
| 368 std::string ContinuationIndent; |
| 369 // Counts how nested we are within clustering directives. |
| 370 unsigned ClusteringLevel; |
| 371 // Contains the number of columns needed to hold the generated text, |
| 372 // while clustering. Computed so that we can test if it fits on the |
| 373 // current line. |
| 374 unsigned ClusteredTextSize; |
| 375 // Contains the sequence of directives (including tokens) during |
| 376 // clustering, so that it can be replayed after we determine if a |
| 377 // new line needs to be added. |
| 378 std::vector<const Directive*> ClusteredDirectives; |
| 379 |
| 380 // Returns if we are currently inside a cluster. |
| 381 bool IsClustering() const { |
| 382 return ClusteringLevel > 0; |
| 383 } |
| 384 |
| 385 // Returns the clustering level of the formatter. |
| 386 unsigned GetClusteringLevel() const { |
| 387 return ClusteringLevel; |
| 388 } |
| 389 |
| 390 // Appends the given directive to the list of directives to |
| 391 // replay, if clustering. |
| 392 void AppendForReplay(const Directive *D) { |
| 393 ClusteredDirectives.push_back(D); |
| 394 } |
| 395 |
| 396 /// Writes out the token in the text stream. If necessary, moves to |
| 397 // a new line first. |
| 398 void WriteToken() { |
| 399 WriteToken(GetToken()); |
| 400 } |
| 401 |
| 402 /// Writes out the given token. If necessary, moves to a new line first. |
| 403 void WriteToken(const std::string &Token) { |
| 404 if (Token.empty()) return; |
| 405 AddLineWrapIfNeeded(Token.size()); |
| 406 Write(Token); |
| 407 } |
| 408 |
| 409 // Extracts the text that has been added to the text stream, and |
| 410 // returns it. |
| 411 std::string GetToken(); |
| 412 |
| 413 /// Writes out a non-newline character to the base stream. |
| 414 void Write(char ch); |
| 415 |
| 416 /// Writes out a string. |
| 417 void Write(const std::string &Text); |
| 418 |
| 419 /// Starts a new cluster of tokens. |
| 420 /// Note: We do not allow nested clusterings. |
| 421 void StartClustering(); |
| 422 |
| 423 /// Ends the existing cluster of tokens. |
| 424 void FinishClustering(); |
| 425 |
| 426 /// Adds a newline that ends the current instruction being printed. |
| 427 void WriteEndline(); |
| 428 |
| 429 /// Called just before the first character on a line is printed, to |
| 430 /// add indentation text for the line. |
| 431 virtual void WriteLineIndents(); |
| 432 |
| 433 /// Analyzes the formatter state to determine if a token of the |
| 434 /// given TextSize can fit on the current line. If it can't fit, |
| 435 /// it wraps the input line. Returns true only if line wrap was |
| 436 /// added by this method. |
| 437 bool AddLineWrapIfNeeded(unsigned TextSize) { |
| 438 if (IsClustering()) { |
| 439 // Don't consider line wrapping until all text is clustered. That |
| 440 // way we have full information on what we should do. |
| 441 return false; |
| 442 } else { |
| 443 // If the text fits on the current line, there is nothing to do. |
| 444 // Otherwise, we should add a newline, unless we are already |
| 445 // at the new line. If we are already at the newline, we can't |
| 446 // split up the token, so just allow line overflow. |
| 447 if (LinePosition + TextSize <= LineWidth |
| 448 || LinePosition == 0) |
| 449 return false; |
| 450 // If reached, it must not fit, so add a line wrap. |
| 451 Write('\n'); |
| 452 return true; |
| 453 } |
| 454 } |
| 455 |
| 456 /// Pops the current (intraline) indentation and restores it to the |
| 457 /// previous indentation. Used to restore the indentation of |
| 458 /// parenthesized subexpressions, where this should be called on the |
| 459 /// close parenthesis. |
| 460 void PopIndent() { |
| 461 // Be pragmatic. If there is underflow, assume that it was due to |
| 462 // the fact that the caller of this text formatter used a close |
| 463 // directive for a pair of matching parenthesis that crossed |
| 464 // multiple (i.e. instruction) lines. |
| 465 if (IsClustering() || IntralineIndents.empty()) return; |
| 466 CurrentIndent = IntralineIndents.back(); |
| 467 IntralineIndents.pop_back(); |
| 468 } |
| 469 |
| 470 /// Pushes the current (intraline) indentation to match the current |
| 471 /// position within the line. Used to indent parenthesized |
| 472 /// subexpressions, where this should be called on the open |
| 473 /// parenthesis. |
| 474 void PushIndent() { |
| 475 if (IsClustering()) return; |
| 476 IntralineIndents.push_back(CurrentIndent); |
| 477 CurrentIndent = FixIndentValue(LinePosition); |
| 478 } |
| 479 |
| 480 /// Fixes the given position, to the appropriate value for setting |
| 481 /// CurrentIndent. That is, it makes sure there is always MinLineWidth |
| 482 /// printable characters on a line. |
| 483 unsigned FixIndentValue(unsigned Position) { |
| 484 return std::min(Position, LineWidth - MinLineWidth); |
| 485 } |
| 486 |
| 487 private: |
| 488 /// Directive that generates temporary instances to hold tokens from |
| 489 /// the Tokens() stream. Generated when GetToken() is called. Used |
| 490 /// during clustering to regenerate the corresponding extracted |
| 491 /// tokens during a replay. |
| 492 class GetTokenDirective : public Directive { |
| 493 friend class DirectiveMemoryPool<GetTokenDirective>; |
| 494 GetTokenDirective(TextFormatter *Formatter) |
| 495 : Directive(Formatter) {} |
| 496 |
| 497 public: |
| 498 ~GetTokenDirective() override {} |
| 499 |
| 500 /// Allocates an instance of a GetTokenDirective. |
| 501 /// Note: Will be reclaimed when MyApply is called. |
| 502 static Directive *Allocate(TextFormatter *Formatter, |
| 503 const std::string &Text); |
| 504 |
| 505 protected: |
| 506 void MyApply(bool Replay) const override { |
| 507 WriteToken(Text); |
| 508 if (!IsClustering()) |
| 509 Formatter->GetTokenFreeList.Free(const_cast<GetTokenDirective*>(this)); |
| 510 } |
| 511 |
| 512 private: |
| 513 // The token text. |
| 514 std::string Text; |
| 515 }; |
| 516 |
| 517 // The set of freed GetTokenDirectives, that can be reused. |
| 518 DirectiveMemoryPool<GetTokenDirective> GetTokenFreeList; |
| 519 }; |
| 520 |
| 521 inline raw_ostream &operator<<(raw_ostream &Stream, |
| 522 const TextFormatter::Directive &Directive) { |
| 523 // Be sure that the directive is defined for the given stream, |
| 524 // before applying the directive, since directives may have |
| 525 // different meanings on different text streams. |
| 526 assert(&Stream == &Directive.GetFormatter().Tokens()); |
| 527 Directive.Apply(); |
| 528 return Stream; |
| 529 } |
| 530 |
| 531 /// Defines a directive that only tokenizes the text in the Tokens() |
| 532 /// stream. |
| 533 class TokenizeTextDirective : public TextFormatter::Directive { |
| 534 public: |
| 535 explicit TokenizeTextDirective(TextFormatter *Formatter) |
| 536 : TextFormatter::Directive(Formatter) {} |
| 537 |
| 538 ~TokenizeTextDirective() override {} |
| 539 |
| 540 protected: |
| 541 void MyApply(bool Replay) const override {} |
| 542 }; |
| 543 |
| 544 /// Defines a token which doesn't need whitespace on either side of |
| 545 /// the token to be a valid token (such as punctuation). |
| 546 class TokenTextDirective : public TextFormatter::Directive { |
| 547 public: |
| 548 TokenTextDirective(TextFormatter *Formatter, const std::string &Str) |
| 549 : TextFormatter::Directive(Formatter), Text(Str) { |
| 550 } |
| 551 |
| 552 ~TokenTextDirective() override {} |
| 553 |
| 554 protected: |
| 555 void MyApply(bool Replay) const override { |
| 556 WriteToken(Text); |
| 557 } |
| 558 |
| 559 private: |
| 560 std::string Text; |
| 561 }; |
| 562 |
| 563 /// Writes out the current token. Then adds a space if the base |
| 564 /// stream is not at the beginning of a continuation line. |
| 565 class SpaceTextDirective : public TextFormatter::Directive { |
| 566 public: |
| 567 SpaceTextDirective(TextFormatter *Formatter, const std::string &Space) |
| 568 : TextFormatter::Directive(Formatter), Space(Space) {} |
| 569 |
| 570 explicit SpaceTextDirective(TextFormatter *Formatter) |
| 571 : TextFormatter::Directive(Formatter), Space(" ") {} |
| 572 |
| 573 ~SpaceTextDirective() {} |
| 574 |
| 575 protected: |
| 576 void MyApply(bool Replay) const override { |
| 577 if (!AddLineWrapIfNeeded(Space.size())) |
| 578 WriteToken(Space); |
| 579 } |
| 580 private: |
| 581 std::string Space; |
| 582 }; |
| 583 |
| 584 /// Adds a newline that ends the current instruction being printed. |
| 585 class EndlineTextDirective : public TextFormatter::Directive { |
| 586 public: |
| 587 explicit EndlineTextDirective(TextFormatter *Formatter) |
| 588 : TextFormatter::Directive(Formatter) {} |
| 589 |
| 590 ~EndlineTextDirective() override {} |
| 591 |
| 592 protected: |
| 593 void MyApply(bool Replay) const override { |
| 594 WriteEndline(); |
| 595 } |
| 596 }; |
| 597 |
| 598 /// Inserts a token and then pushes the current indent to the position |
| 599 /// after the token. Used to model a open parenthesis. |
| 600 class OpenTextDirective : public TokenTextDirective { |
| 601 public: |
| 602 |
| 603 // Creates an open using the given indent. |
| 604 OpenTextDirective(TextFormatter *Formatter, const std::string &Text) |
| 605 : TokenTextDirective(Formatter, Text) {} |
| 606 |
| 607 ~OpenTextDirective() override {} |
| 608 |
| 609 protected: |
| 610 void MyApply(bool Replay) const override { |
| 611 TokenTextDirective::MyApply(Replay); |
| 612 PushIndent(); |
| 613 } |
| 614 }; |
| 615 |
| 616 /// Inserts a token and then pops current indent. Used to model a |
| 617 /// close parenthesis. |
| 618 class CloseTextDirective : public TokenTextDirective { |
| 619 public: |
| 620 CloseTextDirective(TextFormatter *Formatter, const std::string &Text) |
| 621 : TokenTextDirective(Formatter, Text) {} |
| 622 |
| 623 ~CloseTextDirective() override {} |
| 624 |
| 625 protected: |
| 626 void MyApply(bool Replay) const override { |
| 627 TokenTextDirective::MyApply(Replay); |
| 628 PopIndent(); |
| 629 } |
| 630 }; |
| 631 |
| 632 /// Defines the beginning of a token cluster, which should be put on the |
| 633 /// same line if possible. |
| 634 class StartClusteringDirective : public TextFormatter::Directive { |
| 635 public: |
| 636 explicit StartClusteringDirective(TextFormatter *Formatter) |
| 637 : TextFormatter::Directive(Formatter) {} |
| 638 |
| 639 ~StartClusteringDirective() override {} |
| 640 |
| 641 protected: |
| 642 void MyApply(bool Replay) const override { |
| 643 StartClustering(); |
| 644 } |
| 645 |
| 646 void MaybeSaveForReplay() const override { |
| 647 if (GetClusteringLevel() > 1) AppendForReplay(this); |
| 648 } |
| 649 }; |
| 650 |
| 651 class FinishClusteringDirective : public TextFormatter::Directive { |
| 652 public: |
| 653 explicit FinishClusteringDirective(TextFormatter *Formatter) |
| 654 : TextFormatter::Directive(Formatter) {} |
| 655 |
| 656 ~FinishClusteringDirective() override {} |
| 657 |
| 658 protected: |
| 659 void MyApply(bool Replay) const override { |
| 660 FinishClustering(); |
| 661 } |
| 662 }; |
| 663 |
| 664 class ObjDumpStream; |
| 665 |
| 666 /// Models that an abbreviation index is not specified when dumping a |
| 667 /// bitcode record. |
| 668 static int32_t ABBREV_INDEX_NOT_SPECIFIED = -1; |
| 669 |
| 670 /// The formatter used for dumping records in ObjDumpStream. |
| 671 class RecordTextFormatter : public TextFormatter { |
| 672 public: |
| 673 /// The address write width used to print the number of |
| 674 /// bytes in the record bit address, when printing records. |
| 675 static const unsigned AddressWriteWidth = 8; |
| 676 |
| 677 explicit RecordTextFormatter(ObjDumpStream *ObjDump); |
| 678 |
| 679 ~RecordTextFormatter() override {} |
| 680 |
| 681 /// Writes out the given record of values as an instruction. |
| 682 void WriteValues(uint64_t Bit, |
| 683 const llvm::NaClBitcodeValues &Values, |
| 684 int32_t AbbrevIndex = ABBREV_INDEX_NOT_SPECIFIED); |
| 685 |
| 686 /// Returns text corresponding to an empty label column. |
| 687 std::string GetEmptyLabelColumn(); |
| 688 |
| 689 // Converts the given start bit to the corresponding address to |
| 690 // print. That is, generate "Bit/8:Bit%8" value. |
| 691 static std::string RecordAddress(uint64_t Bit, unsigned MinByteWidth); |
| 692 |
| 693 // Returns the record address (when printing records) associated with |
| 694 // the given bit. |
| 695 static std::string RecordAddress(uint64_t Bit) { |
| 696 return RecordAddress(Bit, AddressWriteWidth); |
| 697 } |
| 698 |
| 699 protected: |
| 700 void WriteLineIndents() override; |
| 701 |
| 702 private: |
| 703 // The object dumper this formatter is associated with. |
| 704 ObjDumpStream *ObjDump; |
| 705 // The address label associated with the current line. |
| 706 std::string Label; |
| 707 // The open brace '<' for a record. |
| 708 OpenTextDirective OpenBrace; |
| 709 // The close brace '>' for a record. |
| 710 CloseTextDirective CloseBrace; |
| 711 // A comma between elements in a record. |
| 712 TokenTextDirective Comma; |
| 713 // A space inside a record. |
| 714 SpaceTextDirective Space; |
| 715 // End the line. |
| 716 EndlineTextDirective Endline; |
| 717 // Start clustering tokens. |
| 718 StartClusteringDirective StartCluster; |
| 719 // End clustering tokens. |
| 720 FinishClusteringDirective FinishCluster; |
| 721 }; |
| 722 |
| 723 /// Implements a stream to print out bitcode records, assembly code, |
| 724 /// comments, and errors. The general format is to print records and |
| 725 /// assembly side by side. Comments and errors (associated with the |
| 726 /// record and/or assembly code) follow each printed record. |
| 727 /// |
| 728 /// Alignment of records, assembly, comments, and errors is done by |
| 729 /// buffering assembly, comments, and errors until a write or flush |
| 730 /// occurs. Then, the various streams are stitched together to |
| 731 /// produce the corresponding output text. There are two buffers: one |
| 732 /// holds the assembly, and the other holds comments and errors. |
| 733 /// |
| 734 /// There are exactly two methods that can cause text to be added to |
| 735 /// the objdump stream. Method Flush just flushes out the assembly and |
| 736 /// comments/errors buffer without printing a record. If there is no |
| 737 /// buffered assembly/comments/errors, nothing is done. Method Write |
| 738 /// prints the given record, and also flushes out the assembly and |
| 739 /// comments/errors buffer. Hence, in general, comments and errors |
| 740 /// follow the record/assembly. However, if you want them to appear |
| 741 /// before, use method Flush. |
| 742 /// |
| 743 /// The constructor is defined with two flags: DumpRecords and |
| 744 /// DumpAssembly. Comments and errors are flushed on every write, |
| 745 /// independent of these flags. Records are printed out only if |
| 746 /// DumpRecords is true. Assembly is flushed only if DumpAssembly is |
| 747 /// true. |
| 748 /// |
| 749 /// To buffer assembly, call method Assembly to get a (string) stream |
| 750 /// to buffer the assembly code. To buffer comments, call method |
| 751 /// Comments() to get a (string) stream to buffer the comments. |
| 752 /// |
| 753 /// To buffer an error, call method Error. This method will increment |
| 754 /// the error count, and return the comments stream after writing |
| 755 /// "Error(byte:bit): ". |
| 756 /// |
| 757 /// If a single line of text is buffered into the assembly stream, no |
| 758 /// new line is needed. The corresponding call to Write will |
| 759 /// automatically insert the newline for you, if you did not add |
| 760 /// it. If multiple lines are to be buffered into the assembly stream, |
| 761 /// each line must be separated with a newline character. It is |
| 762 /// always safe to end all assembly lines with a newline character. |
| 763 /// |
| 764 /// Also note that this class takes care of formatting records to fit |
| 765 /// into a calculated record width (based on value set to |
| 766 /// RecordWidth). On the other hand, we assume that the assembly is |
| 767 /// formatted by the caller (i.e. owner of this object). |
| 768 class ObjDumpStream { |
| 769 ObjDumpStream(const ObjDumpStream&) LLVM_DELETED_FUNCTION; |
| 770 void operator=(const ObjDumpStream&) LLVM_DELETED_FUNCTION; |
| 771 public: |
| 772 /// The default number of error messages that will be printed before |
| 773 /// execution is stopped due to too many errors. |
| 774 static unsigned DefaultMaxErrors; |
| 775 |
| 776 /// The default value for the column that separates records and |
| 777 /// assembly, when DumpRecords and DumpAssembly is true. |
| 778 static unsigned ComboObjDumpSeparatorColumn; |
| 779 |
| 780 /// The default value for line width when DumpRecords is true, |
| 781 /// and DumpAssembly is false. This value is typically larger |
| 782 /// than ComboObjDumpSeparatorColumn, since the entire line |
| 783 /// can be used to print records. |
| 784 static unsigned RecordObjectDumpLength; |
| 785 |
| 786 /// Creates an objdump stream which will dump records, assembly, |
| 787 /// comments and errors into a single (user proved Stream). When |
| 788 /// DumpRecords is true, the contents of records will be |
| 789 /// dumped. When DumpAssembly is true, the corresponding assembly |
| 790 /// will be printed. When both are true, the records and assembly |
| 791 /// will be printed side by side. When both are false, only comments |
| 792 /// and errors will be printed. |
| 793 ObjDumpStream(raw_ostream &Stream, bool DumpRecords, bool DumpAssembly); |
| 794 |
| 795 ~ObjDumpStream() { Flush(); } |
| 796 |
| 797 /// Returns stream to buffer assembly that will be printed during the |
| 798 /// next write call. |
| 799 raw_ostream &Assembly() { |
| 800 return AssemblyStream; |
| 801 } |
| 802 |
| 803 /// Returns stream to buffer records that will be printed during the |
| 804 /// next write call. |
| 805 raw_ostream &Records() { |
| 806 return RecordStream; |
| 807 } |
| 808 |
| 809 /// Returns stream to buffer messages that will be printed during the |
| 810 // next write call. |
| 811 raw_ostream &Comments() { |
| 812 return MessageStream; |
| 813 } |
| 814 |
| 815 /// Prints "Warning(Bit/8:Bit%8): " onto the comments stream, and |
| 816 /// then returns the comments stream. In general, warnings will be |
| 817 /// printed after the next record, unless a call to Flush is made. |
| 818 raw_ostream &Warning() { |
| 819 return Warning(LastKnownBit); |
| 820 } |
| 821 |
| 822 /// Prints "Warning(Bit/8:Bit%8): " onto the comments stream, and |
| 823 /// then returns the comments stream. In general, warnings will be |
| 824 /// printed after the next record, unless a call to Flush is made. |
| 825 raw_ostream &Warning(uint64_t Bit) { |
| 826 LastKnownBit = Bit; |
| 827 return PrintMessagePrefix("Warning", Bit); |
| 828 } |
| 829 |
| 830 /// Prints "Error(Bit/8:Bit%8): " onto the comments stream, records |
| 831 /// that an error has occurred, and then returns the comments |
| 832 /// stream. In general errors will be printed after the next record, |
| 833 /// unless a call to Flush is made. |
| 834 raw_ostream &Error() { |
| 835 return Error(LastKnownBit); |
| 836 } |
| 837 |
| 838 /// Prints "Error(Bit/8:Bit%8): " onto the comments stream, records |
| 839 /// that an error has occurred, and then returns the comments |
| 840 /// stream. In general errors will be printed after the next record, |
| 841 /// unless a call to Flush is made. |
| 842 raw_ostream &Error(uint64_t Bit); |
| 843 |
| 844 /// Write a fatal error message to the dump stream, and then |
| 845 /// stop the executable. If any assembly, comments, or errors have |
| 846 /// been buffered, they will be printed first. |
| 847 void Fatal(const std::string &Message) { |
| 848 Fatal(LastKnownBit, Message); |
| 849 } |
| 850 |
| 851 /// Write a fatal error message to the dump stream, and then |
| 852 /// stop the executable. If any assembly, comments, or errors have |
| 853 /// been buffered, they will be printed first. Associates fatal error |
| 854 /// Message with the given Bit. |
| 855 void Fatal(uint64_t Bit, const std::string &Message); |
| 856 |
| 857 /// Write a fatal error message to the dump stream, and then |
| 858 /// stop the executable. If any assembly, comments, or errors have |
| 859 /// been buffered, they will be printed first, along with the given record. |
| 860 void Fatal(uint64_t Bit, |
| 861 const llvm::NaClBitcodeRecordData &Record, |
| 862 const std::string &Message); |
| 863 |
| 864 /// Dumps a record (at the given bit), along with all buffered assembly, |
| 865 /// comments, and errors, into the objdump stream. |
| 866 void Write(uint64_t Bit, |
| 867 const llvm::NaClBitcodeRecordData &Record, |
| 868 int32_t AbbrevIndex = ABBREV_INDEX_NOT_SPECIFIED) { |
| 869 LastKnownBit = Bit; |
| 870 NaClBitcodeValues Values(Record); |
| 871 RecordFormatter.WriteValues(Bit, Values, AbbrevIndex); |
| 872 Flush(); |
| 873 } |
| 874 |
| 875 /// Dumps the buffered assembly, comments, and errors, without any |
| 876 /// corresponding record, into the objdump stream. |
| 877 void Flush(); |
| 878 |
| 879 /// Increments the record indent by one. |
| 880 void IncRecordIndent() { |
| 881 RecordFormatter.Inc(); |
| 882 } |
| 883 |
| 884 /// Decrements the record indent by one. |
| 885 void DecRecordIndent() { |
| 886 RecordFormatter.Dec(); |
| 887 } |
| 888 |
| 889 /// Returns the record indenter being used by the objdump stream, for |
| 890 /// the purposes of querying state. |
| 891 const TextIndenter &GetRecordIndenter() { |
| 892 return RecordFormatter; |
| 893 } |
| 894 |
| 895 /// Returns the number of errors reported to the dump stream. |
| 896 unsigned GetNumErrors() const { |
| 897 return NumErrors; |
| 898 } |
| 899 |
| 900 // Returns true if dumping record. |
| 901 bool GetDumpRecords() const { |
| 902 return DumpRecords; |
| 903 } |
| 904 |
| 905 // Returns true if dumping assembly. |
| 906 bool GetDumpAssembly() const { |
| 907 return DumpAssembly; |
| 908 } |
| 909 |
| 910 /// Changes the default assumption that bit addresses start |
| 911 /// at index 0. |
| 912 void SetStartOffset(uint64_t Offset) { |
| 913 StartOffset = Offset; |
| 914 } |
| 915 |
| 916 /// Changes the maximum number of errors allowed. |
| 917 void SetMaxErrors(unsigned NewMax) { |
| 918 MaxErrors = NewMax; |
| 919 } |
| 920 |
| 921 /// Changes the width allowed for records (from the default). |
| 922 void SetRecordWidth(unsigned Width) { |
| 923 RecordWidth = Width; |
| 924 } |
| 925 |
| 926 unsigned GetRecordWidth() const { |
| 927 return RecordWidth; |
| 928 } |
| 929 |
| 930 /// Changes the column separator character to the given value. |
| 931 void SetColumnSeparator(char Separator) { |
| 932 ColumnSeparator = Separator; |
| 933 } |
| 934 |
| 935 /// Changes the internal state, to assume one is processing a record |
| 936 /// at the given bit. Used by Error() and Fatal(Message) to fill in |
| 937 /// the corresponding bit to associate with the error message. |
| 938 void SetRecordBitAddress(uint64_t Bit) { |
| 939 LastKnownBit = Bit; |
| 940 } |
| 941 |
| 942 // Converts the given start bit to the corresponding address to |
| 943 // print. That is, generate "Bit/8:Bit%8" value. |
| 944 std::string ObjDumpAddress(uint64_t Bit, unsigned MinByteWidth=1) { |
| 945 return RecordFormatter.RecordAddress(Bit + StartOffset, MinByteWidth); |
| 946 } |
| 947 |
| 948 // Returns the record address (when printing records) associated with |
| 949 // the given bit. |
| 950 std::string RecordAddress(uint64_t Bit) { |
| 951 return RecordFormatter.RecordAddress(Bit + StartOffset); |
| 952 } |
| 953 |
| 954 private: |
| 955 // The stream to dump to. |
| 956 raw_ostream &Stream; |
| 957 // True if records should be dumped to the dump stream. |
| 958 bool DumpRecords; |
| 959 // True if assembly text should be dumped to the dump stream. |
| 960 bool DumpAssembly; |
| 961 // The number of errors reported. |
| 962 unsigned NumErrors; |
| 963 // The maximum number of errors before quitting. |
| 964 unsigned MaxErrors; |
| 965 // The number of columns available to print bitcode records. |
| 966 unsigned RecordWidth; |
| 967 // The number of bits to add to the record bit address, to correct |
| 968 // the record bit address passed to the write routines. |
| 969 uint64_t StartOffset; |
| 970 // The buffer for assembly to be printed during the next write. |
| 971 std::string AssemblyBuffer; |
| 972 // The stream to buffer assembly into the assembly buffer. |
| 973 raw_string_ostream AssemblyStream; |
| 974 // The buffer for comments and errors. |
| 975 std::string MessageBuffer; |
| 976 // The stream to buffer comments and errors into the message. |
| 977 raw_string_ostream MessageStream; |
| 978 // The character used to separate records from assembly. |
| 979 char ColumnSeparator; |
| 980 // The last known bit passed to the objdump object. Used as default |
| 981 // for automatically generated errors. |
| 982 uint64_t LastKnownBit; |
| 983 /// The buffer for records to be printed to during the next write. |
| 984 std::string RecordBuffer; |
| 985 /// The stream to buffer recordds into the record buffer. |
| 986 raw_string_ostream RecordStream; |
| 987 /// The text formatter for generating records. |
| 988 RecordTextFormatter RecordFormatter; |
| 989 |
| 990 // Resets assembly and buffers. |
| 991 void ResetBuffers() { |
| 992 RecordBuffer.clear(); |
| 993 AssemblyBuffer.clear(); |
| 994 MessageBuffer.clear(); |
| 995 } |
| 996 |
| 997 // Returns the message stream with 'Label(Bit/8:Bit%8): '. |
| 998 raw_ostream &PrintMessagePrefix(const char *Label, uint64_t Bit) { |
| 999 return Comments() << Label << "(" << ObjDumpAddress(Bit) << "): "; |
| 1000 } |
| 1001 }; |
| 1002 |
| 1003 } |
| 1004 } |
| 1005 |
| 1006 #endif |
OLD | NEW |