Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(639)

Unified Diff: src/scanner.cc

Issue 6246102: Improve ScanJsonNumber performance. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/scanner.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/scanner.cc
===================================================================
--- src/scanner.cc (revision 6629)
+++ src/scanner.cc (working copy)
@@ -25,11 +25,13 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <limits.h>
#include "v8.h"
#include "ast.h"
#include "handles.h"
#include "scanner.h"
+#include "strtod.h"
#include "unicode-inl.h"
namespace v8 {
@@ -420,6 +422,10 @@
token = ScanJsonString();
break;
case '-':
+ Advance();
+ token = ScanJsonNumber();
+ number = -number;
+ break;
case '0':
case '1':
case '2':
@@ -515,35 +521,108 @@
Token::Value JsonScanner::ScanJsonNumber() {
- LiteralScope literal(this);
- if (c0_ == '-') AddLiteralCharAdvance();
+ // Maximum number of significant digits in decimal representation.
+ // The longest possible double in decimal representation is
+ // (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074
+ // (768 digits). If we parse a number whose first digits are equal to a
+ // mean of 2 adjacent doubles (that could have up to 769 digits) the result
+ // must be rounded to the bigger one unless the tail consists of zeros, so
+ // we don't need to preserve all the digits.
+ const int kMaxSignificantDigits = 772;
+ // The longest form of simplified number is: "-<significant digits>'.1eXXX\0".
+ const int kBufferSize = kMaxSignificantDigits + 10;
+ char buffer[kBufferSize]; // NOLINT: size is known at compile time.
+ int buffer_pos = 0;
+
+ // Exponent will be adjusted if insignificant digits of the integer part
+ // or insignificant leading zeros of the fractional part are dropped.
+ int exponent = 0;
+ int significant_digits = 0;
+ int insignificant_digits = 0;
+ int i = 0;
+ bool nonzero_digit_dropped = false;
if (c0_ == '0') {
- AddLiteralCharAdvance();
+ Advance();
// Prefix zero is only allowed if it's the only digit before
// a decimal point or exponent.
if ('0' <= c0_ && c0_ <= '9') return Token::ILLEGAL;
} else {
if (c0_ < '1' || c0_ > '9') return Token::ILLEGAL;
do {
- AddLiteralCharAdvance();
+ if (significant_digits < kMaxSignificantDigits) {
+ ASSERT(buffer_pos < kBufferSize);
+ buffer[buffer_pos++] = static_cast<char>(c0_);
+ significant_digits++;
+ i = i * 10 + c0_ - '0';
+ } else {
+ insignificant_digits++; // Move the digit into the exponential part.
+ nonzero_digit_dropped = nonzero_digit_dropped || c0_ != '0';
+ }
+ Advance();
} while (c0_ >= '0' && c0_ <= '9');
+ if (c0_ != '.' && c0_ != 'e' && c0_ != 'E' && significant_digits < 10) {
+ number = i;
+ return Token::NUMBER;
+ }
}
if (c0_ == '.') {
- AddLiteralCharAdvance();
+ Advance();
if (c0_ < '0' || c0_ > '9') return Token::ILLEGAL;
+ if (significant_digits == 0) {
+ // Integer part consists of 0.
+ // Significant digits start after leading zero(s).
+ while (c0_ == '0') {
+ Advance();
+ exponent--; // Move this 0 into the exponent.
+ }
+ if (c0_ < '0' || c0_ > '9') {
+ number = 0.0;
+ return Token::NUMBER;
+ }
+ }
do {
- AddLiteralCharAdvance();
+ if (significant_digits < kMaxSignificantDigits) {
+ ASSERT(buffer_pos < kBufferSize);
+ buffer[buffer_pos++] = static_cast<char>(c0_);
+ significant_digits++;
+ exponent--;
+ } else {
+ // Ignore insignificant digits in the fractional part.
+ nonzero_digit_dropped = nonzero_digit_dropped || c0_ != '0';
+ }
+ Advance();
} while (c0_ >= '0' && c0_ <= '9');
}
- if (AsciiAlphaToLower(c0_) == 'e') {
- AddLiteralCharAdvance();
- if (c0_ == '-' || c0_ == '+') AddLiteralCharAdvance();
+ if (c0_ == 'e' || c0_ == 'E') {
+ Advance();
+ bool expsign = (c0_ == '-');
+ if (expsign || c0_ == '+') Advance();
if (c0_ < '0' || c0_ > '9') return Token::ILLEGAL;
+ const int max_exponent = INT_MAX / 2;
+ ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2);
+ int num = 0;
do {
- AddLiteralCharAdvance();
+ // Check overflow.
+ int digit = c0_ - '0';
+ if (num >= max_exponent / 10
+ && !(num == max_exponent / 10 && digit <= max_exponent % 10)) {
+ num = max_exponent;
+ } else {
+ num = num * 10 + digit;
+ }
+ Advance();
} while (c0_ >= '0' && c0_ <= '9');
+ exponent += (expsign ? -num : num);
}
- literal.Complete();
+
+ exponent += insignificant_digits;
+ if (nonzero_digit_dropped) {
+ buffer[buffer_pos++] = '1';
+ exponent--;
+ }
+ ASSERT(buffer_pos < kBufferSize);
+ buffer[buffer_pos] = '\0';
+ number = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
return Token::NUMBER;
}
« no previous file with comments | « src/scanner.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698