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
-~----------~----~----~----~------~----~------~--~---