| @@ -0,0 +1,384 @@ | ||
| +// Copyright 2012 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +#include "date.h" | ||
| + | ||
| +#include "v8.h" | ||
| + | ||
| +#include "objects.h" | ||
| +#include "objects-inl.h" | ||
| + | ||
| +namespace v8 { | ||
| +namespace internal { | ||
| + | ||
| + | ||
| +static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1}; | ||
| +static const int kDaysIn4Years = 4 * 365 + 1; | ||
| +static const int kDaysIn100Years = 25 * kDaysIn4Years - 1; | ||
| +static const int kDaysIn400Years = 4 * kDaysIn100Years + 1; | ||
| +static const int kDays1970to2000 = 30 * 365 + 7; | ||
| +static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years - | ||
| + kDays1970to2000; | ||
| +static const int kYearsOffset = 400000; | ||
| +static const char kDaysInMonths[] = | ||
| + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | ||
| + | ||
| + | ||
| +void DateCache::ResetDateCache() { | ||
| + static const int kMaxStamp = Smi::kMaxValue; | ||
| + stamp_ = Smi::FromInt(stamp_->value() + 1); | ||
| + if (stamp_->value() > kMaxStamp) { | ||
| + stamp_ = Smi::FromInt(0); | ||
| + } | ||
| + ASSERT(stamp_ != Smi::FromInt(kInvalidStamp)); | ||
| + for (int i = 0; i < kDSTSize; ++i) { | ||
| + ClearSegment(&dst_[i]); | ||
| + } | ||
| + dst_usage_counter_ = 0; | ||
| + before_ = &dst_[0]; | ||
| + after_ = &dst_[1]; | ||
| + local_offset_ms_ = kInvalidLocalOffsetInMs; | ||
| + ymd_valid_ = false; | ||
| +} | ||
| + | ||
| + | ||
| +void DateCache::ClearSegment(DST* segment) { | ||
| + segment->start_sec = kMaxEpochTimeInSec; | ||
| + segment->end_sec = -kMaxEpochTimeInSec; | ||
| + segment->offset_ms = 0; | ||
| + segment->last_used = 0; | ||
| +} | ||
| + | ||
| + | ||
| +void DateCache::YearMonthDayFromDays( | ||
| + int days, int* year, int* month, int* day) { | ||
| + if (ymd_valid_) { | ||
| + // Check conservatively if the given 'days' has | ||
| + // the same year and month as the cached 'days'. | ||
| + int new_day = ymd_day_ + (days - ymd_days_); | ||
| + if (new_day >= 1 && new_day <= 28) { | ||
| + ymd_day_ = new_day; | ||
| + ymd_days_ = days; | ||
| + *year = ymd_year_; | ||
| + *month = ymd_month_; | ||
| + *day = new_day; | ||
| + return; | ||
| + } | ||
| + } | ||
| + int save_days = days; | ||
| + | ||
| + days += kDaysOffset; | ||
| + *year = 400 * (days / kDaysIn400Years) - kYearsOffset; | ||
| + days %= kDaysIn400Years; | ||
| + | ||
| + ASSERT(DaysFromYearMonth(*year, 0) + days == save_days); | ||
| + | ||
| + days--; | ||
| + int yd1 = days / kDaysIn100Years; | ||
| + days %= kDaysIn100Years; | ||
| + *year += 100 * yd1; | ||
| + | ||
| + days++; | ||
| + int yd2 = days / kDaysIn4Years; | ||
| + days %= kDaysIn4Years; | ||
| + *year += 4 * yd2; | ||
| + | ||
| + days--; | ||
| + int yd3 = days / 365; | ||
| + days %= 365; | ||
| + *year += yd3; | ||
| + | ||
| + | ||
| + bool is_leap = (!yd1 || yd2) && !yd3; | ||
| + | ||
| + ASSERT(days >= -1); | ||
| + ASSERT(is_leap || (days >= 0)); | ||
| + ASSERT((days < 365) || (is_leap && (days < 366))); | ||
| + ASSERT(is_leap == ((*year % 4 == 0) && (*year % 100 || (*year % 400 == 0)))); | ||
| + ASSERT(is_leap || ((DaysFromYearMonth(*year, 0) + days) == save_days)); | ||
| + ASSERT(!is_leap || ((DaysFromYearMonth(*year, 0) + days + 1) == save_days)); | ||
| + | ||
| + days += is_leap; | ||
| + | ||
| + // Check if the date is after February. | ||
| + if (days >= 31 + 28 + is_leap) { | ||
| + days -= 31 + 28 + is_leap; | ||
| + // Find the date starting from March. | ||
| + for (int i = 2; i < 12; i++) { | ||
| + if (days < kDaysInMonths[i]) { | ||
| + *month = i; | ||
| + *day = days + 1; | ||
| + break; | ||
| + } | ||
| + days -= kDaysInMonths[i]; | ||
| + } | ||
| + } else { | ||
| + // Check January and February. | ||
| + if (days < 31) { | ||
| + *month = 0; | ||
| + *day = days + 1; | ||
| + } else { | ||
| + *month = 1; | ||
| + *day = days - 31 + 1; | ||
| + } | ||
| + } | ||
| + ASSERT(DaysFromYearMonth(*year, *month) + *day - 1 == save_days); | ||
| + ymd_valid_ = true; | ||
| + ymd_year_ = *year; | ||
| + ymd_month_ = *month; | ||
| + ymd_day_ = *day; | ||
| + ymd_days_ = save_days; | ||
| +} | ||
| + | ||
| + | ||
| +int DateCache::DaysFromYearMonth(int year, int month) { | ||
| + static const int day_from_month[] = {0, 31, 59, 90, 120, 151, | ||
| + 181, 212, 243, 273, 304, 334}; | ||
| + static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152, | ||
| + 182, 213, 244, 274, 305, 335}; | ||
| + | ||
| + year += month / 12; | ||
| + month %= 12; | ||
| + if (month < 0) { | ||
| + year--; | ||
| + month += 12; | ||
| + } | ||
| + | ||
| + ASSERT(month >= 0); | ||
| + ASSERT(month < 12); | ||
| + | ||
| + // year_delta is an arbitrary number such that: | ||
| + // a) year_delta = -1 (mod 400) | ||
| + // b) year + year_delta > 0 for years in the range defined by | ||
| + // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of | ||
| + // Jan 1 1970. This is required so that we don't run into integer | ||
| + // division of negative numbers. | ||
| + // c) there shouldn't be an overflow for 32-bit integers in the following | ||
| + // operations. | ||
| + static const int year_delta = 399999; | ||
| + static const int base_day = 365 * (1970 + year_delta) + | ||
| + (1970 + year_delta) / 4 - | ||
| + (1970 + year_delta) / 100 + | ||
| + (1970 + year_delta) / 400; | ||
| + | ||
| + int year1 = year + year_delta; | ||
| + int day_from_year = 365 * year1 + | ||
| + year1 / 4 - | ||
| + year1 / 100 + | ||
| + year1 / 400 - | ||
| + base_day; | ||
| + | ||
| + if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) { | ||
| + return day_from_year + day_from_month[month]; | ||
| + } | ||
| + return day_from_year + day_from_month_leap[month]; | ||
| +} | ||
| + | ||
| + | ||
| +void DateCache::ExtendTheAfterSegment(int time_sec, int offset_ms) { | ||
| + if (after_->offset_ms == offset_ms && | ||
| + after_->start_sec <= time_sec + kDefaultDSTDeltaInSec && | ||
| + time_sec <= after_->end_sec) { | ||
| + // Extend the after_ segment. | ||
| + after_->start_sec = time_sec; | ||
| + } else { | ||
| + // The after_ segment is either invalid or starts too late. | ||
| + if (after_->start_sec <= after_->end_sec) { | ||
| + // If the after_ segment is valid, replace it with a new segment. | ||
| + after_ = LeastRecentlyUsedDST(before_); | ||
| + } | ||
| + after_->start_sec = time_sec; | ||
| + after_->end_sec = time_sec; | ||
| + after_->offset_ms = offset_ms; | ||
| + after_->last_used = ++dst_usage_counter_; | ||
| + } | ||
| +} | ||
| + | ||
| + | ||
| +int DateCache::DaylightSavingsOffsetInMs(int64_t time_ms) { | ||
| + int time_sec = (time_ms >= 0 && time_ms <= kMaxEpochTimeInMs) | ||
| + ? static_cast<int>(time_ms / 1000) | ||
| + : static_cast<int>(EquivalentTime(time_ms) / 1000); | ||
| + | ||
| + // Invalidate cache if the usage counter is close to overflow. | ||
| + // Note that dst_usage_counter is incremented less than ten times | ||
| + // in this function. | ||
| + if (dst_usage_counter_ >= kMaxInt - 10) { | ||
| + dst_usage_counter_ = 0; | ||
| + for (int i = 0; i < kDSTSize; ++i) { | ||
| + ClearSegment(&dst_[i]); | ||
| + } | ||
| + } | ||
| + | ||
| + // Optimistic fast check. | ||
| + if (before_->start_sec <= time_sec && | ||
| + time_sec <= before_->end_sec) { | ||
| + // Cache hit. | ||
| + before_->last_used = ++dst_usage_counter_; | ||
| + return before_->offset_ms; | ||
| + } | ||
| + | ||
| + ProbeDST(time_sec); | ||
| + | ||
| + ASSERT(InvalidSegment(before_) || before_->start_sec <= time_sec); | ||
| + ASSERT(InvalidSegment(after_) || time_sec < after_->start_sec); | ||
| + | ||
| + if (InvalidSegment(before_)) { | ||
| + // Cache miss. | ||
| + before_->start_sec = time_sec; | ||
| + before_->end_sec = time_sec; | ||
| + before_->offset_ms = GetDaylightSavingsOffsetFromOS(time_sec); | ||
| + before_->last_used = ++dst_usage_counter_; | ||
| + return before_->offset_ms; | ||
| + } | ||
| + | ||
| + if (time_sec <= before_->end_sec) { | ||
| + // Cache hit. | ||
| + before_->last_used = ++dst_usage_counter_; | ||
| + return before_->offset_ms; | ||
| + } | ||
| + | ||
| + if (time_sec > before_->end_sec + kDefaultDSTDeltaInSec) { | ||
| + // If the before_ segment ends too early, then just | ||
| + // query for the offset of the time_sec | ||
| + int offset_ms = GetDaylightSavingsOffsetFromOS(time_sec); | ||
| + ExtendTheAfterSegment(time_sec, offset_ms); | ||
| + // This swap helps the optimistic fast check in subsequent invocations. | ||
| + DST* temp = before_; | ||
| + before_ = after_; | ||
| + after_ = temp; | ||
| + return offset_ms; | ||
| + } | ||
| + | ||
| + // Now the time_sec is between | ||
| + // before_->end_sec and before_->end_sec + default DST delta. | ||
| + // Update the usage counter of before_ since it is going to be used. | ||
| + before_->last_used = ++dst_usage_counter_; | ||
| + | ||
| + // Check if after_ segment is invalid or starts too late. | ||
| + // Note that start_sec of invalid segments is kMaxEpochTimeInSec. | ||
| + if (before_->end_sec + kDefaultDSTDeltaInSec <= after_->start_sec) { | ||
| + int new_after_start_sec = before_->end_sec + kDefaultDSTDeltaInSec; | ||
| + int new_offset_ms = GetDaylightSavingsOffsetFromOS(new_after_start_sec); | ||
| + ExtendTheAfterSegment(new_after_start_sec, new_offset_ms); | ||
| + } else { | ||
| + ASSERT(!InvalidSegment(after_)); | ||
| + // Update the usage counter of after_ since it is going to be used. | ||
| + after_->last_used = ++dst_usage_counter_; | ||
| + } | ||
| + | ||
| + // Now the time_sec is between before_->end_sec and after_->start_sec. | ||
| + // Only one daylight savings offset change can occur in this interval. | ||
| + | ||
| + if (before_->offset_ms == after_->offset_ms) { | ||
| + // Merge two segments if they have the same offset. | ||
| + before_->end_sec = after_->end_sec; | ||
| + ClearSegment(after_); | ||
| + return before_->offset_ms; | ||
| + } | ||
| + | ||
| + // Binary search for daylight savings offset change point, | ||
| + // but give up if we don't find it in four iterations. | ||
| + for (int i = 4; i >= 0; --i) { | ||
| + int delta = after_->start_sec - before_->end_sec; | ||
| + int middle_sec = (i == 0) ? time_sec : before_->end_sec + delta / 2; | ||
| + int offset_ms = GetDaylightSavingsOffsetFromOS(middle_sec); | ||
| + if (before_->offset_ms == offset_ms) { | ||
| + before_->end_sec = middle_sec; | ||
| + if (time_sec <= before_->end_sec) { | ||
| + return offset_ms; | ||
| + } | ||
| + } else { | ||
| + ASSERT(after_->offset_ms == offset_ms); | ||
| + after_->start_sec = middle_sec; | ||
| + if (time_sec >= after_->start_sec) { | ||
| + // This swap helps the optimistic fast check in subsequent invocations. | ||
| + DST* temp = before_; | ||
| + before_ = after_; | ||
| + after_ = temp; | ||
| + return offset_ms; | ||
| + } | ||
| + } | ||
| + } | ||
| + UNREACHABLE(); | ||
| + return 0; | ||
| +} | ||
| + | ||
| + | ||
| +void DateCache::ProbeDST(int time_sec) { | ||
| + DST* before = NULL; | ||
| + DST* after = NULL; | ||
| + ASSERT(before_ != after_); | ||
| + | ||
| + for (int i = 0; i < kDSTSize; ++i) { | ||
| + if (dst_[i].start_sec <= time_sec) { | ||
| + if (before == NULL || before->start_sec < dst_[i].start_sec) { | ||
| + before = &dst_[i]; | ||
| + } | ||
| + } else if (time_sec < dst_[i].end_sec) { | ||
| + if (after == NULL || after->end_sec > dst_[i].end_sec) { | ||
| + after = &dst_[i]; | ||
| + } | ||
| + } | ||
| + } | ||
| + | ||
| + // If before or after segments were not found, | ||
| + // then set them to any invalid segment. | ||
| + if (before == NULL) { | ||
| + before = InvalidSegment(before_) ? before_ : LeastRecentlyUsedDST(after); | ||
| + } | ||
| + if (after == NULL) { | ||
| + after = InvalidSegment(after_) && before != after_ | ||
| + ? after_ : LeastRecentlyUsedDST(before); | ||
| + } | ||
| + | ||
| + ASSERT(before != NULL); | ||
| + ASSERT(after != NULL); | ||
| + ASSERT(before != after); | ||
| + ASSERT(InvalidSegment(before) || before->start_sec <= time_sec); | ||
| + ASSERT(InvalidSegment(after) || time_sec < after->start_sec); | ||
| + ASSERT(InvalidSegment(before) || InvalidSegment(after) || | ||
| + before->end_sec < after->start_sec); | ||
| + | ||
| + before_ = before; | ||
| + after_ = after; | ||
| +} | ||
| + | ||
| + | ||
| +DateCache::DST* DateCache::LeastRecentlyUsedDST(DST* skip) { | ||
| + DST* result = NULL; | ||
| + for (int i = 0; i < kDSTSize; ++i) { | ||
| + if (&dst_[i] == skip) continue; | ||
| + if (result == NULL || result->last_used > dst_[i].last_used) { | ||
| + result = &dst_[i]; | ||
| + } | ||
| + } | ||
| + ClearSegment(result); | ||
| + return result; | ||
| +} | ||
| + | ||
| +} } // namespace v8::internal |
| @@ -0,0 +1,260 @@ | ||
| +// Copyright 2012 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +#ifndef V8_DATE_H_ | ||
| +#define V8_DATE_H_ | ||
| + | ||
| +#include "allocation.h" | ||
| +#include "globals.h" | ||
| +#include "platform.h" | ||
| + | ||
| + | ||
| +namespace v8 { | ||
| +namespace internal { | ||
| + | ||
| +class DateCache { | ||
| + public: | ||
| + static const int kMsPerMin = 60 * 1000; | ||
| + static const int kSecPerDay = 24 * 60 * 60; | ||
| + static const int64_t kMsPerDay = kSecPerDay * 1000; | ||
| + | ||
| + // The largest time that can be passed to OS date-time library functions. | ||
| + static const int kMaxEpochTimeInSec = kMaxInt; | ||
| + static const int64_t kMaxEpochTimeInMs = | ||
| + static_cast<int64_t>(kMaxInt) * 1000; | ||
| + | ||
| + // The largest time that can be stored in JSDate. | ||
| + static const int64_t kMaxTimeInMs = | ||
| + static_cast<int64_t>(864000000) * 10000000; | ||
| + | ||
| + // Conservative upper bound on time that can be stored in JSDate | ||
| + // before UTC conversion. | ||
| + static const int64_t kMaxTimeBeforeUTCInMs = | ||
| + kMaxTimeInMs + 10 * kMsPerDay; | ||
| + | ||
| + // Sentinel that denotes an invalid local offset. | ||
| + static const int kInvalidLocalOffsetInMs = kMaxInt; | ||
| + // Sentinel that denotes an invalid cache stamp. | ||
| + // It is an invariant of DateCache that cache stamp is non-negative. | ||
| + static const int kInvalidStamp = -1; | ||
| + | ||
| + DateCache() : stamp_(0) { | ||
| + ResetDateCache(); | ||
| + } | ||
| + | ||
| + virtual ~DateCache() {} | ||
| + | ||
| + | ||
| + // Clears cached timezone information and increments the cache stamp. | ||
| + void ResetDateCache(); | ||
| + | ||
| + | ||
| + // Computes floor(time_ms / kMsPerDay). | ||
| + static int DaysFromTime(int64_t time_ms) { | ||
| + if (time_ms < 0) time_ms -= (kMsPerDay - 1); | ||
| + return static_cast<int>(time_ms / kMsPerDay); | ||
| + } | ||
| + | ||
| + | ||
| + // Computes modulo(time_ms, kMsPerDay) given that | ||
| + // days = floor(time_ms / kMsPerDay). | ||
| + static int TimeInDay(int64_t time_ms, int days) { | ||
| + return static_cast<int>(time_ms - days * kMsPerDay); | ||
| + } | ||
| + | ||
| + | ||
| + // Given the number of days since the epoch, computes the weekday. | ||
| + // ECMA 262 - 15.9.1.6. | ||
| + int Weekday(int days) { | ||
| + int result = (days + 4) % 7; | ||
| + return result >= 0 ? result : result + 7; | ||
| + } | ||
| + | ||
| + | ||
| + bool IsLeap(int year) { | ||
| + return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); | ||
| + } | ||
| + | ||
| + | ||
| + // ECMA 262 - 15.9.1.7. | ||
| + int LocalOffsetInMs() { | ||
| + if (local_offset_ms_ == kInvalidLocalOffsetInMs) { | ||
| + local_offset_ms_ = GetLocalOffsetFromOS(); | ||
| + } | ||
| + return local_offset_ms_; | ||
| + } | ||
| + | ||
| + | ||
| + const char* LocalTimezone(int64_t time_ms) { | ||
| + if (time_ms < 0 || time_ms > kMaxEpochTimeInMs) { | ||
| + time_ms = EquivalentTime(time_ms); | ||
| + } | ||
| + return OS::LocalTimezone(static_cast<double>(time_ms)); | ||
| + } | ||
| + | ||
| + // ECMA 262 - 15.9.5.26 | ||
| + int TimezoneOffset(int64_t time_ms) { | ||
| + int64_t local_ms = ToLocal(time_ms); | ||
| + return static_cast<int>((time_ms - local_ms) / kMsPerMin); | ||
| + } | ||
| + | ||
| + // ECMA 262 - 15.9.1.9 | ||
| + int64_t ToLocal(int64_t time_ms) { | ||
| + return time_ms + LocalOffsetInMs() + DaylightSavingsOffsetInMs(time_ms); | ||
| + } | ||
| + | ||
| + // ECMA 262 - 15.9.1.9 | ||
| + int64_t ToUTC(int64_t time_ms) { | ||
| + time_ms -= LocalOffsetInMs(); | ||
| + return time_ms - DaylightSavingsOffsetInMs(time_ms); | ||
| + } | ||
| + | ||
| + | ||
| + // Computes a time equivalent to the given time according | ||
| + // to ECMA 262 - 15.9.1.9. | ||
| + // The issue here is that some library calls don't work right for dates | ||
| + // that cannot be represented using a non-negative signed 32 bit integer | ||
| + // (measured in whole seconds based on the 1970 epoch). | ||
| + // We solve this by mapping the time to a year with same leap-year-ness | ||
| + // and same starting day for the year. The ECMAscript specification says | ||
| + // we must do this, but for compatibility with other browsers, we use | ||
| + // the actual year if it is in the range 1970..2037 | ||
| + int64_t EquivalentTime(int64_t time_ms) { | ||
| + int days = DaysFromTime(time_ms); | ||
| + int time_within_day_ms = static_cast<int>(time_ms - days * kMsPerDay); | ||
| + int year, month, day; | ||
| + YearMonthDayFromDays(days, &year, &month, &day); | ||
| + int new_days = DaysFromYearMonth(EquivalentYear(year), month) + day - 1; | ||
| + return static_cast<int64_t>(new_days) * kMsPerDay + time_within_day_ms; | ||
| + } | ||
| + | ||
| + // Returns an equivalent year in the range [2008-2035] matching | ||
| + // - leap year, | ||
| + // - week day of first day. | ||
| + // ECMA 262 - 15.9.1.9. | ||
| + int EquivalentYear(int year) { | ||
| + int week_day = Weekday(DaysFromYearMonth(year, 0)); | ||
| + int recent_year = (IsLeap(year) ? 1956 : 1967) + (week_day * 12) % 28; | ||
| + // Find the year in the range 2008..2037 that is equivalent mod 28. | ||
| + // Add 3*28 to give a positive argument to the modulus operator. | ||
| + return 2008 + (recent_year + 3 * 28 - 2008) % 28; | ||
| + } | ||
| + | ||
| + // Given the number of days since the epoch, computes | ||
| + // the corresponding year, month, and day. | ||
| + void YearMonthDayFromDays(int days, int* year, int* month, int* day); | ||
| + | ||
| + // Computes the number of days since the epoch for | ||
| + // the first day of the given month in the given year. | ||
| + int DaysFromYearMonth(int year, int month); | ||
| + | ||
| + // Cache stamp is used for invalidating caches in JSDate. | ||
| + // We increment the stamp each time when the timezone information changes. | ||
| + // JSDate objects perform stamp check and invalidate their caches if | ||
| + // their saved stamp is not equal to the current stamp. | ||
| + Smi* stamp() { return stamp_; } | ||
| + void* stamp_address() { return &stamp_; } | ||
| + | ||
| + // These functions are virtual so that we can override them when testing. | ||
| + virtual int GetDaylightSavingsOffsetFromOS(int64_t time_sec) { | ||
| + double time_ms = static_cast<double>(time_sec * 1000); | ||
| + return static_cast<int>(OS::DaylightSavingsOffset(time_ms)); | ||
| + } | ||
| + | ||
| + virtual int GetLocalOffsetFromOS() { | ||
| + double offset = OS::LocalTimeOffset(); | ||
| + ASSERT(offset < kInvalidLocalOffsetInMs); | ||
| + return static_cast<int>(offset); | ||
| + } | ||
| + | ||
| + private: | ||
| + // The implementation relies on the fact that no time zones have | ||
| + // more than one daylight savings offset change per 19 days. | ||
| + // In Egypt in 2010 they decided to suspend DST during Ramadan. This | ||
| + // led to a short interval where DST is in effect from September 10 to | ||
| + // September 30. | ||
| + static const int kDefaultDSTDeltaInSec = 19 * kSecPerDay; | ||
| + | ||
| + // Size of the Daylight Savings Time cache. | ||
| + static const int kDSTSize = 32; | ||
| + | ||
| + // Daylight Savings Time segment stores a segment of time where | ||
| + // daylight savings offset does not change. | ||
| + struct DST { | ||
| + int start_sec; | ||
| + int end_sec; | ||
| + int offset_ms; | ||
| + int last_used; | ||
| + }; | ||
| + | ||
| + // Computes the daylight savings offset for the given time. | ||
| + // ECMA 262 - 15.9.1.8 | ||
| + int DaylightSavingsOffsetInMs(int64_t time_ms); | ||
| + | ||
| + // Sets the before_ and the after_ segments from the DST cache such that | ||
| + // the before_ segment starts earlier than the given time and | ||
| + // the after_ segment start later than the given time. | ||
| + // Both segments might be invalid. | ||
| + // The last_used counters of the before_ and after_ are updated. | ||
| + void ProbeDST(int time_sec); | ||
| + | ||
| + // Finds the least recently used segment from the DST cache that is not | ||
| + // equal to the given 'skip' segment. | ||
| + DST* LeastRecentlyUsedDST(DST* skip); | ||
| + | ||
| + // Extends the after_ segment with the given point or resets it | ||
| + // if it starts later than the given time + kDefaultDSTDeltaInSec. | ||
| + inline void ExtendTheAfterSegment(int time_sec, int offset_ms); | ||
| + | ||
| + // Makes the given segment invalid. | ||
| + inline void ClearSegment(DST* segment); | ||
| + | ||
| + bool InvalidSegment(DST* segment) { | ||
| + return segment->start_sec > segment->end_sec; | ||
| + } | ||
| + | ||
| + Smi* stamp_; | ||
| + | ||
| + // Daylight Saving Time cache. | ||
| + DST dst_[kDSTSize]; | ||
| + int dst_usage_counter_; | ||
| + DST* before_; | ||
| + DST* after_; | ||
| + | ||
| + int local_offset_ms_; | ||
| + | ||
| + // Year/Month/Day cache. | ||
| + bool ymd_valid_; | ||
| + int ymd_days_; | ||
| + int ymd_year_; | ||
| + int ymd_month_; | ||
| + int ymd_day_; | ||
| +}; | ||
| + | ||
| +} } // namespace v8::internal | ||
| + | ||
| +#endif |
| @@ -0,0 +1,226 @@ | ||
| +// Copyright 2012 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +#include "v8.h" | ||
| + | ||
| +#include "interface.h" | ||
| + | ||
| +namespace v8 { | ||
| +namespace internal { | ||
| + | ||
| +static bool Match(void* key1, void* key2) { | ||
| + String* name1 = *static_cast<String**>(key1); | ||
| + String* name2 = *static_cast<String**>(key2); | ||
| + ASSERT(name1->IsSymbol()); | ||
| + ASSERT(name2->IsSymbol()); | ||
| + return name1 == name2; | ||
| +} | ||
| + | ||
| + | ||
| +Interface* Interface::Lookup(Handle<String> name) { | ||
| + ASSERT(IsModule()); | ||
| + ZoneHashMap* map = Chase()->exports_; | ||
| + if (map == NULL) return NULL; | ||
| + ZoneHashMap::Entry* p = map->Lookup(name.location(), name->Hash(), false); | ||
| + if (p == NULL) return NULL; | ||
| + ASSERT(*static_cast<String**>(p->key) == *name); | ||
| + ASSERT(p->value != NULL); | ||
| + return static_cast<Interface*>(p->value); | ||
| +} | ||
| + | ||
| + | ||
| +#ifdef DEBUG | ||
| +// Current nesting depth for debug output. | ||
| +class Nesting { | ||
| + public: | ||
| + Nesting() { current_ += 2; } | ||
| + ~Nesting() { current_ -= 2; } | ||
| + static int current() { return current_; } | ||
| + private: | ||
| + static int current_; | ||
| +}; | ||
| + | ||
| +int Nesting::current_ = 0; | ||
| +#endif | ||
| + | ||
| + | ||
| +void Interface::DoAdd( | ||
| + void* name, uint32_t hash, Interface* interface, bool* ok) { | ||
| + MakeModule(ok); | ||
| + if (!*ok) return; | ||
| + | ||
| +#ifdef DEBUG | ||
| + if (FLAG_print_interface_details) { | ||
| + PrintF("%*s# Adding...\n", Nesting::current(), ""); | ||
| + PrintF("%*sthis = ", Nesting::current(), ""); | ||
| + this->Print(Nesting::current()); | ||
| + PrintF("%*s%s : ", Nesting::current(), "", | ||
| + (*reinterpret_cast<String**>(name))->ToAsciiArray()); | ||
| + interface->Print(Nesting::current()); | ||
| + } | ||
| +#endif | ||
| + | ||
| + ZoneHashMap** map = &Chase()->exports_; | ||
| + if (*map == NULL) *map = new ZoneHashMap(Match, 8); | ||
| + | ||
| + ZoneHashMap::Entry* p = (*map)->Lookup(name, hash, !IsFrozen()); | ||
| + if (p == NULL) { | ||
| + // This didn't have name but was frozen already, that's an error. | ||
| + *ok = false; | ||
| + } else if (p->value == NULL) { | ||
| + p->value = interface; | ||
| + } else { | ||
| +#ifdef DEBUG | ||
| + Nesting nested; | ||
| +#endif | ||
| + reinterpret_cast<Interface*>(p->value)->Unify(interface, ok); | ||
| + } | ||
| + | ||
| +#ifdef DEBUG | ||
| + if (FLAG_print_interface_details) { | ||
| + PrintF("%*sthis' = ", Nesting::current(), ""); | ||
| + this->Print(Nesting::current()); | ||
| + PrintF("%*s# Added.\n", Nesting::current(), ""); | ||
| + } | ||
| +#endif | ||
| +} | ||
| + | ||
| + | ||
| +void Interface::Unify(Interface* that, bool* ok) { | ||
| + if (this->forward_) return this->Chase()->Unify(that, ok); | ||
| + if (that->forward_) return this->Unify(that->Chase(), ok); | ||
| + ASSERT(this->forward_ == NULL); | ||
| + ASSERT(that->forward_ == NULL); | ||
| + | ||
| + *ok = true; | ||
| + if (this == that) return; | ||
| + if (this->IsValue()) return that->MakeValue(ok); | ||
| + if (that->IsValue()) return this->MakeValue(ok); | ||
| + | ||
| +#ifdef DEBUG | ||
| + if (FLAG_print_interface_details) { | ||
| + PrintF("%*s# Unifying...\n", Nesting::current(), ""); | ||
| + PrintF("%*sthis = ", Nesting::current(), ""); | ||
| + this->Print(Nesting::current()); | ||
| + PrintF("%*sthat = ", Nesting::current(), ""); | ||
| + that->Print(Nesting::current()); | ||
| + } | ||
| +#endif | ||
| + | ||
| + // Merge the smaller interface into the larger, for performance. | ||
| + if (this->exports_ != NULL && (that->exports_ == NULL || | ||
| + this->exports_->occupancy() >= that->exports_->occupancy())) { | ||
| + this->DoUnify(that, ok); | ||
| + } else { | ||
| + that->DoUnify(this, ok); | ||
| + } | ||
| + | ||
| +#ifdef DEBUG | ||
| + if (FLAG_print_interface_details) { | ||
| + PrintF("%*sthis' = ", Nesting::current(), ""); | ||
| + this->Print(Nesting::current()); | ||
| + PrintF("%*sthat' = ", Nesting::current(), ""); | ||
| + that->Print(Nesting::current()); | ||
| + PrintF("%*s# Unified.\n", Nesting::current(), ""); | ||
| + } | ||
| +#endif | ||
| +} | ||
| + | ||
| + | ||
| +void Interface::DoUnify(Interface* that, bool* ok) { | ||
| + ASSERT(this->forward_ == NULL); | ||
| + ASSERT(that->forward_ == NULL); | ||
| + ASSERT(!this->IsValue()); | ||
| + ASSERT(!that->IsValue()); | ||
| + ASSERT(*ok); | ||
| + | ||
| +#ifdef DEBUG | ||
| + Nesting nested; | ||
| +#endif | ||
| + | ||
| + // Try to merge all members from that into this. | ||
| + ZoneHashMap* map = that->exports_; | ||
| + if (map != NULL) { | ||
| + for (ZoneHashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) { | ||
| + this->DoAdd(p->key, p->hash, static_cast<Interface*>(p->value), ok); | ||
| + if (!*ok) return; | ||
| + } | ||
| + } | ||
| + | ||
| + // If the new interface is larger than that's, then there were members in | ||
| + // 'this' which 'that' didn't have. If 'that' was frozen that is an error. | ||
| + int this_size = this->exports_ == NULL ? 0 : this->exports_->occupancy(); | ||
| + int that_size = map == NULL ? 0 : map->occupancy(); | ||
| + if (that->IsFrozen() && this_size > that_size) { | ||
| + *ok = false; | ||
| + return; | ||
| + } | ||
| + | ||
| + // Merge interfaces. | ||
| + this->flags_ |= that->flags_; | ||
| + that->forward_ = this; | ||
| +} | ||
| + | ||
| + | ||
| +#ifdef DEBUG | ||
| +void Interface::Print(int n) { | ||
| + int n0 = n > 0 ? n : 0; | ||
| + | ||
| + if (FLAG_print_interface_details) { | ||
| + PrintF("%p", static_cast<void*>(this)); | ||
| + for (Interface* link = this->forward_; link != NULL; link = link->forward_) | ||
| + PrintF("->%p", static_cast<void*>(link)); | ||
| + PrintF(" "); | ||
| + } | ||
| + | ||
| + if (IsUnknown()) { | ||
| + PrintF("unknown\n"); | ||
| + } else if (IsValue()) { | ||
| + PrintF("value\n"); | ||
| + } else if (IsModule()) { | ||
| + PrintF("module %s{", IsFrozen() ? "" : "(unresolved) "); | ||
| + ZoneHashMap* map = Chase()->exports_; | ||
| + if (map == NULL || map->occupancy() == 0) { | ||
| + PrintF("}\n"); | ||
| + } else if (n < 0 || n0 >= 2 * FLAG_print_interface_depth) { | ||
| + // Avoid infinite recursion on cyclic types. | ||
| + PrintF("...}\n"); | ||
| + } else { | ||
| + PrintF("\n"); | ||
| + for (ZoneHashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) { | ||
| + String* name = *static_cast<String**>(p->key); | ||
| + Interface* interface = static_cast<Interface*>(p->value); | ||
| + PrintF("%*s%s : ", n0 + 2, "", name->ToAsciiArray()); | ||
| + interface->Print(n0 + 2); | ||
| + } | ||
| + PrintF("%*s}\n", n0, ""); | ||
| + } | ||
| + } | ||
| +} | ||
| +#endif | ||
| + | ||
| +} } // namespace v8::internal |
| @@ -0,0 +1,156 @@ | ||
| +// Copyright 2012 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +#ifndef V8_INTERFACE_H_ | ||
| +#define V8_INTERFACE_H_ | ||
| + | ||
| +#include "zone-inl.h" // For operator new. | ||
| + | ||
| +namespace v8 { | ||
| +namespace internal { | ||
| + | ||
| + | ||
| +// This class implements the following abstract grammar of interfaces | ||
| +// (i.e. module types): | ||
| +// interface ::= UNDETERMINED | VALUE | MODULE(exports) | ||
| +// exports ::= {name : interface, ...} | ||
| +// A frozen module type is one that is fully determined. Unification does not | ||
| +// allow adding additional exports to frozen interfaces. | ||
| +// Otherwise, unifying modules merges their exports. | ||
| +// Undetermined types are unification variables that can be unified freely. | ||
| + | ||
| +class Interface : public ZoneObject { | ||
| + public: | ||
| + // --------------------------------------------------------------------------- | ||
| + // Factory methods. | ||
| + | ||
| + static Interface* NewValue() { | ||
| + static Interface value_interface(VALUE + FROZEN); // Cached. | ||
| + return &value_interface; | ||
| + } | ||
| + | ||
| + static Interface* NewUnknown() { | ||
| + return new Interface(NONE); | ||
| + } | ||
| + | ||
| + static Interface* NewModule() { | ||
| + return new Interface(MODULE); | ||
| + } | ||
| + | ||
| + // --------------------------------------------------------------------------- | ||
| + // Mutators. | ||
| + | ||
| + // Add a name to the list of exports. If it already exists, unify with | ||
| + // interface, otherwise insert unless this is closed. | ||
| + void Add(Handle<String> name, Interface* interface, bool* ok) { | ||
| + DoAdd(name.location(), name->Hash(), interface, ok); | ||
| + } | ||
| + | ||
| + // Unify with another interface. If successful, both interface objects will | ||
| + // represent the same type, and changes to one are reflected in the other. | ||
| + void Unify(Interface* that, bool* ok); | ||
| + | ||
| + // Determine this interface to be a value interface. | ||
| + void MakeValue(bool* ok) { | ||
| + *ok = !IsModule(); | ||
| + if (*ok) Chase()->flags_ |= VALUE; | ||
| + } | ||
| + | ||
| + // Determine this interface to be a module interface. | ||
| + void MakeModule(bool* ok) { | ||
| + *ok = !IsValue(); | ||
| + if (*ok) Chase()->flags_ |= MODULE; | ||
| + } | ||
| + | ||
| + // Do not allow any further refinements, directly or through unification. | ||
| + void Freeze(bool* ok) { | ||
| + *ok = IsValue() || IsModule(); | ||
| + if (*ok) Chase()->flags_ |= FROZEN; | ||
| + } | ||
| + | ||
| + // --------------------------------------------------------------------------- | ||
| + // Accessors. | ||
| + | ||
| + // Look up an exported name. Returns NULL if not (yet) defined. | ||
| + Interface* Lookup(Handle<String> name); | ||
| + | ||
| + // Check whether this is still a fully undetermined type. | ||
| + bool IsUnknown() { return Chase()->flags_ == NONE; } | ||
| + | ||
| + // Check whether this is a value type. | ||
| + bool IsValue() { return Chase()->flags_ & VALUE; } | ||
| + | ||
| + // Check whether this is a module type. | ||
| + bool IsModule() { return Chase()->flags_ & MODULE; } | ||
| + | ||
| + // Check whether this is closed (i.e. fully determined). | ||
| + bool IsFrozen() { return Chase()->flags_ & FROZEN; } | ||
| + | ||
| + // --------------------------------------------------------------------------- | ||
| + // Debugging. | ||
| +#ifdef DEBUG | ||
| + void Print(int n = 0); // n = indentation; n < 0 => don't print recursively | ||
| +#endif | ||
| + | ||
| + // --------------------------------------------------------------------------- | ||
| + // Implementation. | ||
| + private: | ||
| + enum Flags { // All flags are monotonic | ||
| + NONE = 0, | ||
| + VALUE = 1, // This type describes a value | ||
| + MODULE = 2, // This type describes a module | ||
| + FROZEN = 4 // This type is fully determined | ||
| + }; | ||
| + | ||
| + int flags_; | ||
| + Interface* forward_; // Unification link | ||
| + ZoneHashMap* exports_; // Module exports and their types (allocated lazily) | ||
| + | ||
| + explicit Interface(int flags) | ||
| + : flags_(flags), | ||
| + forward_(NULL), | ||
| + exports_(NULL) { | ||
| +#ifdef DEBUG | ||
| + if (FLAG_print_interface_details) | ||
| + PrintF("# Creating %p\n", static_cast<void*>(this)); | ||
| +#endif | ||
| + } | ||
| + | ||
| + Interface* Chase() { | ||
| + Interface* result = this; | ||
| + while (result->forward_ != NULL) result = result->forward_; | ||
| + if (result != this) forward_ = result; // On-the-fly path compression. | ||
| + return result; | ||
| + } | ||
| + | ||
| + void DoAdd(void* name, uint32_t hash, Interface* interface, bool* ok); | ||
| + void DoUnify(Interface* that, bool* ok); | ||
| +}; | ||
| + | ||
| +} } // namespace v8::internal | ||
| + | ||
| +#endif // V8_INTERFACE_H_ |
| @@ -0,0 +1,168 @@ | ||
| +// Copyright 2012 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +#include "v8.h" | ||
| + | ||
| +#include "global-handles.h" | ||
| +#include "snapshot.h" | ||
| +#include "cctest.h" | ||
| + | ||
| +using namespace v8::internal; | ||
| + | ||
| +class DateCacheMock: public DateCache { | ||
| + public: | ||
| + struct Rule { | ||
| + int year, start_month, start_day, end_month, end_day, offset_sec; | ||
| + }; | ||
| + | ||
| + DateCacheMock(int local_offset, Rule* rules, int rules_count) | ||
| + : local_offset_(local_offset), rules_(rules), rules_count_(rules_count) {} | ||
| + | ||
| + protected: | ||
| + virtual int GetDaylightSavingsOffsetFromOS(int64_t time_sec) { | ||
| + int days = DaysFromTime(time_sec * 1000); | ||
| + int time_in_day_sec = TimeInDay(time_sec * 1000, days) / 1000; | ||
| + int year, month, day; | ||
| + YearMonthDayFromDays(days, &year, &month, &day); | ||
| + Rule* rule = FindRuleFor(year, month, day, time_in_day_sec); | ||
| + return rule == NULL ? 0 : rule->offset_sec * 1000; | ||
| + } | ||
| + | ||
| + | ||
| + virtual int GetLocalOffsetFromOS() { | ||
| + return local_offset_; | ||
| + } | ||
| + | ||
| + private: | ||
| + Rule* FindRuleFor(int year, int month, int day, int time_in_day_sec) { | ||
| + Rule* result = NULL; | ||
| + for (int i = 0; i < rules_count_; i++) | ||
| + if (Match(&rules_[i], year, month, day, time_in_day_sec)) { | ||
| + result = &rules_[i]; | ||
| + } | ||
| + return result; | ||
| + } | ||
| + | ||
| + | ||
| + bool Match(Rule* rule, int year, int month, int day, int time_in_day_sec) { | ||
| + if (rule->year != 0 && rule->year != year) return false; | ||
| + if (rule->start_month > month) return false; | ||
| + if (rule->end_month < month) return false; | ||
| + int start_day = ComputeRuleDay(year, rule->start_month, rule->start_day); | ||
| + if (rule->start_month == month && start_day > day) return false; | ||
| + if (rule->start_month == month && start_day == day && | ||
| + 2 * 3600 > time_in_day_sec) | ||
| + return false; | ||
| + int end_day = ComputeRuleDay(year, rule->end_month, rule->end_day); | ||
| + if (rule->end_month == month && end_day < day) return false; | ||
| + if (rule->end_month == month && end_day == day && | ||
| + 2 * 3600 <= time_in_day_sec) | ||
| + return false; | ||
| + return true; | ||
| + } | ||
| + | ||
| + | ||
| + int ComputeRuleDay(int year, int month, int day) { | ||
| + if (day != 0) return day; | ||
| + int days = DaysFromYearMonth(year, month); | ||
| + // Find the first Sunday of the month. | ||
| + while (Weekday(days + day) != 6) day++; | ||
| + return day + 1; | ||
| + } | ||
| + | ||
| + int local_offset_; | ||
| + Rule* rules_; | ||
| + int rules_count_; | ||
| +}; | ||
| + | ||
| +static int64_t TimeFromYearMonthDay(DateCache* date_cache, | ||
| + int year, | ||
| + int month, | ||
| + int day) { | ||
| + int64_t result = date_cache->DaysFromYearMonth(year, month); | ||
| + return (result + day - 1) * DateCache::kMsPerDay; | ||
| +} | ||
| + | ||
| +static void CheckDST(int64_t time) { | ||
| + Isolate* isolate = Isolate::Current(); | ||
| + DateCache* date_cache = isolate->date_cache(); | ||
| + int64_t actual = date_cache->ToLocal(time); | ||
| + int64_t expected = time + date_cache->GetLocalOffsetFromOS() + | ||
| + date_cache->GetDaylightSavingsOffsetFromOS(time / 1000); | ||
| + CHECK_EQ(actual, expected); | ||
| +} | ||
| + | ||
| + | ||
| +TEST(DaylightSavingsTime) { | ||
| + LocalContext context; | ||
| + v8::HandleScope scope; | ||
| + Isolate* isolate = Isolate::Current(); | ||
| + DateCacheMock::Rule rules[] = { | ||
| + {0, 2, 0, 10, 0, 3600}, // DST from March to November in any year. | ||
| + {2010, 2, 0, 7, 20, 3600}, // DST from March to August 20 in 2010. | ||
| + {2010, 7, 20, 8, 10, 0}, // No DST from August 20 to September 10 in 2010. | ||
| + {2010, 8, 10, 10, 0, 3600}, // DST from September 10 to November in 2010. | ||
| + }; | ||
| + | ||
| + int local_offset_ms = -36000000; // -10 hours. | ||
| + | ||
| + DateCacheMock* date_cache = | ||
| + new DateCacheMock(local_offset_ms, rules, ARRAY_SIZE(rules)); | ||
| + | ||
| + isolate->set_date_cache(date_cache); | ||
| + | ||
| + int64_t start_of_2010 = TimeFromYearMonthDay(date_cache, 2010, 0, 1); | ||
| + int64_t start_of_2011 = TimeFromYearMonthDay(date_cache, 2011, 0, 1); | ||
| + int64_t august_20 = TimeFromYearMonthDay(date_cache, 2010, 7, 20); | ||
| + int64_t september_10 = TimeFromYearMonthDay(date_cache, 2010, 8, 10); | ||
| + CheckDST((august_20 + september_10) / 2); | ||
| + CheckDST(september_10); | ||
| + CheckDST(september_10 + 2 * 3600); | ||
| + CheckDST(september_10 + 2 * 3600 - 1000); | ||
| + CheckDST(august_20 + 2 * 3600); | ||
| + CheckDST(august_20 + 2 * 3600 - 1000); | ||
| + CheckDST(august_20); | ||
| + // Check each day of 2010. | ||
| + for (int64_t time = start_of_2011 + 2 * 3600; | ||
| + time >= start_of_2010; | ||
| + time -= DateCache::kMsPerDay) { | ||
| + CheckDST(time); | ||
| + CheckDST(time - 1000); | ||
| + CheckDST(time + 1000); | ||
| + } | ||
| + // Check one day from 2010 to 2100. | ||
| + for (int year = 2100; year >= 2010; year--) { | ||
| + CheckDST(TimeFromYearMonthDay(date_cache, year, 5, 5)); | ||
| + } | ||
| + CheckDST((august_20 + september_10) / 2); | ||
| + CheckDST(september_10); | ||
| + CheckDST(september_10 + 2 * 3600); | ||
| + CheckDST(september_10 + 2 * 3600 - 1000); | ||
| + CheckDST(august_20 + 2 * 3600); | ||
| + CheckDST(august_20 + 2 * 3600 - 1000); | ||
| + CheckDST(august_20); | ||
| +} |
| @@ -0,0 +1,109 @@ | ||
| +// Copyright 2012 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| + | ||
| +#include "v8.h" | ||
| + | ||
| +#include "cctest.h" | ||
| +#include "compiler.h" | ||
| +#include "execution.h" | ||
| +#include "isolate.h" | ||
| + | ||
| + | ||
| +using namespace v8::internal; | ||
| + | ||
| +static v8::Persistent<v8::Context> env; | ||
| + | ||
| + | ||
| +void SetSeeds(Handle<ByteArray> seeds, uint32_t state0, uint32_t state1) { | ||
| + for (int i = 0; i < 4; i++) { | ||
| + seeds->set(i, static_cast<byte>(state0 >> (i * kBitsPerByte))); | ||
| + seeds->set(i + 4, static_cast<byte>(state1 >> (i * kBitsPerByte))); | ||
| + } | ||
| +} | ||
| + | ||
| + | ||
| +void TestSeeds(Handle<JSFunction> fun, | ||
| + Handle<Context> context, | ||
| + uint32_t state0, | ||
| + uint32_t state1) { | ||
| + bool has_pending_exception; | ||
| + Handle<JSObject> global(context->global()); | ||
| + Handle<ByteArray> seeds(context->random_seed()); | ||
| + | ||
| + SetSeeds(seeds, state0, state1); | ||
| + Handle<Object> value = | ||
| + Execution::Call(fun, global, 0, NULL, &has_pending_exception); | ||
| + CHECK(value->IsHeapNumber()); | ||
| + CHECK(fun->IsOptimized()); | ||
| + double crankshaft_value = HeapNumber::cast(*value)->value(); | ||
| + | ||
| + SetSeeds(seeds, state0, state1); | ||
| + V8::FillHeapNumberWithRandom(*value, *context); | ||
| + double runtime_value = HeapNumber::cast(*value)->value(); | ||
| + CHECK_EQ(runtime_value, crankshaft_value); | ||
| +} | ||
| + | ||
| + | ||
| +TEST(CrankshaftRandom) { | ||
| + if (env.IsEmpty()) env = v8::Context::New(); | ||
| + // Skip test if crankshaft is disabled. | ||
| + if (!V8::UseCrankshaft()) return; | ||
| + v8::HandleScope scope; | ||
| + env->Enter(); | ||
| + | ||
| + Handle<Context> context(Isolate::Current()->context()); | ||
| + Handle<JSObject> global(context->global()); | ||
| + Handle<ByteArray> seeds(context->random_seed()); | ||
| + bool has_pending_exception; | ||
| + | ||
| + CompileRun("function f() { return Math.random(); }"); | ||
| + | ||
| + Object* symbol = FACTORY->LookupAsciiSymbol("f")->ToObjectChecked(); | ||
| + MaybeObject* fun_object = | ||
| + context->global()->GetProperty(String::cast(symbol)); | ||
| + Handle<JSFunction> fun(JSFunction::cast(fun_object->ToObjectChecked())); | ||
| + | ||
| + // Optimize function. | ||
| + Execution::Call(fun, global, 0, NULL, &has_pending_exception); | ||
| + Execution::Call(fun, global, 0, NULL, &has_pending_exception); | ||
| + if (!fun->IsOptimized()) fun->MarkForLazyRecompilation(); | ||
| + | ||
| + // Test with some random values. | ||
| + TestSeeds(fun, context, 0xC0C0AFFE, 0x31415926); | ||
| + TestSeeds(fun, context, 0x01020304, 0xFFFFFFFF); | ||
| + TestSeeds(fun, context, 0x00000001, 0x00000000); | ||
| + | ||
| + // Test that we bail out to runtime when seeds are uninitialized (zeros). | ||
| + SetSeeds(seeds, 0, 0); | ||
| + Handle<Object> value = | ||
| + Execution::Call(fun, global, 0, NULL, &has_pending_exception); | ||
| + CHECK(value->IsHeapNumber()); | ||
| + CHECK(fun->IsOptimized()); | ||
| + double crankshaft_value = HeapNumber::cast(*value)->value(); | ||
| + CHECK_NE(0.0, crankshaft_value); | ||
| +} |
| @@ -0,0 +1,128 @@ | ||
| +// Copyright 2012 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +// Flags: --allow-natives-syntax | ||
| + | ||
| +function test_helper_for_ics(func, b1, b2, b3, b4) { | ||
| + assertEquals(b1, func(.5, .5)); | ||
| + assertEquals(b2, func(.5, undefined)); | ||
| + assertEquals(b3, func(undefined, .5)); | ||
| + assertEquals(b4, func(undefined, undefined)); | ||
| +} | ||
| + | ||
| +function test_helper_for_crankshaft(func, b1, b2, b3, b4) { | ||
| + assertEquals(b1, func(.5, .5)); | ||
| + %OptimizeFunctionOnNextCall(func); | ||
| + assertEquals(b1, func(.5, .5)); | ||
| + assertEquals(b2, func(.5, undefined)); | ||
| + assertEquals(b3, func(undefined, .5)); | ||
| + assertEquals(b4, func(undefined, undefined)); | ||
| +} | ||
| + | ||
| +function less_1(a, b) { | ||
| + return a < b; | ||
| +} | ||
| + | ||
| +test_helper_for_ics(less_1, false, false, false, false); | ||
| + | ||
| +function less_2(a, b) { | ||
| + return a < b; | ||
| +} | ||
| + | ||
| +test_helper_for_crankshaft(less_1, false, false, false, false); | ||
| + | ||
| +function greater_1(a, b) { | ||
| + return a > b; | ||
| +} | ||
| + | ||
| +test_helper_for_ics(greater_1, false, false, false, false); | ||
| + | ||
| +function greater_2(a, b) { | ||
| + return a > b; | ||
| +} | ||
| + | ||
| +test_helper_for_crankshaft(greater_1, false, false, false, false); | ||
| + | ||
| +function less_equal_1(a, b) { | ||
| + return a <= b; | ||
| +} | ||
| + | ||
| +test_helper_for_ics(less_equal_1, true, false, false, false); | ||
| + | ||
| +function less_equal_2(a, b) { | ||
| + return a <= b; | ||
| +} | ||
| + | ||
| +test_helper_for_crankshaft(less_equal_1, true, false, false, false); | ||
| + | ||
| +function greater_equal_1(a, b) { | ||
| + return a >= b; | ||
| +} | ||
| + | ||
| +test_helper_for_ics(greater_equal_1, true, false, false, false); | ||
| + | ||
| +function greater_equal_2(a, b) { | ||
| + return a >= b; | ||
| +} | ||
| + | ||
| +test_helper_for_crankshaft(greater_equal_1, true, false, false, false); | ||
| + | ||
| +function equal_1(a, b) { | ||
| + return a == b; | ||
| +} | ||
| + | ||
| +test_helper_for_ics(equal_1, true, false, false, true); | ||
| + | ||
| +function equal_2(a, b) { | ||
| + return a == b; | ||
| +} | ||
| + | ||
| +test_helper_for_crankshaft(equal_2, true, false, false, true); | ||
| + | ||
| +function strict_equal_1(a, b) { | ||
| + return a === b; | ||
| +} | ||
| + | ||
| +test_helper_for_ics(strict_equal_1, true, false, false, true); | ||
| + | ||
| +function strict_equal_2(a, b) { | ||
| + return a === b; | ||
| +} | ||
| + | ||
| +test_helper_for_crankshaft(strict_equal_2, true, false, false, true); | ||
| + | ||
| +function not_equal_1(a, b) { | ||
| + return a != b; | ||
| +} | ||
| + | ||
| +test_helper_for_ics(not_equal_1, false, true, true, false); | ||
| + | ||
| +function not_equal_2(a, b) { | ||
| + return a != b; | ||
| +} | ||
| + | ||
| +test_helper_for_crankshaft(not_equal_2, false, true, true, false); |
| @@ -0,0 +1,308 @@ | ||
| +// Copyright 2012 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +// Flags: --allow-natives-syntax --inline-construct --nolimit-inlining | ||
| + | ||
| +// Test that huge constructors (more than 256 this assignments) are | ||
| +// handled correctly. | ||
| + | ||
| +// Test huge constructor when being inlined into hydrogen. | ||
| +function test() { | ||
| + return new huge(); | ||
| +} | ||
| +test(); | ||
| +test(); | ||
| +%OptimizeFunctionOnNextCall(test); | ||
| +var o = test(); | ||
| +assertEquals(1, o.foo1); | ||
| +assertEquals(257, o.foo257); | ||
| + | ||
| +// Test huge constructor with specialized constructor stub. | ||
| +var o = new huge(); | ||
| +assertEquals(1, o.foo1); | ||
| +assertEquals(257, o.foo257); | ||
| + | ||
| +// The huge constructor, nothing interesting beyond this point. | ||
| +function huge() { | ||
| + this.foo1 = 1; | ||
| + this.foo2 = 2; | ||
| + this.foo3 = 3; | ||
| + this.foo4 = 4; | ||
| + this.foo5 = 5; | ||
| + this.foo6 = 6; | ||
| + this.foo7 = 7; | ||
| + this.foo8 = 8; | ||
| + this.foo9 = 9; | ||
| + this.foo10 = 10; | ||
| + this.foo11 = 11; | ||
| + this.foo12 = 12; | ||
| + this.foo13 = 13; | ||
| + this.foo14 = 14; | ||
| + this.foo15 = 15; | ||
| + this.foo16 = 16; | ||
| + this.foo17 = 17; | ||
| + this.foo18 = 18; | ||
| + this.foo19 = 19; | ||
| + this.foo20 = 20; | ||
| + this.foo21 = 21; | ||
| + this.foo22 = 22; | ||
| + this.foo23 = 23; | ||
| + this.foo24 = 24; | ||
| + this.foo25 = 25; | ||
| + this.foo26 = 26; | ||
| + this.foo27 = 27; | ||
| + this.foo28 = 28; | ||
| + this.foo29 = 29; | ||
| + this.foo30 = 30; | ||
| + this.foo31 = 31; | ||
| + this.foo32 = 32; | ||
| + this.foo33 = 33; | ||
| + this.foo34 = 34; | ||
| + this.foo35 = 35; | ||
| + this.foo36 = 36; | ||
| + this.foo37 = 37; | ||
| + this.foo38 = 38; | ||
| + this.foo39 = 39; | ||
| + this.foo40 = 40; | ||
| + this.foo41 = 41; | ||
| + this.foo42 = 42; | ||
| + this.foo43 = 43; | ||
| + this.foo44 = 44; | ||
| + this.foo45 = 45; | ||
| + this.foo46 = 46; | ||
| + this.foo47 = 47; | ||
| + this.foo48 = 48; | ||
| + this.foo49 = 49; | ||
| + this.foo50 = 50; | ||
| + this.foo51 = 51; | ||
| + this.foo52 = 52; | ||
| + this.foo53 = 53; | ||
| + this.foo54 = 54; | ||
| + this.foo55 = 55; | ||
| + this.foo56 = 56; | ||
| + this.foo57 = 57; | ||
| + this.foo58 = 58; | ||
| + this.foo59 = 59; | ||
| + this.foo60 = 60; | ||
| + this.foo61 = 61; | ||
| + this.foo62 = 62; | ||
| + this.foo63 = 63; | ||
| + this.foo64 = 64; | ||
| + this.foo65 = 65; | ||
| + this.foo66 = 66; | ||
| + this.foo67 = 67; | ||
| + this.foo68 = 68; | ||
| + this.foo69 = 69; | ||
| + this.foo70 = 70; | ||
| + this.foo71 = 71; | ||
| + this.foo72 = 72; | ||
| + this.foo73 = 73; | ||
| + this.foo74 = 74; | ||
| + this.foo75 = 75; | ||
| + this.foo76 = 76; | ||
| + this.foo77 = 77; | ||
| + this.foo78 = 78; | ||
| + this.foo79 = 79; | ||
| + this.foo80 = 80; | ||
| + this.foo81 = 81; | ||
| + this.foo82 = 82; | ||
| + this.foo83 = 83; | ||
| + this.foo84 = 84; | ||
| + this.foo85 = 85; | ||
| + this.foo86 = 86; | ||
| + this.foo87 = 87; | ||
| + this.foo88 = 88; | ||
| + this.foo89 = 89; | ||
| + this.foo90 = 90; | ||
| + this.foo91 = 91; | ||
| + this.foo92 = 92; | ||
| + this.foo93 = 93; | ||
| + this.foo94 = 94; | ||
| + this.foo95 = 95; | ||
| + this.foo96 = 96; | ||
| + this.foo97 = 97; | ||
| + this.foo98 = 98; | ||
| + this.foo99 = 99; | ||
| + this.foo100 = 100; | ||
| + this.foo101 = 101; | ||
| + this.foo102 = 102; | ||
| + this.foo103 = 103; | ||
| + this.foo104 = 104; | ||
| + this.foo105 = 105; | ||
| + this.foo106 = 106; | ||
| + this.foo107 = 107; | ||
| + this.foo108 = 108; | ||
| + this.foo109 = 109; | ||
| + this.foo110 = 110; | ||
| + this.foo111 = 111; | ||
| + this.foo112 = 112; | ||
| + this.foo113 = 113; | ||
| + this.foo114 = 114; | ||
| + this.foo115 = 115; | ||
| + this.foo116 = 116; | ||
| + this.foo117 = 117; | ||
| + this.foo118 = 118; | ||
| + this.foo119 = 119; | ||
| + this.foo120 = 120; | ||
| + this.foo121 = 121; | ||
| + this.foo122 = 122; | ||
| + this.foo123 = 123; | ||
| + this.foo124 = 124; | ||
| + this.foo125 = 125; | ||
| + this.foo126 = 126; | ||
| + this.foo127 = 127; | ||
| + this.foo128 = 128; | ||
| + this.foo129 = 129; | ||
| + this.foo130 = 130; | ||
| + this.foo131 = 131; | ||
| + this.foo132 = 132; | ||
| + this.foo133 = 133; | ||
| + this.foo134 = 134; | ||
| + this.foo135 = 135; | ||
| + this.foo136 = 136; | ||
| + this.foo137 = 137; | ||
| + this.foo138 = 138; | ||
| + this.foo139 = 139; | ||
| + this.foo140 = 140; | ||
| + this.foo141 = 141; | ||
| + this.foo142 = 142; | ||
| + this.foo143 = 143; | ||
| + this.foo144 = 144; | ||
| + this.foo145 = 145; | ||
| + this.foo146 = 146; | ||
| + this.foo147 = 147; | ||
| + this.foo148 = 148; | ||
| + this.foo149 = 149; | ||
| + this.foo150 = 150; | ||
| + this.foo151 = 151; | ||
| + this.foo152 = 152; | ||
| + this.foo153 = 153; | ||
| + this.foo154 = 154; | ||
| + this.foo155 = 155; | ||
| + this.foo156 = 156; | ||
| + this.foo157 = 157; | ||
| + this.foo158 = 158; | ||
| + this.foo159 = 159; | ||
| + this.foo160 = 160; | ||
| + this.foo161 = 161; | ||
| + this.foo162 = 162; | ||
| + this.foo163 = 163; | ||
| + this.foo164 = 164; | ||
| + this.foo165 = 165; | ||
| + this.foo166 = 166; | ||
| + this.foo167 = 167; | ||
| + this.foo168 = 168; | ||
| + this.foo169 = 169; | ||
| + this.foo170 = 170; | ||
| + this.foo171 = 171; | ||
| + this.foo172 = 172; | ||
| + this.foo173 = 173; | ||
| + this.foo174 = 174; | ||
| + this.foo175 = 175; | ||
| + this.foo176 = 176; | ||
| + this.foo177 = 177; | ||
| + this.foo178 = 178; | ||
| + this.foo179 = 179; | ||
| + this.foo180 = 180; | ||
| + this.foo181 = 181; | ||
| + this.foo182 = 182; | ||
| + this.foo183 = 183; | ||
| + this.foo184 = 184; | ||
| + this.foo185 = 185; | ||
| + this.foo186 = 186; | ||
| + this.foo187 = 187; | ||
| + this.foo188 = 188; | ||
| + this.foo189 = 189; | ||
| + this.foo190 = 190; | ||
| + this.foo191 = 191; | ||
| + this.foo192 = 192; | ||
| + this.foo193 = 193; | ||
| + this.foo194 = 194; | ||
| + this.foo195 = 195; | ||
| + this.foo196 = 196; | ||
| + this.foo197 = 197; | ||
| + this.foo198 = 198; | ||
| + this.foo199 = 199; | ||
| + this.foo200 = 200; | ||
| + this.foo201 = 201; | ||
| + this.foo202 = 202; | ||
| + this.foo203 = 203; | ||
| + this.foo204 = 204; | ||
| + this.foo205 = 205; | ||
| + this.foo206 = 206; | ||
| + this.foo207 = 207; | ||
| + this.foo208 = 208; | ||
| + this.foo209 = 209; | ||
| + this.foo210 = 210; | ||
| + this.foo211 = 211; | ||
| + this.foo212 = 212; | ||
| + this.foo213 = 213; | ||
| + this.foo214 = 214; | ||
| + this.foo215 = 215; | ||
| + this.foo216 = 216; | ||
| + this.foo217 = 217; | ||
| + this.foo218 = 218; | ||
| + this.foo219 = 219; | ||
| + this.foo220 = 220; | ||
| + this.foo221 = 221; | ||
| + this.foo222 = 222; | ||
| + this.foo223 = 223; | ||
| + this.foo224 = 224; | ||
| + this.foo225 = 225; | ||
| + this.foo226 = 226; | ||
| + this.foo227 = 227; | ||
| + this.foo228 = 228; | ||
| + this.foo229 = 229; | ||
| + this.foo230 = 230; | ||
| + this.foo231 = 231; | ||
| + this.foo232 = 232; | ||
| + this.foo233 = 233; | ||
| + this.foo234 = 234; | ||
| + this.foo235 = 235; | ||
| + this.foo236 = 236; | ||
| + this.foo237 = 237; | ||
| + this.foo238 = 238; | ||
| + this.foo239 = 239; | ||
| + this.foo240 = 240; | ||
| + this.foo241 = 241; | ||
| + this.foo242 = 242; | ||
| + this.foo243 = 243; | ||
| + this.foo244 = 244; | ||
| + this.foo245 = 245; | ||
| + this.foo246 = 246; | ||
| + this.foo247 = 247; | ||
| + this.foo248 = 248; | ||
| + this.foo249 = 249; | ||
| + this.foo250 = 250; | ||
| + this.foo251 = 251; | ||
| + this.foo252 = 252; | ||
| + this.foo253 = 253; | ||
| + this.foo254 = 254; | ||
| + this.foo255 = 255; | ||
| + this.foo256 = 256; | ||
| + this.foo257 = 257; | ||
| +} |
| @@ -0,0 +1,90 @@ | ||
| +// Copyright 2012 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +// Flags: --allow-natives-syntax --expose-gc --inline-construct | ||
| + | ||
| +// Test that inlined object allocation works for different layouts of | ||
| +// objects (e.g. in object properties, slack tracking in progress or | ||
| +// changing of function prototypes) | ||
| + | ||
| +function test_helper(construct, a, b) { | ||
| + return new construct(a, b); | ||
| +} | ||
| + | ||
| +function test(construct) { | ||
| + %DeoptimizeFunction(test); | ||
| + test_helper(construct, 0, 0); | ||
| + test_helper(construct, 0, 0); | ||
| + %OptimizeFunctionOnNextCall(test_helper); | ||
| + // Test adding a new property after allocation was inlined. | ||
| + var o = test_helper(construct, 1, 2); | ||
| + o.z = 3; | ||
| + assertEquals(1, o.x); | ||
| + assertEquals(2, o.y); | ||
| + assertEquals(3, o.z); | ||
| + // Test changing the prototype after allocation was inlined. | ||
| + construct.prototype = { z:6 }; | ||
| + var o = test_helper(construct, 4, 5); | ||
| + assertEquals(4, o.x); | ||
| + assertEquals(5, o.y); | ||
| + assertEquals(6, o.z); | ||
| + %DeoptimizeFunction(test_helper); | ||
| + gc(); // Makes V8 forget about type information for test_helper. | ||
| +} | ||
| + | ||
| +function finalize_slack_tracking(construct) { | ||
| + // Value chosen based on kGenerousAllocationCount = 8. | ||
| + for (var i = 0; i < 8; i++) { | ||
| + new construct(0, 0); | ||
| + } | ||
| +} | ||
| + | ||
| + | ||
| +// Both properties are pre-allocated in object properties. | ||
| +function ConstructInObjectPreAllocated(a, b) { | ||
| + this.x = a; | ||
| + this.y = b; | ||
| +} | ||
| +finalize_slack_tracking(ConstructInObjectPreAllocated); | ||
| +test(ConstructInObjectPreAllocated); | ||
| + | ||
| + | ||
| +// Both properties are unused in object properties. | ||
| +function ConstructInObjectUnused(a, b) { | ||
| + this.x = a < 0 ? 0 : a; | ||
| + this.y = b > 0 ? b : 0; | ||
| +} | ||
| +finalize_slack_tracking(ConstructInObjectUnused); | ||
| +test(ConstructInObjectUnused); | ||
| + | ||
| + | ||
| +// Test inlined allocation while slack tracking is still in progress. | ||
| +function ConstructWhileSlackTracking(a, b) { | ||
| + this.x = a; | ||
| + this.y = b; | ||
| +} | ||
| +test(ConstructWhileSlackTracking); |
| @@ -0,0 +1,152 @@ | ||
| +// Copyright 2012 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +// Flags: --allow-natives-syntax --expose-gc --inline-construct | ||
| + | ||
| +// Test inlining of constructor calls. | ||
| + | ||
| +function TestInlinedConstructor(closure) { | ||
| + var result; | ||
| + var counter = { value:0 }; | ||
| + result = closure(11, 12, counter); | ||
| + assertEquals(23, result); | ||
| + assertEquals(1, counter.value); | ||
| + result = closure(23, 19, counter); | ||
| + assertEquals(42, result); | ||
| + assertEquals(2, counter.value); | ||
| + %OptimizeFunctionOnNextCall(closure); | ||
| + result = closure(1, 42, counter) | ||
| + assertEquals(43, result); | ||
| + assertEquals(3, counter.value); | ||
| + result = closure("foo", "bar", counter) | ||
| + assertEquals("foobar", result) | ||
| + assertEquals(4, counter.value); | ||
| +} | ||
| + | ||
| +function TestInAllContexts(constructor) { | ||
| + function value_context(a, b, counter) { | ||
| + var obj = new constructor(a, b, counter); | ||
| + return obj.x; | ||
| + } | ||
| + function test_context(a, b, counter) { | ||
| + if (!new constructor(a, b, counter)) { | ||
| + assertUnreachable("should not happen"); | ||
| + } | ||
| + return a + b; | ||
| + } | ||
| + function effect_context(a, b, counter) { | ||
| + new constructor(a, b, counter); | ||
| + return a + b; | ||
| + } | ||
| + TestInlinedConstructor(value_context); | ||
| + TestInlinedConstructor(test_context); | ||
| + TestInlinedConstructor(effect_context); | ||
| + %DeoptimizeFunction(value_context); | ||
| + %DeoptimizeFunction(test_context); | ||
| + %DeoptimizeFunction(effect_context); | ||
| + gc(); // Makes V8 forget about type information for *_context. | ||
| +} | ||
| + | ||
| + | ||
| +// Test constructor returning nothing in all contexts. | ||
| +function c1(a, b, counter) { | ||
| + this.x = a + b; | ||
| + counter.value++; | ||
| +} | ||
| +TestInAllContexts(c1); | ||
| + | ||
| + | ||
| +// Test constructor returning an object in all contexts. | ||
| +function c2(a, b, counter) { | ||
| + var obj = new Object(); | ||
| + obj.x = a + b; | ||
| + counter.value++; | ||
| + return obj; | ||
| +} | ||
| +TestInAllContexts(c2); | ||
| + | ||
| + | ||
| +// Test constructor returning a primitive value in all contexts. | ||
| +function c3(a, b, counter) { | ||
| + this.x = a + b; | ||
| + counter.value++; | ||
| + return "not an object"; | ||
| +} | ||
| +TestInAllContexts(c3); | ||
| + | ||
| + | ||
| +// Test constructor called with too many arguments. | ||
| +function c_too_many(a, b) { | ||
| + this.x = a + b; | ||
| +} | ||
| +function f_too_many(a, b, c) { | ||
| + var obj = new c_too_many(a, b, c); | ||
| + return obj.x; | ||
| +} | ||
| +assertEquals(23, f_too_many(11, 12, 1)); | ||
| +assertEquals(42, f_too_many(23, 19, 1)); | ||
| +%OptimizeFunctionOnNextCall(f_too_many); | ||
| +assertEquals(43, f_too_many(1, 42, 1)); | ||
| +assertEquals("foobar", f_too_many("foo", "bar", "baz")) | ||
| + | ||
| + | ||
| +// Test constructor called with too few arguments. | ||
| +function c_too_few(a, b) { | ||
| + assertSame(undefined, b); | ||
| + this.x = a + 1; | ||
| +} | ||
| +function f_too_few(a) { | ||
| + var obj = new c_too_few(a); | ||
| + return obj.x; | ||
| +} | ||
| +assertEquals(12, f_too_few(11)); | ||
| +assertEquals(24, f_too_few(23)); | ||
| +%OptimizeFunctionOnNextCall(f_too_few); | ||
| +assertEquals(2, f_too_few(1)); | ||
| +assertEquals("foo1", f_too_few("foo")) | ||
| + | ||
| + | ||
| +// Test constructor that cannot be inlined. | ||
| +function c_unsupported_syntax(a, b, counter) { | ||
| + try { | ||
| + this.x = a + b; | ||
| + counter.value++; | ||
| + } catch(e) { | ||
| + throw new Error(); | ||
| + } | ||
| +} | ||
| +TestInAllContexts(c_unsupported_syntax); | ||
| + | ||
| + | ||
| +// Regression test: Inlined constructors called as functions do not get their | ||
| +// implicit receiver object set to undefined, even in strict mode. | ||
| +function c_strict(a, b, counter) { | ||
| + "use strict"; | ||
| + this.x = a + b; | ||
| + counter.value++; | ||
| +} | ||
| +TestInAllContexts(c_strict); |
| @@ -0,0 +1,45 @@ | ||
| +// Copyright 2012 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +// Flags: --allow-natives-syntax --noenable-sse3 | ||
| + | ||
| +var a = new Int32Array(1); | ||
| +var G = 0x80000000; | ||
| + | ||
| +function f(x) { | ||
| + var v = x; | ||
| + v = v + 1; | ||
| + a[0] = v; | ||
| + v = v - 1; | ||
| + return v; | ||
| +} | ||
| + | ||
| +assertEquals(G, f(G)); | ||
| +assertEquals(G, f(G)); | ||
| +%OptimizeFunctionOnNextCall(f); | ||
| +assertEquals(G, f(G)); | ||
| + |
| @@ -0,0 +1,139 @@ | ||
| +// Copyright 2012 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +// Flags: --harmony-modules --harmony-scoping | ||
| + | ||
| +// Test basic module interface inference. | ||
| + | ||
| +"use strict"; | ||
| + | ||
| +print("begin.") | ||
| + | ||
| +export let x = print("0") | ||
| + | ||
| +export module B = A.B | ||
| + | ||
| +export module A { | ||
| + export let x = print("1") | ||
| + export let f = function() { return B.x } | ||
| + export module B { | ||
| + module BB = B | ||
| + export BB, x | ||
| + let x = print("2") | ||
| + let y = print("3") | ||
| + let Ax = A.x | ||
| + let ABx = A.B.x | ||
| + let Ay = A.y | ||
| + let BBx = BB.x | ||
| + let Af = A.f | ||
| + function f(x,y) { return x } | ||
| + } | ||
| + export let y = print("4") | ||
| + let Ax = A.x | ||
| + let Bx = B.x | ||
| + let ABx = A.B.x | ||
| + module C { | ||
| + export let z = print("5") | ||
| + export module D = B | ||
| + // TODO(rossberg): turn these into proper negative test cases once we have | ||
| + // suitable error messages. | ||
| + // import C.z // multiple declarations | ||
| + import x from B | ||
| + } | ||
| + module D { | ||
| + // TODO(rossberg): Handle import *. | ||
| + // import A.* // invalid forward import | ||
| + } | ||
| + module M {} | ||
| + // TODO(rossberg): Handle import *. | ||
| + // import M.* // invalid forward import | ||
| + let Cz = C.z | ||
| + let CDx = C.D.x | ||
| +} | ||
| + | ||
| +export module Imports { | ||
| + module A1 { | ||
| + export module A2 {} | ||
| + } | ||
| + module B { | ||
| + // TODO(rossberg): Handle import *. | ||
| + // import A1.* | ||
| + // import A2.* // unbound variable A2 | ||
| + } | ||
| +} | ||
| + | ||
| +export module E { | ||
| + export let xx = x | ||
| + export y, B | ||
| + let Bx = B.x | ||
| + // TODO(rossberg): Handle import *. | ||
| + // import A.* | ||
| +} | ||
| + | ||
| +export module M1 { | ||
| + export module A2 = M2 | ||
| +} | ||
| +export module M2 { | ||
| + export module A1 = M1 | ||
| +} | ||
| + | ||
| +// TODO(rossberg): turn these into proper negative test cases once we have | ||
| +// suitable error messages. | ||
| +// module W1 = W2.W | ||
| +// module W2 = { export module W = W3 } | ||
| +// module W3 = W1 // cyclic module definition | ||
| + | ||
| +// module W1 = W2.W3 | ||
| +// module W2 = { | ||
| +// export module W3 = W4 | ||
| +// export module W4 = W1 | ||
| +// } // cyclic module definition | ||
| + | ||
| +// TODO(rossberg): Handle import *. | ||
| +//module M3B = M3.B | ||
| +//export module M3 { | ||
| +// export module B { export let x = "" } | ||
| +// module C1 = { import M3.* } | ||
| +// module C2 = { import M3.B.* } | ||
| +// module C3 = { import M3B.* } | ||
| +// module C4 = { export x import B.* } | ||
| +//// TODO(rossberg): turn these into proper negative test cases once we have | ||
| +//// suitable error messages. | ||
| +//// export module C5 = { import C5.* } // invalid forward import | ||
| +//// export module C6 = { import M3.C6.* } // invalid forward import | ||
| +//} | ||
| + | ||
| +export module External at "external.js" | ||
| +export module External1 = External | ||
| +export module ExternalA = External.A | ||
| +export module InnerExternal { | ||
| + export module E at "external.js" | ||
| +} | ||
| +export module External2 = InnerExternal.E | ||
| +//export let xxx = InnerExternal.E.A.x | ||
| + | ||
| +print("end.") |
| @@ -0,0 +1,58 @@ | ||
| +// Copyright 2012 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +// Test Harmony Number.isFinite() and Number.isNaN() functions. | ||
| + | ||
| +assertTrue(Number.isFinite(0)); | ||
| +assertTrue(Number.isFinite(Number.MIN_VALUE)); | ||
| +assertTrue(Number.isFinite(Number.MAX_VALUE)); | ||
| +assertFalse(Number.isFinite(Number.NaN)); | ||
| +assertFalse(Number.isFinite(Number.POSITIVE_INFINITY)); | ||
| +assertFalse(Number.isFinite(Number.NEGATIVE_INFINITY)); | ||
| +assertFalse(Number.isFinite(new Number(0))); | ||
| +assertFalse(Number.isFinite(1/0)); | ||
| +assertFalse(Number.isFinite(-1/0)); | ||
| +assertFalse(Number.isFinite({})); | ||
| +assertFalse(Number.isFinite([])); | ||
| +assertFalse(Number.isFinite("s")); | ||
| +assertFalse(Number.isFinite(null)); | ||
| +assertFalse(Number.isFinite(undefined)); | ||
| + | ||
| +assertFalse(Number.isNaN(0)); | ||
| +assertFalse(Number.isNaN(Number.MIN_VALUE)); | ||
| +assertFalse(Number.isNaN(Number.MAX_VALUE)); | ||
| +assertTrue(Number.isNaN(Number.NaN)); | ||
| +assertFalse(Number.isNaN(Number.POSITIVE_INFINITY)); | ||
| +assertFalse(Number.isNaN(Number.NEGATIVE_INFINITY)); | ||
| +assertFalse(Number.isNaN(new Number(0))); | ||
| +assertFalse(Number.isNaN(1/0)); | ||
| +assertFalse(Number.isNaN(-1/0)); | ||
| +assertFalse(Number.isNaN({})); | ||
| +assertFalse(Number.isNaN([])); | ||
| +assertFalse(Number.isNaN("s")); | ||
| +assertFalse(Number.isNaN(null)); | ||
| +assertFalse(Number.isNaN(undefined)); |
| @@ -0,0 +1,47 @@ | ||
| +// Copyright 2012 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +// Test both the Harmony egal operator and it's function equivalent. | ||
| + | ||
| +function TestEgal(expected, x, y) { | ||
| + // TODO(mstarzinger): Once we have the egal operator, we can test it here. | ||
| + assertSame(expected, Object.is(x, y)); | ||
| +} | ||
| + | ||
| +var test_set = [ {}, [], 1/0, -1/0, "s", 0, 0/-1, null, undefined ]; | ||
| +print(test_set); | ||
| +for (var i = 0; i < test_set.length; i++) { | ||
| + for (var j = 0; j < test_set.length; j++) { | ||
| + if (i == j) { | ||
| + assertSame(test_set[i], test_set[j]); | ||
| + TestEgal(true, test_set[i], test_set[j]); | ||
| + } else { | ||
| + TestEgal(false, test_set[i], test_set[j]); | ||
| + TestEgal(false, test_set[j], test_set[i]); | ||
| + } | ||
| + } | ||
| +} |
| @@ -0,0 +1,57 @@ | ||
| +// Copyright 2012 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +// Flags: --expose-debug-as debug | ||
| + | ||
| +// Test that the break point is set before initializing the loop variable | ||
| +// so that we break before any iteration has been run. | ||
| + | ||
| +Debug = debug.Debug; | ||
| + | ||
| +var break_hit = false; | ||
| + | ||
| +function listener(event, exec_state, event_data, data) { | ||
| + if (event == Debug.DebugEvent.Break) { | ||
| + break_hit = true; | ||
| + } | ||
| +} | ||
| + | ||
| +Debug.setListener(listener); | ||
| + | ||
| +function test() { | ||
| + for (var i = 0; i < 3; i++) { // Break here. | ||
| + if (i == 0) break; | ||
| + } | ||
| +} | ||
| + | ||
| +Debug.setBreakPoint(test, 1, 0); | ||
| + | ||
| +assertTrue(Debug.showBreakPoints(test).indexOf("// Break here.") >= 0); | ||
| + | ||
| +test(); | ||
| + | ||
| +assertTrue(break_hit); |
| @@ -0,0 +1,116 @@ | ||
| +// Copyright 2012 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +// Flags: --expose-debug-as debug | ||
| + | ||
| +// Test whether scripts compiled after setting the break point are | ||
| +// updated correctly. | ||
| + | ||
| +Debug = debug.Debug; | ||
| + | ||
| +var break_count = 0; | ||
| +var test_break_1 = false; | ||
| +var test_break_2 = false; | ||
| + | ||
| +function sendCommand(state, cmd) { | ||
| + // Get the debug command processor in paused state. | ||
| + var dcp = state.debugCommandProcessor(false); | ||
| + var request = JSON.stringify(cmd); | ||
| + var response = dcp.processDebugJSONRequest(request); | ||
| + return JSON.parse(response); | ||
| +} | ||
| + | ||
| +function setBreakPointByName(state) { | ||
| + sendCommand(state, { | ||
| + seq: 0, | ||
| + type: "request", | ||
| + command: "setbreakpoint", | ||
| + arguments: { | ||
| + type: "script", | ||
| + target: "testScriptOne", | ||
| + line: 2 | ||
| + } | ||
| + }); | ||
| +} | ||
| + | ||
| +function setBreakPointByRegExp(state) { | ||
| + sendCommand(state, { | ||
| + seq: 0, | ||
| + type: "request", | ||
| + command: "setbreakpoint", | ||
| + arguments: { | ||
| + type: "scriptRegExp", | ||
| + target: "Scrip.Two", | ||
| + line: 2 | ||
| + } | ||
| + }); | ||
| +} | ||
| + | ||
| +function listener(event, exec_state, event_data, data) { | ||
| + try { | ||
| + if (event == Debug.DebugEvent.Break) { | ||
| + switch (break_count) { | ||
| + case 0: | ||
| + // Set break points before the code has been compiled. | ||
| + setBreakPointByName(exec_state); | ||
| + setBreakPointByRegExp(exec_state); | ||
| + break; | ||
| + case 1: | ||
| + // Set the flag to prove that we hit the first break point. | ||
| + test_break_1 = true; | ||
| + break; | ||
| + case 2: | ||
| + // Set the flag to prove that we hit the second break point. | ||
| + test_break_2 = true; | ||
| + break; | ||
| + } | ||
| + break_count++; | ||
| + } | ||
| + } catch (e) { | ||
| + print(e); | ||
| + } | ||
| +} | ||
| + | ||
| +Debug.setListener(listener); | ||
| +debugger; | ||
| + | ||
| +eval('function test1() { \n' + | ||
| + ' assertFalse(test_break_1); \n' + | ||
| + ' assertTrue(test_break_1); \n' + | ||
| + '} \n' + | ||
| + '//@ sourceURL=testScriptOne'); | ||
| + | ||
| +eval('function test2() { \n' + | ||
| + ' assertFalse(test_break_2); \n' + | ||
| + ' assertTrue(test_break_2); \n' + | ||
| + '} \n' + | ||
| + '//@ sourceURL=testScriptTwo'); | ||
| + | ||
| +test1(); | ||
| +test2(); | ||
| +assertEquals(3, break_count); | ||
| + |
| @@ -0,0 +1,40 @@ | ||
| +// Copyright 2011 the V8 project authors. All rights reserved. | ||
| +// Redistribution and use in source and binary forms, with or without | ||
| +// modification, are permitted provided that the following conditions are | ||
| +// met: | ||
| +// | ||
| +// * Redistributions of source code must retain the above copyright | ||
| +// notice, this list of conditions and the following disclaimer. | ||
| +// * Redistributions in binary form must reproduce the above | ||
| +// copyright notice, this list of conditions and the following | ||
| +// disclaimer in the documentation and/or other materials provided | ||
| +// with the distribution. | ||
| +// * Neither the name of Google Inc. nor the names of its | ||
| +// contributors may be used to endorse or promote products derived | ||
| +// from this software without specific prior written permission. | ||
| +// | ||
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +// See: http://code.google.com/p/v8/issues/detail?id=1980 | ||
| + | ||
| +var invalid_this = [ "invalid", 23, undefined, null ]; | ||
| +for (var i = 0; i < invalid_this.length; i++) { | ||
| + var exception = false; | ||
| + try { | ||
| + Error.prototype.toString.call(invalid_this[i]); | ||
| + } catch (e) { | ||
| + exception = true; | ||
| + assertTrue("called_on_non_object" == e.type); | ||
| + } | ||
| + assertTrue(exception); | ||
| +} |
| @@ -0,0 +1,194 @@ | ||
| +# Copyright 2012 the V8 project authors. All rights reserved. | ||
| +# Redistribution and use in source and binary forms, with or without | ||
| +# modification, are permitted provided that the following conditions are | ||
| +# met: | ||
| +# | ||
| +# * Redistributions of source code must retain the above copyright | ||
| +# notice, this list of conditions and the following disclaimer. | ||
| +# * Redistributions in binary form must reproduce the above | ||
| +# copyright notice, this list of conditions and the following | ||
| +# disclaimer in the documentation and/or other materials provided | ||
| +# with the distribution. | ||
| +# * Neither the name of Google Inc. nor the names of its | ||
| +# contributors may be used to endorse or promote products derived | ||
| +# from this software without specific prior written permission. | ||
| +# | ||
| +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| + | ||
| +# This file contains common function definitions for various other shell | ||
| +# scripts in this directory. It is not meant to be executed by itself. | ||
| + | ||
| +# Important: before including this file, the following variables must be set: | ||
| +# - BRANCHNAME | ||
| +# - PERSISTFILE_BASENAME | ||
| + | ||
| +TEMP_BRANCH=$BRANCHNAME-temporary-branch-created-by-script | ||
| +VERSION_FILE="src/version.cc" | ||
| +CHANGELOG_ENTRY_FILE="$PERSISTFILE_BASENAME-changelog-entry" | ||
| +PATCH_FILE="$PERSISTFILE_BASENAME-patch" | ||
| +COMMITMSG_FILE="$PERSISTFILE_BASENAME-commitmsg" | ||
| +TOUCHED_FILES_FILE="$PERSISTFILE_BASENAME-touched-files" | ||
| +TRUNK_REVISION_FILE="$PERSISTFILE_BASENAME-trunkrevision" | ||
| +START_STEP=0 | ||
| +CURRENT_STEP=0 | ||
| + | ||
| +die() { | ||
| + [[ -n "$1" ]] && echo "Error: $1" | ||
| + echo "Exiting." | ||
| + exit 1 | ||
| +} | ||
| + | ||
| +confirm() { | ||
| + echo -n "$1 [Y/n] " | ||
| + read ANSWER | ||
| + if [[ -z "$ANSWER" || "$ANSWER" == "Y" || "$ANSWER" == "y" ]] ; then | ||
| + return 0 | ||
| + else | ||
| + return 1 | ||
| + fi | ||
| +} | ||
| + | ||
| +delete_branch() { | ||
| + local MATCH=$(git branch | grep $1 | awk '{print $NF}' ) | ||
| + if [ "$MATCH" == "$1" ] ; then | ||
| + confirm "Branch $1 exists, do you want to delete it?" | ||
| + if [ $? -eq 0 ] ; then | ||
| + git branch -D $1 || die "Deleting branch '$1' failed." | ||
| + echo "Branch $1 deleted." | ||
| + else | ||
| + die "Can't continue. Please delete branch $1 and try again." | ||
| + fi | ||
| + fi | ||
| +} | ||
| + | ||
| +# Persist and restore variables to support canceling/resuming execution | ||
| +# of this script. | ||
| +persist() { | ||
| + local VARNAME=$1 | ||
| + local FILE="$PERSISTFILE_BASENAME-$VARNAME" | ||
| + echo "${!VARNAME}" > $FILE | ||
| +} | ||
| + | ||
| +restore() { | ||
| + local VARNAME=$1 | ||
| + local FILE="$PERSISTFILE_BASENAME-$VARNAME" | ||
| + local VALUE="$(cat $FILE)" | ||
| + eval "$VARNAME=\"$VALUE\"" | ||
| +} | ||
| + | ||
| +restore_if_unset() { | ||
| + local VARNAME=$1 | ||
| + [[ -z "${!VARNAME}" ]] && restore "$VARNAME" | ||
| + [[ -z "${!VARNAME}" ]] && die "Variable '$VARNAME' could not be restored." | ||
| +} | ||
| + | ||
| +initial_environment_checks() { | ||
| + # Cancel if this is not a git checkout. | ||
| + [[ -d .git ]] \ | ||
| + || die "This is not a git checkout, this script won't work for you." | ||
| + | ||
| + # Cancel if EDITOR is unset or not executable. | ||
| + [[ -n "$EDITOR" && -x "$(which $EDITOR)" ]] \ | ||
| + || die "Please set your EDITOR environment variable, you'll need it." | ||
| +} | ||
| + | ||
| +common_prepare() { | ||
| + # Check for a clean workdir. | ||
| + [[ -z "$(git status -s -uno)" ]] \ | ||
| + || die "Workspace is not clean. Please commit or undo your changes." | ||
| + | ||
| + # Persist current branch. | ||
| + CURRENT_BRANCH=$(git status -s -b -uno | grep "^##" | awk '{print $2}') | ||
| + persist "CURRENT_BRANCH" | ||
| + | ||
| + # Fetch unfetched revisions. | ||
| + git svn fetch || die "'git svn fetch' failed." | ||
| + | ||
| + # Get ahold of a safe temporary branch and check it out. | ||
| + if [ "$CURRENT_BRANCH" != "$TEMP_BRANCH" ] ; then | ||
| + delete_branch $TEMP_BRANCH | ||
| + git checkout -b $TEMP_BRANCH | ||
| + fi | ||
| + | ||
| + # Delete the branch that will be created later if it exists already. | ||
| + delete_branch $BRANCHNAME | ||
| +} | ||
| + | ||
| +common_cleanup() { | ||
| + restore_if_unset "CURRENT_BRANCH" | ||
| + git checkout -f $CURRENT_BRANCH | ||
| + [[ "$TEMP_BRANCH" != "$CURRENT_BRANCH" ]] && git branch -D $TEMP_BRANCH | ||
| + [[ "$BRANCHNAME" != "$CURRENT_BRANCH" ]] && git branch -D $BRANCHNAME | ||
| + # Clean up all temporary files. | ||
| + rm -f "$PERSISTFILE_BASENAME"* | ||
| +} | ||
| + | ||
| +# These two functions take a prefix for the variable names as first argument. | ||
| +read_and_persist_version() { | ||
| + for v in MAJOR_VERSION MINOR_VERSION BUILD_NUMBER PATCH_LEVEL; do | ||
| + VARNAME="$1${v%%_*}" | ||
| + VALUE=$(grep "#define $v" "$VERSION_FILE" | awk '{print $NF}') | ||
| + eval "$VARNAME=\"$VALUE\"" | ||
| + persist "$VARNAME" | ||
| + done | ||
| +} | ||
| +restore_version_if_unset() { | ||
| + for v in MAJOR MINOR BUILD PATCH; do | ||
| + restore_if_unset "$1$v" | ||
| + done | ||
| +} | ||
| + | ||
| +upload_step() { | ||
| + let CURRENT_STEP+=1 | ||
| + if [ $START_STEP -le $CURRENT_STEP ] ; then | ||
| + echo ">>> Step $CURRENT_STEP: Upload for code review." | ||
| + echo -n "Please enter the email address of a V8 reviewer for your patch: " | ||
| + read REVIEWER | ||
| + git cl upload -r "$REVIEWER" --send-mail \ | ||
| + || die "'git cl upload' failed, please try again." | ||
| + fi | ||
| +} | ||
| + | ||
| +wait_for_lgtm() { | ||
| + echo "Please wait for an LGTM, then type \"LGTM<Return>\" to commit your \ | ||
| +change. (If you need to iterate on the patch or double check that it's \ | ||
| +sane, do so in another shell, but remember to not change the headline of \ | ||
| +the uploaded CL." | ||
| + unset ANSWER | ||
| + while [ "$ANSWER" != "LGTM" ] ; do | ||
| + [[ -n "$ANSWER" ]] && echo "That was not 'LGTM'." | ||
| + echo -n "> " | ||
| + read ANSWER | ||
| + done | ||
| +} | ||
| + | ||
| +# Takes a file containing the patch to apply as first argument. | ||
| +apply_patch() { | ||
| + patch -p1 < "$1" | tee >(awk '{print $NF}' >> "$TOUCHED_FILES_FILE") | ||
| + [[ $? -eq 0 ]] || die "Applying the patch failed." | ||
| +} | ||
| + | ||
| +stage_files() { | ||
| + # Stage added and modified files. | ||
| + TOUCHED_FILES=$(cat "$TOUCHED_FILES_FILE") | ||
| + for FILE in $TOUCHED_FILES ; do | ||
| + git add "$FILE" | ||
| + done | ||
| + # Stage deleted files. | ||
| + DELETED_FILES=$(git status -s -uno --porcelain | grep "^ D" \ | ||
| + | awk '{print $NF}') | ||
| + for FILE in $DELETED_FILES ; do | ||
| + git rm "$FILE" | ||
| + done | ||
| + rm -f "$TOUCHED_FILES_FILE" | ||
| +} |