From d6c0ba0195950a4adda3c2abb9439dc2e86ca282 Mon Sep 17 00:00:00 2001
From: Lucian Grijincu <lucian@fb.com>
Date: Wed, 28 Sep 2016 22:33:39 -0700
Subject: [PATCH] folly: Range: outline exception throwing

Summary:
Here's some godbolt: https://godbolt.org/g/9K36Km

  advanceNoInline(S):
          movq    %rdi, %rax
          sarq    $32, %rax
          cmpl    %eax, %edi
          jg      .L20
          leal    1(%rdi), %eax
          ret
  .L20:
          subq    $8, %rsp
          call    S::outOfRange() [clone .isra.0]

vs previous implementation

  advance(S):
          movq    %rdi, %rdx
          sarq    $32, %rdx
          cmpl    %edx, %edi
          jg      .L14
          leal    1(%rdi), %eax
          ret
  .L14:
          pushq   %rbp
          pushq   %rbx
          movl    $16, %edi
          subq    $8, %rsp
          call    __cxa_allocate_exception
          movl    $.LC0, %esi
          movq    %rax, %rdi
          movq    %rax, %rbx
          call    std::out_of_range::out_of_range(char const*)
          movl    std::out_of_range::~out_of_range(), %edx
          movl    typeinfo for std::out_of_range, %esi
          movq    %rbx, %rdi
          call    __cxa_throw
          movq    %rax, %rbp
          movq    %rbx, %rdi
          call    __cxa_free_exception
          movq    %rbp, %rdi
          call    _Unwind_Resume

Reviewed By: ot

Differential Revision: D3940968

fbshipit-source-id: b47a41e7cdd863fcef099ff3c21860b2979ee6e8
---
 folly/Range.h | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/folly/Range.h b/folly/Range.h
index 59e14bd5..9cacdd58 100644
--- a/folly/Range.h
+++ b/folly/Range.h
@@ -145,6 +145,11 @@ struct IsCharPointer<const char*> {
   typedef int type;
 };
 
+// Prevent it from being inlined to reduce instruction bloat.
+FOLLY_NOINLINE inline void throwOutOfRange() {
+  throw std::out_of_range("index out of range");
+}
+
 } // namespace detail
 
 /**
@@ -217,7 +222,7 @@ public:
   template <class T = Iter, typename detail::IsCharPointer<T>::const_type = 0>
   Range(const std::string& str, std::string::size_type startFrom) {
     if (UNLIKELY(startFrom > str.size())) {
-      throw std::out_of_range("index out of range");
+      detail::throwOutOfRange();
     }
     b_ = str.data() + startFrom;
     e_ = str.data() + str.size();
@@ -228,7 +233,7 @@ public:
         std::string::size_type startFrom,
         std::string::size_type size) {
     if (UNLIKELY(startFrom > str.size())) {
-      throw std::out_of_range("index out of range");
+      detail::throwOutOfRange();
     }
     b_ = str.data() + startFrom;
     if (str.size() - startFrom < size) {
@@ -251,7 +256,7 @@ public:
   template <class T = Iter, typename detail::IsCharPointer<T>::const_type = 0>
   Range(const fbstring& str, fbstring::size_type startFrom) {
     if (UNLIKELY(startFrom > str.size())) {
-      throw std::out_of_range("index out of range");
+      detail::throwOutOfRange();
     }
     b_ = str.data() + startFrom;
     e_ = str.data() + str.size();
@@ -261,7 +266,7 @@ public:
   Range(const fbstring& str, fbstring::size_type startFrom,
         fbstring::size_type size) {
     if (UNLIKELY(startFrom > str.size())) {
-      throw std::out_of_range("index out of range");
+      detail::throwOutOfRange();
     }
     b_ = str.data() + startFrom;
     if (str.size() - startFrom < size) {
@@ -426,12 +431,12 @@ public:
   }
 
   value_type& at(size_t i) {
-    if (i >= size()) throw std::out_of_range("index out of range");
+    if (i >= size()) detail::throwOutOfRange();
     return b_[i];
   }
 
   const value_type& at(size_t i) const {
-    if (i >= size()) throw std::out_of_range("index out of range");
+    if (i >= size()) detail::throwOutOfRange();
     return b_[i];
   }
 
@@ -453,21 +458,21 @@ public:
 
   void advance(size_type n) {
     if (UNLIKELY(n > size())) {
-      throw std::out_of_range("index out of range");
+      detail::throwOutOfRange();
     }
     b_ += n;
   }
 
   void subtract(size_type n) {
     if (UNLIKELY(n > size())) {
-      throw std::out_of_range("index out of range");
+      detail::throwOutOfRange();
     }
     e_ -= n;
   }
 
   Range subpiece(size_type first, size_type length = npos) const {
     if (UNLIKELY(first > size())) {
-      throw std::out_of_range("index out of range");
+      detail::throwOutOfRange();
     }
 
     return Range(b_ + first, std::min(length, size() - first));
@@ -628,7 +633,7 @@ public:
     } else if (e == e_) {
       e_ = b;
     } else {
-      throw std::out_of_range("index out of range");
+      detail::throwOutOfRange();
     }
   }
 
-- 
2.34.1