Author: [email protected]
Date: Thu Feb 19 04:35:50 2009
New Revision: 1315

Modified:
    branches/experimental/toiger/   (props changed)
    branches/experimental/toiger/src/array.js
    branches/experimental/toiger/src/codegen-ia32.cc
    branches/experimental/toiger/src/date-delay.js
    branches/experimental/toiger/src/regexp-macro-assembler-irregexp-inl.h    
(props changed)
    branches/experimental/toiger/src/string.js
    branches/experimental/toiger/src/v8natives.js
    branches/experimental/toiger/test/mjsunit/date.js

Log:
Experimental: port bleeding_edge r1276 (a grab bag of optimizations)
to the code generator branch.  The only file that really needs to be
looked at is codegen-ia32.cc.  The others were merged by svn without
issue.

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

Modified: branches/experimental/toiger/src/array.js
==============================================================================
--- branches/experimental/toiger/src/array.js   (original)
+++ branches/experimental/toiger/src/array.js   Thu Feb 19 04:35:50 2009
@@ -620,7 +620,11 @@
    var custom_compare = IS_FUNCTION(comparefn);

    function Compare(x,y) {
+    // Assume the comparefn, if any, is a consistent comparison function.
+    // If it isn't, we are allowed arbitrary behavior by ECMA 15.4.4.11.
+    if (x === y) return 0;
      if (custom_compare) {
+      // Don't call directly to avoid exposing the builtin's global object.
        return comparefn.call(null, x, y);
      }
      if (%_IsSmi(x) && %_IsSmi(y)) {
@@ -635,6 +639,10 @@
    function InsertionSort(a, from, to) {
      for (var i = from + 1; i < to; i++) {
        var element = a[i];
+      // Pre-convert the element to a string for comparison if we know
+      // it will happen on each compare anyway.
+      var key =
+          (custom_compare || %_IsSmi(element)) ? element :  
ToString(element);
        // place element in a[from..i[
        // binary search
        var min = from;
@@ -642,7 +650,7 @@
        // The search interval is a[min..max[
        while (min < max) {
          var mid = min + ((max - min) >> 1);
-        var order = Compare(a[mid], element);
+        var order = Compare(a[mid], key);
          if (order == 0) {
            min = max = mid;
            break;
@@ -663,43 +671,49 @@

    function QuickSort(a, from, to) {
      // Insertion sort is faster for short arrays.
-    if (to - from <= 22) {
+    if (to - from <= 22) {
        InsertionSort(a, from, to);
        return;
      }
      var pivot_index = $floor($random() * (to - from)) + from;
      var pivot = a[pivot_index];
+    // Pre-convert the element to a string for comparison if we know
+    // it will happen on each compare anyway.
+    var pivot_key =
+      (custom_compare || %_IsSmi(pivot)) ? pivot : ToString(pivot);
      // Issue 95: Keep the pivot element out of the comparisons to avoid
      // infinite recursion if comparefn(pivot, pivot) != 0.
-    a[pivot_index] = a[to - 1];
-    a[to - 1] = pivot;
-    var low_end = from;   // Upper bound of the elements lower than pivot.
-    var high_start = to - 1; // Lower bound of the elements greater than  
pivot.
-    for (var i = from; i < high_start; ) {
-      var element = a[i];
-      var order = Compare(element, pivot);
+    var low_end = from; // Upper bound of the elements lower than pivot.
+    var high_start = to; // Lower bound of the elements greater than pivot.
+    var eq_start = to - 1; // Lower bound of elements equal to pivot.
+    a[pivot_index] = a[eq_start];
+    a[eq_start] = pivot;
+    // From eq_start to high_start are elements equal to the pivot
+    // (including the pivot).
+    // From low_end to eq_start are elements that have not been compared  
yet.
+    while (low_end < eq_start) {
+      var element = a[low_end];
+      var order = Compare(element, pivot_key);
        if (order < 0) {
-        a[i] = a[low_end];
-        a[low_end] = element;
          low_end++;
-        i++;
        } else if (order > 0) {
+        eq_start--;
          high_start--;
-        a[i] = a[high_start];
+        a[low_end] = a[eq_start];
+        a[eq_start] = a[high_start];
          a[high_start] = element;
-      } else { // order == 0
-        i++;
+      } else {  // order == 0
+        eq_start--;
+        a[low_end] = a[eq_start];
+        a[eq_start] = element;
        }
      }
-    // Restore the pivot element to its rightful place.
-    a[to - 1] = a[high_start];
-    a[high_start] = pivot;
-    high_start++;
      QuickSort(a, from, low_end);
      QuickSort(a, high_start, to);
    }

    var old_length = ToUint32(this.length);
+  if (old_length < 2) return this;

    %RemoveArrayHoles(this);

@@ -741,10 +755,11 @@
    // loop will not affect the looping.
    var length = this.length;
    var result = [];
+  var result_length = 0;
    for (var i = 0; i < length; i++) {
      var current = this[i];
      if (!IS_UNDEFINED(current) || i in this) {
-      if (f.call(receiver, current, i, this)) result.push(current);
+      if (f.call(receiver, current, i, this)) result[result_length++] =  
current;
      }
    }
    return result;

Modified: branches/experimental/toiger/src/codegen-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/codegen-ia32.cc    (original)
+++ branches/experimental/toiger/src/codegen-ia32.cc    Thu Feb 19 04:35:50  
2009
@@ -1190,12 +1190,20 @@
        deferred->enter()->Branch(not_zero, &operand, not_taken);
        frame_->Spill(operand.reg());
        if (op == Token::BIT_AND) {
-        __ and_(Operand(operand.reg()), Immediate(value));
+        if (int_value == 0) {
+          __ xor_(Operand(operand.reg()), operand.reg());
+        } else {
+          __ and_(Operand(operand.reg()), Immediate(value));
+        }
        } else if (op == Token::BIT_XOR) {
-        __ xor_(Operand(operand.reg()), Immediate(value));
+        if (int_value != 0) {
+          __ xor_(Operand(operand.reg()), Immediate(value));
+        }
        } else {
          ASSERT(op == Token::BIT_OR);
-        __ or_(Operand(operand.reg()), Immediate(value));
+        if (int_value != 0) {
+          __ or_(Operand(operand.reg()), Immediate(value));
+        }
        }
        deferred->BindExit(&operand);
        frame_->Push(&operand);
@@ -4091,6 +4099,23 @@
      Result answer = frame_->CallRuntime(Runtime::kTypeof, 1);
      frame_->Push(&answer);

+  } else if (op == Token::VOID) {
+    Expression* expression = node->expression();
+    if (expression && expression->AsLiteral() && (
+        expression->AsLiteral()->IsTrue() ||
+        expression->AsLiteral()->IsFalse() ||
+        expression->AsLiteral()->handle()->IsNumber() ||
+        expression->AsLiteral()->handle()->IsString() ||
+        expression->AsLiteral()->handle()->IsJSRegExp() ||
+        expression->AsLiteral()->IsNull())) {
+      // Omit evaluating the value of the primitive literal.
+      // It will be discarded anyway, and can have no side effect.
+      frame_->Push(Factory::undefined_value());
+    } else {
+      Load(node->expression());
+      frame_->SetElementAt(0, Factory::undefined_value());
+    }
+
    } else {
      Load(node->expression());
      switch (op) {
@@ -4131,11 +4156,6 @@
          __ and_(answer.reg(), ~kSmiTagMask);  // Remove inverted smi-tag.
          continue_label.Bind(&answer);
          frame_->Push(&answer);
-        break;
-      }
-
-      case Token::VOID: {
-        frame_->SetElementAt(0, Factory::undefined_value());
          break;
        }


Modified: branches/experimental/toiger/src/date-delay.js
==============================================================================
--- branches/experimental/toiger/src/date-delay.js      (original)
+++ branches/experimental/toiger/src/date-delay.js      Thu Feb 19 04:35:50 2009
@@ -232,7 +232,7 @@
  function ToJulianDay(year, month, date) {
    var jy = (month > 1) ? year : year - 1;
    var jm = (month > 1) ? month + 2 : month + 14;
-  var ja = FLOOR(0.01*jy);
+  var ja = FLOOR(jy / 100);
    return FLOOR(FLOOR(365.25*jy) + FLOOR(30.6001*jm) + date + 1720995) + 2  
- ja + FLOOR(0.25*ja);
  }

@@ -247,22 +247,22 @@
    var position = 0;
    var leap_position = 0;
    for (var month = 0; month < 12; month++) {
+    var month_bits = month << kMonthShift;
      var length = month_lengths[month];
      for (var day = 1; day <= length; day++) {
        four_year_cycle_table[leap_position] =
-        (month << kMonthShift) + day;
+        month_bits + day;
        four_year_cycle_table[366 + position] =
-        (1 << kYearShift) + (month << kMonthShift) + day;
+        (1 << kYearShift) + month_bits + day;
        four_year_cycle_table[731 + position] =
-        (2 << kYearShift) + (month << kMonthShift) + day;
+        (2 << kYearShift) + month_bits + day;
        four_year_cycle_table[1096 + position] =
-        (3 << kYearShift) + (month << kMonthShift) + day;
+        (3 << kYearShift) + month_bits + day;
        leap_position++;
        position++;
      }
      if (month == 1) {
-      four_year_cycle_table[leap_position++] =
-        (month << kMonthShift) + 29;
+      four_year_cycle_table[leap_position++] = month_bits + 29;
      }
    }
    return four_year_cycle_table;
@@ -277,10 +277,16 @@
    this.date = date;
  }

+var julian_day_cache_triplet;
+var julian_day_cache_day = $NaN;

  // Compute year, month, and day from modified Julian day.
  // The missing days in 1582 are ignored for JavaScript compatibility.
  function FromJulianDay(julian) {
+  if (julian_day_cache_day == julian) {
+    return julian_day_cache_triplet;
+  }
+  var result;
    // Avoid floating point and non-Smi maths in common case.  This is also  
a period of
    // time where leap years are very regular.  The range is not too large  
to avoid overflow
    // when doing the multiply-to-divide trick.
@@ -293,21 +299,25 @@
      y += after_1968 << 2;
      jsimple -= 1461 * after_1968;
      var four_year_cycle = four_year_cycle_table[jsimple];
-    return new DayTriplet(y + (four_year_cycle >> kYearShift),
-                           (four_year_cycle & kMonthMask) >> kMonthShift,
-                           four_year_cycle & kDayMask);
+    result = new DayTriplet(y + (four_year_cycle >> kYearShift),
+                            (four_year_cycle & kMonthMask) >> kMonthShift,
+                            four_year_cycle & kDayMask);
+  } else {
+    var jalpha = FLOOR((julian - 1867216.25) / 36524.25);
+    var jb = julian + 1 + jalpha - FLOOR(0.25 * jalpha) + 1524;
+    var jc = FLOOR(6680.0 + ((jb-2439870) - 122.1)/365.25);
+    var jd = FLOOR(365 * jc + (0.25 * jc));
+    var je = FLOOR((jb - jd)/30.6001);
+    var m = je - 1;
+    if (m > 12) m -= 13;
+    var y = jc - 4715;
+    if (m > 2) { --y; --m; }
+    var d = jb - jd - FLOOR(30.6001 * je);
+    result = new DayTriplet(y, m, d);
    }
-  var jalpha = FLOOR((julian - 1867216.25) / 36524.25);
-  var jb = julian + 1 + jalpha - FLOOR(0.25 * jalpha) + 1524;
-  var jc = FLOOR(6680.0 + ((jb-2439870) - 122.1)/365.25);
-  var jd = FLOOR(365 * jc + (0.25 * jc));
-  var je = FLOOR((jb - jd)/30.6001);
-  var m = je - 1;
-  if (m > 12) m -= 13;
-  var y = jc - 4715;
-  if (m > 2) { --y; --m; }
-  var d = jb - jd - FLOOR(30.6001 * je);
-  return new DayTriplet(y, m, d);
+  julian_day_cache_day = julian;
+  julian_day_cache_triplet = result;
+  return result;
  }



Modified: branches/experimental/toiger/src/string.js
==============================================================================
--- branches/experimental/toiger/src/string.js  (original)
+++ branches/experimental/toiger/src/string.js  Thu Feb 19 04:35:50 2009
@@ -62,10 +62,14 @@

  // ECMA-262, section 15.5.4.4
  function StringCharAt(pos) {
-  var subject = ToString(this);
-  var index = TO_INTEGER(pos);
-  if (index >= subject.length || index < 0) return "";
-  return %CharFromCode(%StringCharCodeAt(subject, index));
+  var char_code = %_FastCharCodeAt(subject, index);
+  if (!%_IsSmi(char_code)) {
+    var subject = ToString(this);
+    var index = TO_INTEGER(pos);
+    if (index >= subject.length || index < 0) return "";
+    char_code = %StringCharCodeAt(subject, index);
+  }
+  return %CharFromCode(char_code);
  }


@@ -175,7 +179,13 @@
  // otherwise we call the runtime system.
  function SubString(string, start, end) {
    // Use the one character string cache.
-  if (start + 1 == end) return %CharFromCode(%StringCharCodeAt(string,  
start));
+  if (start + 1 == end) {
+    var char_code = %_FastCharCodeAt(string, start);
+    if (!%_IsSmi(char_code)) {
+      char_code = %StringCharCodeAt(string, start);
+    }
+    return %CharFromCode(char_code);
+  }
    return %StringSlice(string, start, end);
  }

@@ -280,7 +290,10 @@
      var expansion = '$';
      var position = next + 1;
      if (position < length) {
-      var peek = %StringCharCodeAt(string, position);
+      var peek = %_FastCharCodeAt(string, position);
+      if (!%_IsSmi(peek)) {
+        peek = %StringCharCodeAt(string, position);
+      }
        if (peek == 36) {         // $$
          ++position;
          builder.add('$');
@@ -297,7 +310,10 @@
          ++position;
          var n = peek - 48;
          if (position < length) {
-          peek = %StringCharCodeAt(string, position);
+          peek = %_FastCharCodeAt(string, position);
+          if (!%_IsSmi(peek)) {
+            peek = %StringCharCodeAt(string, position);
+          }
            // $nn, 01 <= nn <= 99
            if (n != 0 && peek == 48 || peek >= 49 && peek <= 57) {
              var nn = n * 10 + (peek - 48);
@@ -366,7 +382,7 @@
    var start = captures[scaled];
    var end = captures[scaled + 1];
    // If either start or end is missing return.
-  if (start < 0 || end < 0) return;
+  if (start < 0 || end <= start) return;
    builder.addSpecialSlice(start, end);
  };

@@ -437,6 +453,7 @@
    var m = captures.length >> 1;
    if (m == 1) {
      var s = CaptureString(subject, captures, 0);
+    // Don't call directly to avoid exposing the built-in global object.
      return ToString(replace.call(null, s, index, subject));
    }
    var parameters = $Array(m + 2);

Modified: branches/experimental/toiger/src/v8natives.js
==============================================================================
--- branches/experimental/toiger/src/v8natives.js       (original)
+++ branches/experimental/toiger/src/v8natives.js       Thu Feb 19 04:35:50 2009
@@ -81,11 +81,11 @@
      // non-Smi number 9 times faster (230ns vs 2070ns).  Together
      // they make parseInt on a string 1.4% slower (274ns vs 270ns).
      if (%_IsSmi(string)) return string;
-    if (IS_NUMBER(string)) {
-      if (string >= 0.01 && string < 1e9)
-        return $floor(string);
-      if (string <= -0.01 && string > -1e9)
-        return - $floor(-string);
+    if (IS_NUMBER(string) &&
+        ((string < -0.01 && -1e9 < string) ||
+            (0.01 < string && string < 1e9))) {
+      // Truncate number.
+      return string | 0;
      }
    } else {
      radix = TO_INT32(radix);

Modified: branches/experimental/toiger/test/mjsunit/date.js
==============================================================================
--- branches/experimental/toiger/test/mjsunit/date.js   (original)
+++ branches/experimental/toiger/test/mjsunit/date.js   Thu Feb 19 04:35:50  
2009
@@ -42,6 +42,20 @@
  assertEquals(date1, date2);
  assertEquals(date2, date3);

+// Test limits (+/-1e8 days from epoch)
+
+var dMax = new Date(8.64e15);
+assertEquals(8.64e15, dMax.getTime());
+
+var dOverflow = new Date(8.64e15+1);
+assertTrue(isNaN(dOverflow.getTime()));
+
+var dMin = new Date(-8.64e15);
+assertEquals(-8.64e15, dMin.getTime());
+
+var dUnderflow = new Date(-8.64e15-1);
+assertTrue(isNaN(dUnderflow.getTime()));
+

  // Tests inspired by js1_5/Date/regress-346363.js


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

Reply via email to