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 |