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