Commit 6683a617 by Chris Mihelich Committed by Copybara-Service

Give ReturnAddresses and N<uppercase> namespaces separate stacks for clarity.

PiperOrigin-RevId: 633974603
Change-Id: I7efd0f0fadf1803aa8eacb86a18366e9a8a07df0
parent eba8db7b
...@@ -89,11 +89,12 @@ class RustSymbolParser { ...@@ -89,11 +89,12 @@ class RustSymbolParser {
// Recursive-descent parsing is a beautifully readable translation of a // Recursive-descent parsing is a beautifully readable translation of a
// grammar, but it risks stack overflow if implemented by naive recursion on // grammar, but it risks stack overflow if implemented by naive recursion on
// the C++ call stack. So we simulate recursion by goto and switch instead, // the C++ call stack. So we simulate recursion by goto and switch instead,
// keeping a bounded stack of "return addresses" in the stack_ member. // keeping a bounded stack of "return addresses" in the recursion_stack_
// member.
// //
// The callee argument is a statement label. We goto that label after // The callee argument is a statement label. We goto that label after
// saving the "return address" on stack_. The next continue statement in // saving the "return address" on recursion_stack_. The next continue
// the for loop below "returns" from this "call". // statement in the for loop below "returns" from this "call".
// //
// The caller argument names the return point. Each value of caller must // The caller argument names the return point. Each value of caller must
// appear in only one ABSL_DEMANGLER_RECURSE call and be listed in the // appear in only one ABSL_DEMANGLER_RECURSE call and be listed in the
...@@ -107,9 +108,9 @@ class RustSymbolParser { ...@@ -107,9 +108,9 @@ class RustSymbolParser {
// ParseIdentifier. // ParseIdentifier.
#define ABSL_DEMANGLER_RECURSE(callee, caller) \ #define ABSL_DEMANGLER_RECURSE(callee, caller) \
do { \ do { \
if (depth_ == data_stack_pointer_) return false; \ if (recursion_depth_ == kStackSize) return false; \
/* The next continue will switch on this saved value ... */ \ /* The next continue will switch on this saved value ... */ \
stack_[depth_++] = caller; \ recursion_stack_[recursion_depth_++] = caller; \
goto callee; \ goto callee; \
/* ... and will land here, resuming the suspended code. */ \ /* ... and will land here, resuming the suspended code. */ \
case caller: {} \ case caller: {} \
...@@ -119,10 +120,10 @@ class RustSymbolParser { ...@@ -119,10 +120,10 @@ class RustSymbolParser {
// excessively complex input and infinite-loop bugs. // excessively complex input and infinite-loop bugs.
int iter = 0; int iter = 0;
goto whole_encoding; goto whole_encoding;
for (; iter < kMaxReturns && depth_ > 0; ++iter) { for (; iter < kMaxReturns && recursion_depth_ > 0; ++iter) {
// This switch resumes the code path most recently suspended by // This switch resumes the code path most recently suspended by
// ABSL_DEMANGLER_RECURSE. // ABSL_DEMANGLER_RECURSE.
switch (static_cast<ReturnAddress>(stack_[--depth_])) { switch (recursion_stack_[--recursion_depth_]) {
// //
// symbol-name -> // symbol-name ->
// _R decimal-number? path instantiating-crate? vendor-specific-suffix? // _R decimal-number? path instantiating-crate? vendor-specific-suffix?
...@@ -175,13 +176,13 @@ class RustSymbolParser { ...@@ -175,13 +176,13 @@ class RustSymbolParser {
// nested-path -> N namespace path identifier (N already consumed) // nested-path -> N namespace path identifier (N already consumed)
// namespace -> lower | upper // namespace -> lower | upper
nested_path: nested_path:
// Uppercase namespaces must be saved on the stack so we can print // Uppercase namespaces must be saved on a stack so we can print
// ::{closure#0} or ::{shim:vtable#0} or ::{X:name#0} as needed. // ::{closure#0} or ::{shim:vtable#0} or ::{X:name#0} as needed.
if (IsUpper(Peek())) { if (IsUpper(Peek())) {
if (!PushByte(static_cast<std::uint8_t>(Take()))) return false; if (!PushNamespace(Take())) return false;
ABSL_DEMANGLER_RECURSE(path, kIdentifierInUppercaseNamespace); ABSL_DEMANGLER_RECURSE(path, kIdentifierInUppercaseNamespace);
if (!Emit("::")) return false; if (!Emit("::")) return false;
if (!ParseIdentifier(static_cast<char>(PopByte()))) return false; if (!ParseIdentifier(PopNamespace())) return false;
continue; continue;
} }
...@@ -342,9 +343,14 @@ class RustSymbolParser { ...@@ -342,9 +343,14 @@ class RustSymbolParser {
// deeply nested names at the cost of a larger footprint on the C++ call // deeply nested names at the cost of a larger footprint on the C++ call
// stack. // stack.
enum { enum {
// Maximum (recursive calls + N<uppercase> nested-names) open at one time. // Maximum recursive calls outstanding at one time.
kStackSize = 256, kStackSize = 256,
// Maximum N<uppercase> nested-paths open at once. We do not expect
// closures inside closures inside closures as much as functions inside
// modules inside other modules, so we can use a smaller array here.
kNamespaceStackSize = 64,
// Maximum number of nested backrefs. We can keep this stack pretty small // Maximum number of nested backrefs. We can keep this stack pretty small
// because we do not follow backrefs inside generic-args or other contexts // because we do not follow backrefs inside generic-args or other contexts
// that suppress printing, so deep stacking is unlikely in practice. // that suppress printing, so deep stacking is unlikely in practice.
...@@ -560,17 +566,17 @@ class RustSymbolParser { ...@@ -560,17 +566,17 @@ class RustSymbolParser {
return true; return true;
} }
// Pushes byte onto the data stack (the right side of stack_) and returns // Pushes ns onto the namespace stack and returns true if the stack is not
// true if stack_ is not full, else returns false. // full, else returns false.
ABSL_MUST_USE_RESULT bool PushByte(std::uint8_t byte) { ABSL_MUST_USE_RESULT bool PushNamespace(char ns) {
if (depth_ == data_stack_pointer_) return false; if (namespace_depth_ == kNamespaceStackSize) return false;
stack_[--data_stack_pointer_] = byte; namespace_stack_[namespace_depth_++] = ns;
return true; return true;
} }
// Pops the last pushed data byte from stack_. Requires that the data stack // Pops the last pushed namespace. Requires that the namespace stack is not
// is not empty (data_stack_pointer_ < kStackSize). // empty (namespace_depth_ > 0).
std::uint8_t PopByte() { return stack_[data_stack_pointer_++]; } char PopNamespace() { return namespace_stack_[--namespace_depth_]; }
// Pushes position onto the position stack and returns true if the stack is // Pushes position onto the position stack and returns true if the stack is
// not full, else returns false. // not full, else returns false.
...@@ -624,13 +630,16 @@ class RustSymbolParser { ...@@ -624,13 +630,16 @@ class RustSymbolParser {
// position from the data stack. // position from the data stack.
void EndBackref() { pos_ = PopPosition(); } void EndBackref() { pos_ = PopPosition(); }
// Call and data stacks reside in stack_. The leftmost depth_ elements // The leftmost recursion_depth_ elements of recursion_stack_ contain the
// contain ReturnAddresses pushed by ABSL_DEMANGLER_RECURSE. The elements // ReturnAddresses pushed by ABSL_DEMANGLER_RECURSE calls not yet completed.
// from index data_stack_pointer_ to the right edge of stack_ contain bytes ReturnAddress recursion_stack_[kStackSize] = {};
// pushed by PushByte. int recursion_depth_ = 0;
std::uint8_t stack_[kStackSize] = {};
int data_stack_pointer_ = kStackSize; // The leftmost namespace_depth_ elements of namespace_stack_ contain the
int depth_ = 0; // uppercase namespace identifiers for open nested-paths, e.g., 'C' for a
// closure.
char namespace_stack_[kNamespaceStackSize] = {};
int namespace_depth_ = 0;
// The leftmost position_depth_ elements of position_stack_ contain the input // The leftmost position_depth_ elements of position_stack_ contain the input
// positions to return to after fully printing the targets of backrefs. // positions to return to after fully printing the targets of backrefs.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment