Looks in the State cache for a State matching inst, ninst, flag. If one is found, returns it. If one is not found, allocates one, inserts it in the cache, and returns it.
| 724 | // If one is found, returns it. If one is not found, allocates one, |
| 725 | // inserts it in the cache, and returns it. |
| 726 | DFA::State* DFA::CachedState(int* inst, int ninst, uint32_t flag) { |
| 727 | //mutex_.AssertHeld(); |
| 728 | |
| 729 | // Look in the cache for a pre-existing state. |
| 730 | // We have to initialise the struct like this because otherwise |
| 731 | // MSVC will complain about the flexible array member. :( |
| 732 | State state; |
| 733 | state.inst_ = inst; |
| 734 | state.ninst_ = ninst; |
| 735 | state.flag_ = flag; |
| 736 | StateSet::iterator it = state_cache_.find(&state); |
| 737 | if (it != state_cache_.end()) { |
| 738 | if (ExtraDebug) |
| 739 | fprintf(stderr, " -cached-> %s\n", DumpState(*it).c_str()); |
| 740 | return *it; |
| 741 | } |
| 742 | |
| 743 | // Must have enough memory for new state. |
| 744 | // In addition to what we're going to allocate, |
| 745 | // the state cache hash table seems to incur about 40 bytes per |
| 746 | // State*, empirically. |
| 747 | const int kStateCacheOverhead = 40; |
| 748 | int nnext = prog_->bytemap_range() + 1; // + 1 for kByteEndText slot |
| 749 | int mem = sizeof(State) + nnext*sizeof(std::atomic<State*>) + |
| 750 | ninst*sizeof(int); |
| 751 | if (mem_budget_ < mem + kStateCacheOverhead) { |
| 752 | mem_budget_ = -1; |
| 753 | return NULL; |
| 754 | } |
| 755 | mem_budget_ -= mem + kStateCacheOverhead; |
| 756 | |
| 757 | // Allocate new state along with room for next_ and inst_. |
| 758 | char* space = std::allocator<char>().allocate(mem); |
| 759 | State* s = new (space) State; |
| 760 | (void) new (s->next_) std::atomic<State*>[nnext]; |
| 761 | // Work around a unfortunate bug in older versions of libstdc++. |
| 762 | // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64658) |
| 763 | for (int i = 0; i < nnext; i++) |
| 764 | (void) new (s->next_ + i) std::atomic<State*>(NULL); |
| 765 | s->inst_ = new (s->next_ + nnext) int[ninst]; |
| 766 | memmove(s->inst_, inst, ninst*sizeof s->inst_[0]); |
| 767 | s->ninst_ = ninst; |
| 768 | s->flag_ = flag; |
| 769 | if (ExtraDebug) |
| 770 | fprintf(stderr, " -> %s\n", DumpState(s).c_str()); |
| 771 | |
| 772 | // Put state in cache and return it. |
| 773 | state_cache_.insert(s); |
| 774 | return s; |
| 775 | } |
| 776 | |
| 777 | // Clear the cache. Must hold cache_mutex_.w or be in destructor. |
| 778 | void DFA::ClearCache() { |