Commit 3e2712e0 authored by lrn@chromium.org's avatar lrn@chromium.org

Lots of small optimizations, and one that is measurable (speeds up celtickane-array signficantly).


git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1276 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 5344151e
......@@ -620,7 +620,11 @@ function ArraySort(comparefn) {
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 ArraySort(comparefn) {
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 @@ function ArraySort(comparefn) {
// 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 ArraySort(comparefn) {
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 @@ function ArrayFilter(f, receiver) {
// 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;
......
......@@ -1156,12 +1156,20 @@ void CodeGenerator::SmiOperation(Token::Value op,
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, deferred->enter(), not_taken);
if (op == Token::BIT_AND) {
__ and_(Operand(eax), Immediate(value));
if (int_value == 0) {
__ xor_(Operand(eax), eax);
} else {
__ and_(Operand(eax), Immediate(value));
}
} else if (op == Token::BIT_XOR) {
__ xor_(Operand(eax), Immediate(value));
if (int_value != 0) {
__ xor_(Operand(eax), Immediate(value));
}
} else {
ASSERT(op == Token::BIT_OR);
__ or_(Operand(eax), Immediate(value));
if (int_value != 0) {
__ or_(Operand(eax), Immediate(value));
}
}
__ bind(deferred->exit());
frame_->Push(eax);
......@@ -3268,6 +3276,23 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
__ CallRuntime(Runtime::kTypeof, 1);
frame_->Push(eax);
} 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(Immediate(Factory::undefined_value()));
} else {
Load(node->expression());
__ mov(frame_->Top(), Factory::undefined_value());
}
} else {
Load(node->expression());
switch (op) {
......@@ -3306,10 +3331,6 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
break;
}
case Token::VOID:
__ mov(frame_->Top(), Factory::undefined_value());
break;
case Token::ADD: {
// Smi check.
Label continue_label;
......
......@@ -232,7 +232,7 @@ function TimeInYear(year) {
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 @@ function CalculateDateTable() {
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 @@ function DayTriplet(year, month, date) {
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 @@ function FromJulianDay(julian) {
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;
}
......
......@@ -62,10 +62,14 @@ function StringValueOf() {
// 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 @@ function StringMatch(regexp) {
// 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 @@ function ExpandReplacement(string, subject, captures, builder) {
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 @@ function ExpandReplacement(string, subject, captures, builder) {
++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 @@ function addCaptureString(builder, captures, index) {
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 @@ function ApplyReplacementFunction(replace, captures, subject) {
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);
......
......@@ -81,11 +81,11 @@ function GlobalParseInt(string, radix) {
// 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);
......
......@@ -42,6 +42,20 @@ assertEquals(date0, date1);
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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment