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