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 |