Correctly parse line ends for debugging.
authorYang Guo <yangguo@chromium.org>
Thu, 8 Jan 2015 10:45:58 +0000 (11:45 +0100)
committerYang Guo <yangguo@chromium.org>
Thu, 8 Jan 2015 10:46:13 +0000 (10:46 +0000)
Instead of using only \n as line terminator, we now use the definition
in http://www.ecma-international.org/ecma-262/5.1/#sec-7.3

R=marja@chromium.org
BUG=v8:2825
LOG=Y

Review URL: https://codereview.chromium.org/821383009

Cr-Commit-Position: refs/heads/master@{#25989}

src/objects.cc
src/scanner.h
test/mjsunit/regress/regress-2825.js [new file with mode: 0644]

index 5e772ab..10ae80a 100644 (file)
@@ -8764,20 +8764,18 @@ static void CalculateLineEndsImpl(Isolate* isolate,
                                   Vector<const SourceChar> src,
                                   bool include_ending_line) {
   const int src_len = src.length();
-  StringSearch<uint8_t, SourceChar> search(isolate, STATIC_CHAR_VECTOR("\n"));
-
-  // Find and record line ends.
-  int position = 0;
-  while (position != -1 && position < src_len) {
-    position = search.Search(src, position);
-    if (position != -1) {
-      line_ends->Add(position);
-      position++;
-    } else if (include_ending_line) {
-      // Even if the last line misses a line end, it is counted.
-      line_ends->Add(src_len);
-      return;
-    }
+  UnicodeCache* cache = isolate->unicode_cache();
+  for (int i = 0; i < src_len - 1; i++) {
+    SourceChar current = src[i];
+    SourceChar next = src[i + 1];
+    if (cache->IsLineTerminatorSequence(current, next)) line_ends->Add(i);
+  }
+
+  if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) {
+    line_ends->Add(src_len - 1);
+  } else if (include_ending_line) {
+    // Even if the last line misses a line end, it is counted.
+    line_ends->Add(src_len);
   }
 }
 
index 6e668fd..8537c53 100644 (file)
@@ -121,6 +121,12 @@ class UnicodeCache {
   bool IsIdentifierStart(unibrow::uchar c) { return kIsIdentifierStart.get(c); }
   bool IsIdentifierPart(unibrow::uchar c) { return kIsIdentifierPart.get(c); }
   bool IsLineTerminator(unibrow::uchar c) { return kIsLineTerminator.get(c); }
+  bool IsLineTerminatorSequence(unibrow::uchar c, unibrow::uchar next) {
+    if (!IsLineTerminator(c)) return false;
+    if (c == 0x000d && next == 0x000a) return false;  // CR with following LF.
+    return true;
+  }
+
   bool IsWhiteSpace(unibrow::uchar c) { return kIsWhiteSpace.get(c); }
   bool IsWhiteSpaceOrLineTerminator(unibrow::uchar c) {
     return kIsWhiteSpaceOrLineTerminator.get(c);
diff --git a/test/mjsunit/regress/regress-2825.js b/test/mjsunit/regress/regress-2825.js
new file mode 100644 (file)
index 0000000..6ffd8ec
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+
+// Do not edit this file with an editor that replaces \r with \r\n.
+// Variable definitions for i0 through i3 are each terminated with \r.
+function f() {
+  var i0 = 0;\r  var i1 = 1;\r  var i2 = 2;\r  var i3 = 3;\r
+  var j0 = 0;
+  var j1 = 1;
+  var j2 = 2;
+  var j3 = 3;
+}
+
+Debug = debug.Debug;
+var exception = null;
+var break_point_hit = false;
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    break_point_hit = true;
+    assertEquals("  var i2 = 2;", exec_state.frame(0).sourceLineText());
+  } catch (e) {
+    print(e + e.stack);
+    exception = e;
+  }
+}
+
+Debug.setListener(listener);
+
+Debug.setBreakPoint(f, 3, 0);
+
+f();
+
+Debug.setListener(null);
+assertTrue(break_point_hit);
+assertNull(exception);