| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/tools/balsa/balsa_frame.h" | 5 #include "net/tools/balsa/balsa_frame.h" |
| 6 | 6 |
| 7 // Visual C++ defines _M_IX86_FP as 2 if the /arch:SSE2 compiler option is |
| 8 // specified. |
| 9 #if !defined(__SSE2__) && _M_IX86_FP == 2 |
| 10 #define __SSE2__ 1 |
| 11 #endif |
| 12 |
| 7 #include <assert.h> | 13 #include <assert.h> |
| 8 #if __SSE2__ | 14 #if __SSE2__ |
| 9 #include <emmintrin.h> | 15 #include <emmintrin.h> |
| 10 #endif // __SSE2__ | 16 #endif // __SSE2__ |
| 11 | 17 |
| 12 #include <limits> | 18 #include <limits> |
| 13 #include <string> | 19 #include <string> |
| 14 #include <utility> | 20 #include <utility> |
| 15 #include <vector> | 21 #include <vector> |
| 16 | 22 |
| 17 #include "base/logging.h" | 23 #include "base/logging.h" |
| 18 #include "base/port.h" | 24 #include "base/port.h" |
| 19 #include "base/strings/string_piece.h" | 25 #include "base/strings/string_piece.h" |
| 20 #include "net/tools/balsa/balsa_enums.h" | 26 #include "net/tools/balsa/balsa_enums.h" |
| 21 #include "net/tools/balsa/balsa_headers.h" | 27 #include "net/tools/balsa/balsa_headers.h" |
| 22 #include "net/tools/balsa/balsa_visitor_interface.h" | 28 #include "net/tools/balsa/balsa_visitor_interface.h" |
| 23 #include "net/tools/balsa/buffer_interface.h" | 29 #include "net/tools/balsa/buffer_interface.h" |
| 24 #include "net/tools/balsa/simple_buffer.h" | 30 #include "net/tools/balsa/simple_buffer.h" |
| 25 #include "net/tools/balsa/split.h" | 31 #include "net/tools/balsa/split.h" |
| 26 #include "net/tools/balsa/string_piece_utils.h" | 32 #include "net/tools/balsa/string_piece_utils.h" |
| 27 | 33 |
| 28 #if defined(COMPILER_MSVC) | 34 #if defined(COMPILER_MSVC) |
| 35 #include <intrin.h> |
| 29 #include <string.h> | 36 #include <string.h> |
| 37 |
| 38 #pragma intrinsic(_BitScanForward) |
| 39 |
| 40 static int ffs(int i) { |
| 41 unsigned long index; |
| 42 return _BitScanForward(&index, i) ? index + 1 : 0; |
| 43 } |
| 44 |
| 30 #define strncasecmp _strnicmp | 45 #define strncasecmp _strnicmp |
| 31 #else | 46 #else |
| 32 #include <strings.h> | 47 #include <strings.h> |
| 33 #endif | 48 #endif |
| 34 | 49 |
| 35 namespace net { | 50 namespace net { |
| 36 | 51 |
| 37 // Constants holding some header names for headers which can affect the way the | 52 // Constants holding some header names for headers which can affect the way the |
| 38 // HTTP message is framed, and so must be processed specially: | 53 // HTTP message is framed, and so must be processed specially: |
| 39 static const char kContentLength[] = "content-length"; | 54 static const char kContentLength[] = "content-length"; |
| (...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 496 DCHECK_GE(current_header_line->last_char_idx, | 511 DCHECK_GE(current_header_line->last_char_idx, |
| 497 current_header_line->value_begin_idx); | 512 current_header_line->value_begin_idx); |
| 498 } | 513 } |
| 499 | 514 |
| 500 inline void BalsaFrame::FindColonsAndParseIntoKeyValue() { | 515 inline void BalsaFrame::FindColonsAndParseIntoKeyValue() { |
| 501 DCHECK(!lines_.empty()); | 516 DCHECK(!lines_.empty()); |
| 502 const char* stream_begin = headers_->OriginalHeaderStreamBegin(); | 517 const char* stream_begin = headers_->OriginalHeaderStreamBegin(); |
| 503 // The last line is always just a newline (and is uninteresting). | 518 // The last line is always just a newline (and is uninteresting). |
| 504 const Lines::size_type lines_size_m1 = lines_.size() - 1; | 519 const Lines::size_type lines_size_m1 = lines_.size() - 1; |
| 505 #if __SSE2__ | 520 #if __SSE2__ |
| 506 const __v16qi colons = { ':', ':', ':', ':', ':', ':', ':', ':', | 521 const __m128i colons = _mm_set1_epi8(':'); |
| 507 ':', ':', ':', ':', ':', ':', ':', ':'}; | |
| 508 const char* header_lines_end_m16 = headers_->OriginalHeaderStreamEnd() - 16; | 522 const char* header_lines_end_m16 = headers_->OriginalHeaderStreamEnd() - 16; |
| 509 #endif // __SSE2__ | 523 #endif // __SSE2__ |
| 510 const char* current = stream_begin + lines_[1].first; | 524 const char* current = stream_begin + lines_[1].first; |
| 511 // This code is a bit more subtle than it may appear at first glance. | 525 // This code is a bit more subtle than it may appear at first glance. |
| 512 // This code looks for a colon in the current line... but it also looks | 526 // This code looks for a colon in the current line... but it also looks |
| 513 // beyond the current line. If there is no colon in the current line, then | 527 // beyond the current line. If there is no colon in the current line, then |
| 514 // for each subsequent line (until the colon which -has- been found is | 528 // for each subsequent line (until the colon which -has- been found is |
| 515 // associated with a line), no searching for a colon will be performed. In | 529 // associated with a line), no searching for a colon will be performed. In |
| 516 // this way, we minimize the amount of bytes we have scanned for a colon. | 530 // this way, we minimize the amount of bytes we have scanned for a colon. |
| 517 for (Lines::size_type i = 1; i < lines_size_m1;) { | 531 for (Lines::size_type i = 1; i < lines_size_m1;) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 568 // When this condition is true, the last detected colon was part of a | 582 // When this condition is true, the last detected colon was part of a |
| 569 // previous line. We reset to the beginning of the line as we don't care | 583 // previous line. We reset to the beginning of the line as we don't care |
| 570 // about the presence of any colon before the beginning of the current | 584 // about the presence of any colon before the beginning of the current |
| 571 // line. | 585 // line. |
| 572 current = line_begin; | 586 current = line_begin; |
| 573 } | 587 } |
| 574 #if __SSE2__ | 588 #if __SSE2__ |
| 575 while (current < header_lines_end_m16) { | 589 while (current < header_lines_end_m16) { |
| 576 __m128i header_bytes = | 590 __m128i header_bytes = |
| 577 _mm_loadu_si128(reinterpret_cast<const __m128i *>(current)); | 591 _mm_loadu_si128(reinterpret_cast<const __m128i *>(current)); |
| 578 __m128i colon_cmp = | 592 __m128i colon_cmp = _mm_cmpeq_epi8(header_bytes, colons); |
| 579 _mm_cmpeq_epi8(header_bytes, reinterpret_cast<__m128i>(colons)); | |
| 580 int colon_msk = _mm_movemask_epi8(colon_cmp); | 593 int colon_msk = _mm_movemask_epi8(colon_cmp); |
| 581 if (colon_msk == 0) { | 594 if (colon_msk == 0) { |
| 582 current += 16; | 595 current += 16; |
| 583 continue; | 596 continue; |
| 584 } | 597 } |
| 585 current += (ffs(colon_msk) - 1); | 598 current += (ffs(colon_msk) - 1); |
| 586 if (current > line_end) { | 599 if (current > line_end) { |
| 587 break; | 600 break; |
| 588 } | 601 } |
| 589 goto found_colon; | 602 goto found_colon; |
| (...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 975 } | 988 } |
| 976 ++message_current; | 989 ++message_current; |
| 977 } while (message_current < message_end); | 990 } while (message_current < message_end); |
| 978 goto bottom; // this is necessary to skip 'last_char_was_slash_r' checks | 991 goto bottom; // this is necessary to skip 'last_char_was_slash_r' checks |
| 979 } else { | 992 } else { |
| 980 read_real_message: | 993 read_real_message: |
| 981 // Note that SSE2 can be enabled on certain piii platforms. | 994 // Note that SSE2 can be enabled on certain piii platforms. |
| 982 #if __SSE2__ | 995 #if __SSE2__ |
| 983 { | 996 { |
| 984 const char* const message_end_m16 = message_end - 16; | 997 const char* const message_end_m16 = message_end - 16; |
| 985 __v16qi newlines = { '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n', | 998 __m128i newlines = _mm_set1_epi8('\n'); |
| 986 '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n' }; | |
| 987 while (message_current < message_end_m16) { | 999 while (message_current < message_end_m16) { |
| 988 // What this does (using compiler intrinsics): | 1000 // What this does (using compiler intrinsics): |
| 989 // | 1001 // |
| 990 // Load 16 '\n's into an xmm register | 1002 // Load 16 '\n's into an xmm register |
| 991 // Load 16 bytes of currennt message into an xmm register | 1003 // Load 16 bytes of currennt message into an xmm register |
| 992 // Do byte-wise equals on those two xmm registers | 1004 // Do byte-wise equals on those two xmm registers |
| 993 // Take the first bit of each byte, and put that into the first | 1005 // Take the first bit of each byte, and put that into the first |
| 994 // 16 bits of a mask | 1006 // 16 bits of a mask |
| 995 // If the mask is zero, no '\n' found. increment by 16 and try again | 1007 // If the mask is zero, no '\n' found. increment by 16 and try again |
| 996 // Else scan forward to find the first set bit. | 1008 // Else scan forward to find the first set bit. |
| 997 // Increment current by the index of the first set bit | 1009 // Increment current by the index of the first set bit |
| 998 // (ffs returns index of first set bit + 1) | 1010 // (ffs returns index of first set bit + 1) |
| 999 __m128i msg_bytes = | 1011 __m128i msg_bytes = |
| 1000 _mm_loadu_si128(const_cast<__m128i *>( | 1012 _mm_loadu_si128(const_cast<__m128i *>( |
| 1001 reinterpret_cast<const __m128i *>(message_current))); | 1013 reinterpret_cast<const __m128i *>(message_current))); |
| 1002 __m128i newline_cmp = | 1014 __m128i newline_cmp = _mm_cmpeq_epi8(msg_bytes, newlines); |
| 1003 _mm_cmpeq_epi8(msg_bytes, reinterpret_cast<__m128i>(newlines)); | |
| 1004 int newline_msk = _mm_movemask_epi8(newline_cmp); | 1015 int newline_msk = _mm_movemask_epi8(newline_cmp); |
| 1005 if (newline_msk == 0) { | 1016 if (newline_msk == 0) { |
| 1006 message_current += 16; | 1017 message_current += 16; |
| 1007 continue; | 1018 continue; |
| 1008 } | 1019 } |
| 1009 message_current += (ffs(newline_msk) - 1); | 1020 message_current += (ffs(newline_msk) - 1); |
| 1010 const size_t relative_idx = message_current - message_start; | 1021 const size_t relative_idx = message_current - message_start; |
| 1011 const size_t message_current_idx = 1 + base_idx + relative_idx; | 1022 const size_t message_current_idx = 1 + base_idx + relative_idx; |
| 1012 lines_.push_back(std::make_pair(last_slash_n_idx_, | 1023 lines_.push_back(std::make_pair(last_slash_n_idx_, |
| 1013 message_current_idx)); | 1024 message_current_idx)); |
| (...skipping 542 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1556 << "$$$$$$$$$$$$$$$" | 1567 << "$$$$$$$$$$$$$$$" |
| 1557 << " consumed: " << (current - input); | 1568 << " consumed: " << (current - input); |
| 1558 if (Error()) { | 1569 if (Error()) { |
| 1559 LOG(INFO) << BalsaFrameEnums::ErrorCodeToString(ErrorCode()); | 1570 LOG(INFO) << BalsaFrameEnums::ErrorCodeToString(ErrorCode()); |
| 1560 } | 1571 } |
| 1561 #endif // DEBUGFRAMER | 1572 #endif // DEBUGFRAMER |
| 1562 return current - input; | 1573 return current - input; |
| 1563 } | 1574 } |
| 1564 | 1575 |
| 1565 } // namespace net | 1576 } // namespace net |
| OLD | NEW |