Author: [email protected]
Date: Wed Feb  4 04:07:45 2009
New Revision: 1223

Modified:
    branches/bleeding_edge/src/accessors.cc
    branches/bleeding_edge/src/accessors.h
    branches/bleeding_edge/src/bootstrapper.cc
    branches/bleeding_edge/src/compiler.cc
    branches/bleeding_edge/src/messages.js
    branches/bleeding_edge/src/objects.cc

Log:
Refactor code for determining line position in a source file.

1. Make Script::line_ends initialization two-pass to avoid
    dynamic memory allocation
2. Get rid of the original code in messages.js and use
    Script::line_ends instead.

Review URL: http://codereview.chromium.org/21041

Modified: branches/bleeding_edge/src/accessors.cc
==============================================================================
--- branches/bleeding_edge/src/accessors.cc     (original)
+++ branches/bleeding_edge/src/accessors.cc     Wed Feb  4 04:07:45 2009
@@ -252,6 +252,25 @@


  //
+// Accessors::ScriptGetLineEnds
+//
+
+
+Object* Accessors::ScriptGetLineEnds(Object* object, void*) {
+  Object* script = JSValue::cast(object)->value();
+  Script::cast(script)->InitLineEnds();
+  return Script::cast(script)->line_ends();
+}
+
+
+const AccessorDescriptor Accessors::ScriptLineEnds = {
+  ScriptGetLineEnds,
+  IllegalSetter,
+  0
+};
+
+
+//
  // Accessors::FunctionPrototype
  //


Modified: branches/bleeding_edge/src/accessors.h
==============================================================================
--- branches/bleeding_edge/src/accessors.h      (original)
+++ branches/bleeding_edge/src/accessors.h      Wed Feb  4 04:07:45 2009
@@ -45,6 +45,7 @@
    V(ScriptLineOffset)    \
    V(ScriptColumnOffset)  \
    V(ScriptType)          \
+  V(ScriptLineEnds)      \
    V(ObjectPrototype)

  // Accessors contains all predefined proxy accessors.
@@ -82,6 +83,7 @@
    static Object* ScriptGetLineOffset(Object* object, void*);
    static Object* ScriptGetColumnOffset(Object* object, void*);
    static Object* ScriptGetType(Object* object, void*);
+  static Object* ScriptGetLineEnds(Object* object, void*);
    static Object* ObjectGetPrototype(Object* receiver, void*);
    static Object* ObjectSetPrototype(JSObject* receiver, Object* value,  
void*);


Modified: branches/bleeding_edge/src/bootstrapper.cc
==============================================================================
--- branches/bleeding_edge/src/bootstrapper.cc  (original)
+++ branches/bleeding_edge/src/bootstrapper.cc  Wed Feb  4 04:07:45 2009
@@ -1014,6 +1014,14 @@
              Factory::LookupAsciiSymbol("type"),
              proxy_type,
              common_attributes);
+    Handle<Proxy> proxy_line_ends =
+        Factory::NewProxy(&Accessors::ScriptLineEnds);
+    script_descriptors =
+        Factory::CopyAppendProxyDescriptor(
+            script_descriptors,
+            Factory::LookupAsciiSymbol("line_ends"),
+            proxy_line_ends,
+            common_attributes);

      Handle<Map> script_map = Handle<Map>(script_fun->initial_map());
      script_map->set_instance_descriptors(*script_descriptors);

Modified: branches/bleeding_edge/src/compiler.cc
==============================================================================
--- branches/bleeding_edge/src/compiler.cc      (original)
+++ branches/bleeding_edge/src/compiler.cc      Wed Feb  4 04:07:45 2009
@@ -304,12 +304,12 @@
    // the line number is not for free.
    if (Logger::is_enabled()) {
      if (script->name()->IsString()) {
-      int lineNum = script->GetLineNumber(start_position);
-      if (lineNum > 0) {
-        lineNum += script->line_offset()->value() + 1;
+      int line_num = script->GetLineNumber(start_position);
+      if (line_num > 0) {
+        line_num += script->line_offset()->value() + 1;
        }
        LOG(CodeCreateEvent("LazyCompile", *code, *lit->name(),
-                          String::cast(script->name()), lineNum));
+                          String::cast(script->name()), line_num));
      } else {
        LOG(CodeCreateEvent("LazyCompile", *code, *lit->name()));
      }

Modified: branches/bleeding_edge/src/messages.js
==============================================================================
--- branches/bleeding_edge/src/messages.js      (original)
+++ branches/bleeding_edge/src/messages.js      Wed Feb  4 04:07:45 2009
@@ -102,7 +102,7 @@
    invalid_array_length:         "Invalid array length",
    invalid_array_apply_length:   "Function.prototype.apply supports only up  
to 1024 arguments",
    stack_overflow:               "Maximum call stack size exceeded",
-  apply_overflow:               "Function.prototype.apply cannot  
support %0 arguments",
+  apply_overflow:               "Function.prototype.apply cannot  
support %0 arguments",
    // SyntaxError
    unable_to_parse:              "Parse error",
    duplicate_regexp_flag:        "Duplicate RegExp flag %0",
@@ -228,47 +228,19 @@


  /**
- * Initialize the cached source information in a script. Currently all line
- * end positions are cached.
- */
-Script.prototype.initSourceInfo_ = function () {
-  // Just return if initialized.
-  if (this.lineEnds_) return;
-
-  // Collect all line endings.
-  this.lineEnds_ = [];
-  for (var i = 0; i < this.source.length; i++) {
-    var current = this.source.charAt(i);
-    if (current == '\n') {
-      this.lineEnds_.push(i);
-    }
-  }
-
-  // If the script does not end with a line ending add the final end  
position
-  // as just past the last line ending.
-  if (this.lineEnds_[this.lineEnds_.length - 1] != this.source.length - 1)  
{
-    this.lineEnds_.push(this.source.length);
-  }
-};
-
-
-/**
   * Get information on a specific source position.
   * @param {number} position The source position
   * @return {SourceLocation}
   *     If line is negative or not in the source null is returned.
   */
  Script.prototype.locationFromPosition = function (position) {
-  // Make sure source info has been initialized.
-  this.initSourceInfo_();
-
    var lineCount = this.lineCount();
    var line = -1;
-  if (position <= this.lineEnds_[0]) {
+  if (position <= this.line_ends[0]) {
      line = 0;
    } else {
      for (var i = 1; i < lineCount; i++) {
-      if (this.lineEnds_[i - 1] < position && position <=  
this.lineEnds_[i]) {
+      if (this.line_ends[i - 1] < position && position <=  
this.line_ends[i]) {
          line = i;
          break;
        }
@@ -278,8 +250,8 @@
    if (line == -1) return null;

    // Determine start, end and column.
-  var start = line == 0 ? 0 : this.lineEnds_[line - 1] + 1;
-  var end = this.lineEnds_[line];
+  var start = line == 0 ? 0 : this.line_ends[line - 1] + 1;
+  var end = this.line_ends[line];
    if (end > 0 && this.source.charAt(end - 1) == '\r') end--;
    var column = position - start;

@@ -308,9 +280,6 @@
   *     If line is negative or not in the source null is returned.
   */
  Script.prototype.locationFromLine = function (opt_line, opt_column,  
opt_offset_position) {
-  // Make soure source info has been initialized.
-  this.initSourceInfo_();
-
    // Default is the first line in the script. Lines in the script is  
relative
    // to the offset within the resource.
    var line = 0;
@@ -334,13 +303,13 @@
      var lineCount = this.lineCount();
      var offset_line;
      for (var i = 0; i < lineCount; i++) {
-      if (offset_position <= this.lineEnds_[i]) {
+      if (offset_position <= this.line_ends[i]) {
          offset_line = i;
          break;
        }
      }
      if (offset_line + line >= lineCount) return null;
-    return this.locationFromPosition(this.lineEnds_[offset_line + line -  
1] + 1 + column);  // line > 0 here.
+    return this.locationFromPosition(this.line_ends[offset_line + line -  
1] + 1 + column);  // line > 0 here.
    }
  }

@@ -356,9 +325,6 @@
   *     invalid
   */
  Script.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
-  // Make soure source info has been initialized.
-  this.initSourceInfo_();
-
    var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset :  
opt_from_line;
    var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset +  
this.lineCount() : opt_to_line

@@ -368,15 +334,15 @@
    if (from_line < 0) from_line = 0;
    if (to_line > this.lineCount()) to_line = this.lineCount();

-  // Check parameters.
+  // Check parameters.
    if (from_line >= this.lineCount() ||
        to_line < 0 ||
        from_line > to_line) {
      return null;
    }

-  var from_position = from_line == 0 ? 0 : this.lineEnds_[from_line - 1] +  
1;
-  var to_position = to_line == 0 ? 0 : this.lineEnds_[to_line - 1] + 1;
+  var from_position = from_line == 0 ? 0 : this.line_ends[from_line - 1] +  
1;
+  var to_position = to_line == 0 ? 0 : this.line_ends[to_line - 1] + 1;

    // Return a source slice with line numbers re-adjusted to the resource.
    return new SourceSlice(this, from_line + this.line_offset, to_line +  
this.line_offset,
@@ -391,15 +357,15 @@
    if (!IS_UNDEFINED(opt_line)) {
      line = opt_line - this.line_offset;
    }
-
-  // Check parameter.
+
+  // Check parameter.
    if (line < 0 || this.lineCount() <= line) {
      return null;
    }

-  // Return the source line.
-  var start = line == 0 ? 0 : this.lineEnds_[line - 1] + 1;
-  var end = this.lineEnds_[line];
+  // Return the source line.
+  var start = line == 0 ? 0 : this.line_ends[line - 1] + 1;
+  var end = this.line_ends[line];
    return this.source.substring(start, end);
  }

@@ -410,11 +376,8 @@
   *     Number of source lines.
   */
  Script.prototype.lineCount = function() {
-  // Make soure source info has been initialized.
-  this.initSourceInfo_();
-
-  // Return number of source lines.
-  return this.lineEnds_.length;
+  // Return number of source lines.
+  return this.line_ends.length;
  };


@@ -430,7 +393,7 @@
   * Source text for the source context is the character interval [start,  
end[. In
   * most cases end will point to a newline character. It might point just  
past
   * the final position of the source if the last source line does not end  
with a
- * newline character.
+ * newline character.
   * @param {Script} script The Script object for which this is a location
   * @param {number} position Source position for the location
   * @param {number} line The line number for the location

Modified: branches/bleeding_edge/src/objects.cc
==============================================================================
--- branches/bleeding_edge/src/objects.cc       (original)
+++ branches/bleeding_edge/src/objects.cc       Wed Feb  4 04:07:45 2009
@@ -6781,45 +6781,53 @@

    Handle<String> src(String::cast(source()));
    const int src_len = src->length();
-  Handle<JSArray> array = Factory::NewJSArray(0);
-  int array_index = 0;
    Handle<String> new_line = Factory::NewStringFromAscii(CStrVector("\n"));
+
+  // Pass 1: Identify line count
+  int line_count = 0;
    int position = 0;
-  while (position < src_len) {
+  while (position != -1 && position < src_len) {
      position = Runtime::StringMatch(src, new_line, position);
      if (position != -1) {
-      SetElement(array, array_index++,  
Handle<Smi>(Smi::FromInt(position++)));
-    } else {
-      break;
+      position++;
      }
+    // Even if the last line misses a line end, it is counted
+    line_count++;
    }

-  // If the script does not end with a line ending add the final end  
position
-  // as just past the last line ending.
-  if (array_index == 0 ||
-      (Smi::cast(array->GetElement(array_index - 1))->value() != src_len -  
1)) {
-    SetElement(array, array_index++, Handle<Smi>(Smi::FromInt(src_len)));
+  // Pass 2: Fill in line ends positions
+  Handle<FixedArray> array = Factory::NewFixedArray(line_count);
+  int array_index = 0;
+  position = 0;
+  while (position != -1 && position < src_len) {
+    position = Runtime::StringMatch(src, new_line, position);
+    // If the script does not end with a line ending add the final end  
position
+    // as just past the last line ending.
+    array->set(array_index++,
+               Smi::FromInt(position != -1 ? position++ : src_len));
    }
+  ASSERT(array_index == line_count);

-  Handle<FixedArray> fixed_array = Factory::NewFixedArray(0);
-  set_line_ends(*AddKeysFromJSArray(fixed_array, array));
-  ASSERT(line_ends()->IsFixedArray());
+  Handle<JSArray> object = Factory::NewJSArrayWithElements(array);
+  set_line_ends(*object);
+  ASSERT(line_ends()->IsJSArray());
  }


  // Convert code position into line number
  int Script::GetLineNumber(int code_pos) {
    InitLineEnds();
-  FixedArray* line_ends_array = FixedArray::cast(line_ends());
+  JSArray* line_ends_array = JSArray::cast(line_ends());
+  const int line_ends_len =  
(Smi::cast(line_ends_array->length()))->value();

    int line = -1;
-  if (code_pos <= (Smi::cast(line_ends_array->get(0)))->value()) {
+  if (line_ends_len > 0 &&
+      code_pos <= (Smi::cast(line_ends_array->GetElement(0)))->value()) {
      line = 0;
    } else {
-    const int line_ends_length = line_ends_array->length();
-    for (int i = 1; i < line_ends_length; ++i) {
-      if ((Smi::cast(line_ends_array->get(i - 1)))->value() < code_pos &&
-          code_pos <= (Smi::cast(line_ends_array->get(i)))->value()) {
+    for (int i = 1; i < line_ends_len; ++i) {
+      if ((Smi::cast(line_ends_array->GetElement(i - 1)))->value() <  
code_pos &&
+          code_pos <=  
(Smi::cast(line_ends_array->GetElement(i)))->value()) {
          line = i;
          break;
        }

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to