diff options
author | Florin Malita <fmalita@chromium.org> | 2018-06-20 14:23:23 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-06-20 21:58:58 +0000 |
commit | 2e5c1aef58330d8641d88cc6c96fabba274c521d (patch) | |
tree | 089dc0d966017e972c6960914f825174354e5659 /src/utils | |
parent | f9ae670d0563322506490e3fe7f2dae6d432e05f (diff) |
[skjson] Remove the scope index stack
We already allocate a placeholder on the values stack -- we can use that
space to save the previous scope index instead of a dedicated stack.
Yields some minor perf improvements: ~3.5% arm32, ~0.5% x86_64.
Change-Id: I1be30aeb01b1c9661abfe06763a820673e3883f4
Reviewed-on: https://skia-review.googlesource.com/136178
Reviewed-by: Mike Klein <mtklein@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'src/utils')
-rw-r--r-- | src/utils/SkJSON.cpp | 85 |
1 files changed, 54 insertions, 31 deletions
diff --git a/src/utils/SkJSON.cpp b/src/utils/SkJSON.cpp index 2548f4ef41..84a5724fec 100644 --- a/src/utils/SkJSON.cpp +++ b/src/utils/SkJSON.cpp @@ -272,9 +272,7 @@ class DOMParser { public: explicit DOMParser(SkArenaAlloc& alloc) : fAlloc(alloc) { - fValueStack.reserve(kValueStackReserve); - fScopeStack.reserve(kScopeStackReserve); } const Value parse(const char* p, size_t size) { @@ -361,15 +359,16 @@ public: // goto match_post_value; match_post_value: - SkASSERT(!fScopeStack.empty()); + SkASSERT(!this->inTopLevelScope()); p = skip_ws(p); switch (*p) { case ',': ++p; - if (fScopeStack.back() >= 0) { + if (this->inObjectScope()) { goto match_object_key; } else { + SkASSERT(this->inArrayScope()); goto match_value; } case ']': @@ -386,7 +385,7 @@ public: pop_object: SkASSERT(*p == '}'); - if (fScopeStack.back() < 0) { + if (this->inArrayScope()) { return this->error(NullValue(), p, "unexpected object terminator"); } @@ -396,7 +395,7 @@ public: pop_common: SkASSERT(is_eoscope(*p)); - if (fScopeStack.empty()) { + if (this->inTopLevelScope()) { SkASSERT(fValueStack.size() == 1); // Success condition: parsed the top level element and reached the stop token. @@ -425,7 +424,7 @@ public: pop_array: SkASSERT(*p == ']'); - if (fScopeStack.back() >= 0) { + if (this->inObjectScope()) { return this->error(NullValue(), p, "unexpected array terminator"); } @@ -444,14 +443,38 @@ public: private: SkArenaAlloc& fAlloc; + // Pending values stack. static constexpr size_t kValueStackReserve = 256; - static constexpr size_t kScopeStackReserve = 128; - std::vector<Value > fValueStack; - std::vector<intptr_t> fScopeStack; + std::vector<Value> fValueStack; + + // Tracks the current object/array scope, as an index into fStack: + // + // - for objects: fScopeIndex = (index of first value in scope) + // - for arrays : fScopeIndex = -(index of first value in scope) + // + // fScopeIndex == 0 IFF we are at the top level (no current/active scope). + intptr_t fScopeIndex = 0; + // Error reporting. const char* fErrorToken = nullptr; SkString fErrorMessage; + bool inTopLevelScope() const { return fScopeIndex == 0; } + bool inObjectScope() const { return fScopeIndex > 0; } + bool inArrayScope() const { return fScopeIndex < 0; } + + // Helper for masquerading raw primitive types as Values (bypassing tagging, etc). + template <typename T> + class RawValue final : public Value { + public: + explicit RawValue(T v) { + static_assert(sizeof(T) <= sizeof(Value), ""); + *this->cast<T>() = v; + } + + T operator *() const { return *this->cast<T>(); } + }; + template <typename VectorT> void popScopeAsVec(size_t scope_start) { SkASSERT(scope_start > 0); @@ -468,26 +491,27 @@ private: const auto* begin = reinterpret_cast<const T*>(fValueStack.data() + scope_start); - // Instantiate the placeholder value added in onPush{Object/Array}. - fValueStack[scope_start - 1] = VectorT(begin, count, fAlloc); + // Restore the previous scope index from saved placeholder value, + // and instantiate as a vector of values in scope. + auto& placeholder = fValueStack[scope_start - 1]; + fScopeIndex = *static_cast<RawValue<intptr_t>&>(placeholder); + placeholder = VectorT(begin, count, fAlloc); - // Drop the current scope. - fScopeStack.pop_back(); + // Drop the (consumed) values in scope. fValueStack.resize(scope_start); } void pushObjectScope() { - // Object placeholder. - fValueStack.emplace_back(); + // Save a scope index now, and then later we'll overwrite this value as the Object itself. + fValueStack.push_back(RawValue<intptr_t>(fScopeIndex)); - // Object scope marker (size). - fScopeStack.push_back(SkTo<intptr_t>(fValueStack.size())); + // New object scope. + fScopeIndex = SkTo<intptr_t>(fValueStack.size()); } void popObjectScope() { - const auto scope_start = fScopeStack.back(); - SkASSERT(scope_start > 0); - this->popScopeAsVec<ObjectValue>(SkTo<size_t>(scope_start)); + SkASSERT(this->inObjectScope()); + this->popScopeAsVec<ObjectValue>(SkTo<size_t>(fScopeIndex)); SkDEBUGCODE( const auto& obj = fValueStack.back().as<ObjectValue>(); @@ -499,17 +523,16 @@ private: } void pushArrayScope() { - // Array placeholder. - fValueStack.emplace_back(); + // Save a scope index now, and then later we'll overwrite this value as the Array itself. + fValueStack.push_back(RawValue<intptr_t>(fScopeIndex)); - // Array scope marker (-size). - fScopeStack.push_back(-SkTo<intptr_t>(fValueStack.size())); + // New array scope. + fScopeIndex = -SkTo<intptr_t>(fValueStack.size()); } void popArrayScope() { - const auto scope_start = -fScopeStack.back(); - SkASSERT(scope_start > 0); - this->popScopeAsVec<ArrayValue>(SkTo<size_t>(scope_start)); + SkASSERT(this->inArrayScope()); + this->popScopeAsVec<ArrayValue>(SkTo<size_t>(-fScopeIndex)); SkDEBUGCODE( const auto& arr = fValueStack.back().as<ArrayValue>(); @@ -518,9 +541,9 @@ private: } void pushObjectKey(const char* key, size_t size, const char* eos) { - SkASSERT(fScopeStack.back() >= 0); - SkASSERT(fValueStack.size() >= SkTo<size_t>(fScopeStack.back())); - SkASSERT(!((fValueStack.size() - SkTo<size_t>(fScopeStack.back())) & 1)); + SkASSERT(this->inObjectScope()); + SkASSERT(fValueStack.size() >= SkTo<size_t>(fScopeIndex)); + SkASSERT(!((fValueStack.size() - SkTo<size_t>(fScopeIndex)) & 1)); this->pushString(key, size, eos); } |