Commit 5058924d authored by bak@chromium.org's avatar bak@chromium.org

- Added %IsArrayClass, %IsDateClass, and %IsStringClass.

- Added the FLOOR macro that only works on Number objects.
- Added LocalTimeNoCheck in the date code to eliminate some isNaN checks.
- Change computation of four_year_cycle_table to load time.
- Added fast case check to EQUALS and STRICT_EQUALS.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@458 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 734328bd
......@@ -43,7 +43,7 @@ const $Date = global.Date;
// ECMA 262 - 15.9.1.2
function Day(time) {
return $floor(time/msPerDay);
return FLOOR(time/msPerDay);
}
......@@ -69,9 +69,9 @@ function DaysInYear(year) {
function DayFromYear(year) {
return 365 * (year-1970)
+ $floor((year-1969)/4)
- $floor((year-1901)/100)
+ $floor((year-1601)/400);
+ FLOOR((year-1969)/4)
- FLOOR((year-1901)/100)
+ FLOOR((year-1601)/400);
}
......@@ -170,6 +170,10 @@ function LocalTime(time) {
return time + local_time_offset + DaylightSavingsOffset(time);
}
function LocalTimeNoCheck(time) {
return time + local_time_offset + DaylightSavingsOffset(time);
}
function UTC(time) {
if ($isNaN(time)) return time;
......@@ -180,17 +184,17 @@ function UTC(time) {
// ECMA 262 - 15.9.1.10
function HourFromTime(time) {
return Modulo($floor(time / msPerHour), HoursPerDay);
return Modulo(FLOOR(time / msPerHour), HoursPerDay);
}
function MinFromTime(time) {
return Modulo($floor(time / msPerMinute), MinutesPerHour);
return Modulo(FLOOR(time / msPerMinute), MinutesPerHour);
}
function SecFromTime(time) {
return Modulo($floor(time / msPerSecond), SecondsPerMinute);
return Modulo(FLOOR(time / msPerSecond), SecondsPerMinute);
}
......@@ -223,12 +227,11 @@ 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);
return $floor($floor(365.25*jy) + $floor(30.6001*jm) + date + 1720995) + 2 - ja + $floor(0.25*ja);
var ja = FLOOR(0.01*jy);
return FLOOR(FLOOR(365.25*jy) + FLOOR(30.6001*jm) + date + 1720995) + 2 - ja + FLOOR(0.25*ja);
}
var four_year_cycle_table;
var four_year_cycle_table = CalculateDateTable();
function CalculateDateTable() {
......@@ -261,7 +264,6 @@ function CalculateDateTable() {
}
// Constructor for creating objects holding year, month, and date.
// Introduced to ensure the two return points in FromJulianDay match same map.
function DayTriplet(year, month, date) {
......@@ -279,8 +281,6 @@ function FromJulianDay(julian) {
// when doing the multiply-to-divide trick.
if (julian > kDayZeroInJulianDay &&
(julian - kDayZeroInJulianDay) < 40177) { // 1970 - 2080
if (!four_year_cycle_table)
four_year_cycle_table = CalculateDateTable();
var jsimple = (julian - kDayZeroInJulianDay) + 731; // Day 0 is 1st January 1968
var y = 1968;
// Divide by 1461 by multiplying with 22967 and shifting down by 25!
......@@ -292,19 +292,20 @@ function FromJulianDay(julian) {
(four_year_cycle & kMonthMask) >> kMonthShift,
four_year_cycle & kDayMask);
}
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 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);
var d = jb - jd - FLOOR(30.6001 * je);
return new DayTriplet(y, m, d);
}
// Compute number of days given a year, month, date.
// Note that month and date can lie outside the normal range.
// For example:
......@@ -320,7 +321,7 @@ function MakeDay(year, month, date) {
date = TO_INTEGER(date);
// Overflow months into year.
year = year + $floor(month/12);
year = year + FLOOR(month/12);
month = month % 12;
if (month < 0) {
month += 12;
......@@ -400,7 +401,7 @@ function GetTimeFrom(aDate) {
function GetMillisecondsFrom(aDate) {
var t = GetTimeFrom(aDate);
if ($isNaN(t)) return t;
return msFromTime(LocalTime(t));
return msFromTime(LocalTimeNoCheck(t));
}
......@@ -414,7 +415,7 @@ function GetUTCMillisecondsFrom(aDate) {
function GetSecondsFrom(aDate) {
var t = GetTimeFrom(aDate);
if ($isNaN(t)) return t;
return SecFromTime(LocalTime(t));
return SecFromTime(LocalTimeNoCheck(t));
}
......@@ -428,7 +429,7 @@ function GetUTCSecondsFrom(aDate) {
function GetMinutesFrom(aDate) {
var t = GetTimeFrom(aDate);
if ($isNaN(t)) return t;
return MinFromTime(LocalTime(t));
return MinFromTime(LocalTimeNoCheck(t));
}
......@@ -442,7 +443,7 @@ function GetUTCMinutesFrom(aDate) {
function GetHoursFrom(aDate) {
var t = GetTimeFrom(aDate);
if ($isNaN(t)) return t;
return HourFromTime(LocalTime(t));
return HourFromTime(LocalTimeNoCheck(t));
}
......@@ -456,7 +457,7 @@ function GetUTCHoursFrom(aDate) {
function GetFullYearFrom(aDate) {
var t = GetTimeFrom(aDate);
if ($isNaN(t)) return t;
return YearFromTime(LocalTime(t));
return YearFromTime(LocalTimeNoCheck(t));
}
......@@ -470,7 +471,7 @@ function GetUTCFullYearFrom(aDate) {
function GetMonthFrom(aDate) {
var t = GetTimeFrom(aDate);
if ($isNaN(t)) return t;
return MonthFromTime(LocalTime(t));
return MonthFromTime(LocalTimeNoCheck(t));
}
......@@ -484,7 +485,7 @@ function GetUTCMonthFrom(aDate) {
function GetDateFrom(aDate) {
var t = GetTimeFrom(aDate);
if ($isNaN(t)) return t;
return DateFromTime(LocalTime(t));
return DateFromTime(LocalTimeNoCheck(t));
}
......@@ -526,8 +527,8 @@ function TimeString(time) {
function LocalTimezoneString(time) {
var timezoneOffset = (local_time_offset + DaylightSavingsOffset(time)) / msPerMinute;
var sign = (timezoneOffset >= 0) ? 1 : -1;
var hours = $floor((sign * timezoneOffset)/60);
var min = $floor((sign * timezoneOffset)%60);
var hours = FLOOR((sign * timezoneOffset)/60);
var min = FLOOR((sign * timezoneOffset)%60);
var gmt = ' GMT' + ((sign == 1) ? '+' : '-') + TwoDigitString(hours) + TwoDigitString(min);
return gmt + ' (' + LocalTimezone(time) + ')';
}
......@@ -586,7 +587,7 @@ function DateNow() {
function DateToString() {
var t = GetTimeFrom(this);
if ($isNaN(t)) return kInvalidDate;
return DatePrintString(LocalTime(t)) + LocalTimezoneString(t);
return DatePrintString(LocalTimeNoCheck(t)) + LocalTimezoneString(t);
}
......@@ -594,7 +595,7 @@ function DateToString() {
function DateToDateString() {
var t = GetTimeFrom(this);
if ($isNaN(t)) return kInvalidDate;
return DateString(LocalTime(t));
return DateString(LocalTimeNoCheck(t));
}
......@@ -602,7 +603,7 @@ function DateToDateString() {
function DateToTimeString() {
var t = GetTimeFrom(this);
if ($isNaN(t)) return kInvalidDate;
var lt = LocalTime(t);
var lt = LocalTimeNoCheck(t);
return TimeString(lt) + LocalTimezoneString(lt);
}
......@@ -623,7 +624,7 @@ function DateToLocaleDateString() {
function DateToLocaleTimeString() {
var t = GetTimeFrom(this);
if ($isNaN(t)) return kInvalidDate;
var lt = LocalTime(t);
var lt = LocalTimeNoCheck(t);
return TimeString(lt);
}
......@@ -680,7 +681,7 @@ function DateGetUTCDate() {
function DateGetDay() {
var t = GetTimeFrom(this);
if ($isNaN(t)) return t;
return WeekDay(LocalTime(t));
return WeekDay(LocalTimeNoCheck(t));
}
......@@ -744,7 +745,7 @@ function DateGetUTCMilliseconds() {
function DateGetTimezoneOffset() {
var t = GetTimeFrom(this);
if ($isNaN(t)) return t;
return (t - LocalTime(t)) / msPerMinute;
return (t - LocalTimeNoCheck(t)) / msPerMinute;
}
......@@ -884,7 +885,7 @@ function DateSetUTCMonth(month, date) {
// ECMA 262 - 15.9.5.40
function DateSetFullYear(year, month, date) {
var t = GetTimeFrom(this);
t = $isNaN(t) ? 0 : LocalTime(t);
t = $isNaN(t) ? 0 : LocalTimeNoCheck(t);
year = ToNumber(year);
var argc = %_ArgumentsLength();
month = argc < 2 ? MonthFromTime(t) : ToNumber(month);
......@@ -924,7 +925,7 @@ function DateToUTCString() {
function DateGetYear() {
var t = GetTimeFrom(this);
if ($isNaN(t)) return $NaN;
return YearFromTime(LocalTime(t)) - 1900;
return YearFromTime(LocalTimeNoCheck(t)) - 1900;
}
......
......@@ -154,6 +154,8 @@ namespace v8 { namespace internal {
V(object_symbol, "object") \
V(prototype_symbol, "prototype") \
V(string_symbol, "string") \
V(String_symbol, "String") \
V(Date_symbol, "Date") \
V(this_symbol, "this") \
V(to_string_symbol, "toString") \
V(char_at_symbol, "CharAt") \
......
......@@ -79,10 +79,11 @@ macro IS_STRING(arg) = (typeof(arg) === 'string');
macro IS_OBJECT(arg) = (typeof(arg) === 'object');
macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean');
macro IS_REGEXP(arg) = (%ClassOf(arg) === 'RegExp');
macro IS_ARRAY(arg) = (%ClassOf(arg) === 'Array');
macro IS_DATE(arg) = (%ClassOf(arg) === 'Date');
macro IS_ARRAY(arg) = %IsArrayClass(arg);
macro IS_DATE(arg) = %IsDateClass(arg);
macro IS_ERROR(arg) = (%ClassOf(arg) === 'Error');
macro IS_SCRIPT(arg) = (%ClassOf(arg) === 'Script');
macro FLOOR(arg) = %Math_floor(arg);
# Inline macros. Use %IS_VAR to make sure arg is evaluated only once.
macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg));
......
......@@ -221,6 +221,30 @@ static Object* Runtime_ClassOf(Arguments args) {
return JSObject::cast(obj)->class_name();
}
inline static Object* IsSpecificClassOf(Arguments args, String* name) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
Object* obj = args[0];
if (obj->IsJSObject() && (JSObject::cast(obj)->class_name() == name)) {
return Heap::true_value();
}
return Heap::false_value();
}
static Object* Runtime_IsStringClass(Arguments args) {
return IsSpecificClassOf(args, Heap::String_symbol());
}
static Object* Runtime_IsDateClass(Arguments args) {
return IsSpecificClassOf(args, Heap::Date_symbol());
}
static Object* Runtime_IsArrayClass(Arguments args) {
return IsSpecificClassOf(args, Heap::Array_symbol());
}
static Object* Runtime_IsInPrototypeChain(Arguments args) {
NoHandleAllocation ha;
......@@ -2508,8 +2532,12 @@ static Object* Runtime_StringEquals(Arguments args) {
int len = x->length();
if (len != y->length()) return Smi::FromInt(NOT_EQUAL);
if (len == 0) return Smi::FromInt(EQUAL);
// Fast case: First, middle and last characters.
// Handle one elment strings.
if (x->Get(0) != y->Get(0)) return Smi::FromInt(NOT_EQUAL);
if (len == 1) return Smi::FromInt(EQUAL);
// Fast case: First, middle and last characters.
if (x->Get(len>>1) != y->Get(len>>1)) return Smi::FromInt(NOT_EQUAL);
if (x->Get(len - 1) != y->Get(len - 1)) return Smi::FromInt(NOT_EQUAL);
......
......@@ -164,6 +164,9 @@ namespace v8 { namespace internal {
F(GetScript, 1) \
\
F(ClassOf, 1) \
F(IsDateClass, 1) \
F(IsStringClass, 1) \
F(IsArrayClass, 1) \
F(SetCode, 2) \
\
F(CreateApiFunction, 1) \
......
......@@ -52,36 +52,31 @@ const $NaN = 0/0;
// ECMA-262, section 11.9.1, page 55.
function EQUALS(y) {
if (IS_STRING(this) && IS_STRING(y)) return %StringEquals(this, y);
var x = this;
// NOTE: We use iteration instead of recursion, because it is
// difficult to call EQUALS with the correct setting of 'this' in
// an efficient way.
while (true) {
if (IS_NUMBER(x)) {
if (y == null) return 1; // not equal
return %NumberEquals(x, %ToNumber(y));
} else if (IS_STRING(x)) {
if (IS_STRING(y)) return %StringEquals(x, y);
if (IS_NUMBER(y)) return %NumberEquals(%ToNumber(x), y);
if (IS_BOOLEAN(y)) return %NumberEquals(%ToNumber(x), %ToNumber(y));
if (y == null) return 1; // not equal
y = %ToPrimitive(y, NO_HINT);
} else if (IS_BOOLEAN(x)) {
if (IS_BOOLEAN(y)) {
return %_ObjectEquals(x, y) ? 0 : 1;
}
if (y == null) return 1; // not equal
return %NumberEquals(%ToNumber(x), %ToNumber(y));
} else if (x == null) {
// NOTE: This checks for both null and undefined.
return (y == null) ? 0 : 1;
} else {
if (IS_OBJECT(y)) {
return %_ObjectEquals(x, y) ? 0 : 1;
......@@ -90,12 +85,10 @@ function EQUALS(y) {
return %_ObjectEquals(x, y) ? 0 : 1;
}
x = %ToPrimitive(x, NO_HINT);
}
}
}
// ECMA-262, section 11.9.4, page 56.
function STRICT_EQUALS(x) {
if (IS_NUMBER(this)) {
......@@ -125,11 +118,15 @@ function STRICT_EQUALS(x) {
// ECMA-262, section 11.8.5, page 53. The 'ncr' parameter is used as
// the result when either (or both) the operands are NaN.
function COMPARE(x, ncr) {
// Improve performance for floating point compares
// Fast case for numbers and strings.
if (IS_NUMBER(this) && IS_NUMBER(x)) {
return %NumberCompare(this, x, ncr);
}
if (IS_STRING(this) && IS_STRING(x)) {
return %StringCompare(this, x);
}
// Default implementation.
var a = %ToPrimitive(this, NUMBER_HINT);
var b = %ToPrimitive(x, NUMBER_HINT);
if (IS_STRING(a) && IS_STRING(b)) {
......@@ -149,10 +146,10 @@ function COMPARE(x, ncr) {
// ECMA-262, section 11.6.1, page 50.
function ADD(x) {
// Fast case: Check for number operands and do the addition.
if (IS_NUMBER(this) && IS_NUMBER(x)) {
return %NumberAdd(this, x);
}
if (IS_NUMBER(this) && IS_NUMBER(x)) return %NumberAdd(this, x);
if (IS_STRING(this) && IS_STRING(x)) return %StringAdd(this, x);
// Default implementation.
var a = %ToPrimitive(this, NO_HINT);
var b = %ToPrimitive(x, NO_HINT);
......@@ -397,6 +394,10 @@ function TO_STRING() {
// ECMA-262, section 9.1, page 30. Use null/undefined for no hint,
// (1) for number hint, and (2) for string hint.
function ToPrimitive(x, hint) {
// Fast case check.
if (IS_STRING(x)) return x;
if ((hint != NUMBER_HINT) && %IsStringClass(x)) return %_ValueOf(x);
// Normal behaior.
if (!IS_OBJECT(x) && !IS_FUNCTION(x)) return x;
if (x == null) return x; // check for null, undefined
if (hint == NO_HINT) hint = (IS_DATE(x)) ? STRING_HINT : NUMBER_HINT;
......
......@@ -46,7 +46,7 @@
// ECMA-262 section 15.5.4.2
function StringToString() {
if (!IS_STRING(this) && %ClassOf(this) !== 'String')
if (!IS_STRING(this) && !%IsStringClass(this))
throw new $TypeError('String.prototype.toString is not generic');
return %_ValueOf(this);
}
......@@ -54,7 +54,7 @@ function StringToString() {
// ECMA-262 section 15.5.4.3
function StringValueOf() {
if (!IS_STRING(this) && %ClassOf(this) !== 'String')
if (!IS_STRING(this) && !%IsStringClass(this))
throw new $TypeError('String.prototype.valueOf is not generic');
return %_ValueOf(this);
}
......
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