- 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
This commit is contained in:
parent
734328bdd9
commit
5058924d85
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user