diff options
Diffstat (limited to 'src/3rdparty/webkit/JavaScriptCore/runtime')
32 files changed, 1500 insertions, 1416 deletions
diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/ArgList.h b/src/3rdparty/webkit/JavaScriptCore/runtime/ArgList.h index 8e85d7f..4d571fc 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/ArgList.h +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/ArgList.h @@ -44,7 +44,8 @@ namespace JSC { // Constructor for a read-write list, to which you may append values. // FIXME: Remove all clients of this API, then remove this API. MarkedArgumentBuffer() - : m_markSet(0) + : m_isUsingInlineBuffer(true) + , m_markSet(0) #ifndef NDEBUG , m_isReadOnly(false) #endif @@ -57,6 +58,7 @@ namespace JSC { MarkedArgumentBuffer(Register* buffer, size_t size) : m_buffer(buffer) , m_size(size) + , m_isUsingInlineBuffer(true) , m_markSet(0) #ifndef NDEBUG , m_isReadOnly(true) @@ -103,7 +105,7 @@ namespace JSC { { ASSERT(!m_isReadOnly); - if (m_size < inlineCapacity) { + if (m_isUsingInlineBuffer && m_size < inlineCapacity) { m_vector.uncheckedAppend(v); ++m_size; } else { @@ -111,9 +113,23 @@ namespace JSC { // the performance of the fast "just append to inline buffer" case. slowAppend(v); ++m_size; + m_isUsingInlineBuffer = false; } } + void removeLast() + { + ASSERT(m_size); + m_size--; + m_vector.removeLast(); + } + + JSValue last() + { + ASSERT(m_size); + return m_buffer[m_size - 1].jsValue(); + } + iterator begin() { return m_buffer; } iterator end() { return m_buffer + m_size; } @@ -127,6 +143,7 @@ namespace JSC { Register* m_buffer; size_t m_size; + bool m_isUsingInlineBuffer; VectorType m_vector; ListSet* m_markSet; diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/Collector.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/Collector.cpp index 1e5eab3..0ff97b8 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/Collector.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/Collector.cpp @@ -1,7 +1,6 @@ /* * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2007 Eric Seidel <eric@webkit.org> - * Copyright (C) 2008 Torch Mobile, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,6 +27,7 @@ #include "Interpreter.h" #include "JSGlobalObject.h" #include "JSLock.h" +#include "JSONObject.h" #include "JSString.h" #include "JSValue.h" #include "Nodes.h" @@ -409,54 +409,68 @@ void* Heap::allocateNumber(size_t s) return heapAllocate<NumberHeap>(s); } -#if PLATFORM(WIN_CE) -// Return the number of bytes that are writable starting at p. -// The pointer p is assumed to be page aligned. -static inline DWORD numberOfWritableBytes(void* p) -{ - MEMORY_BASIC_INFORMATION buf; - DWORD result = VirtualQuery(p, &buf, sizeof(buf)); - ASSERT(result == sizeof(buf)); - DWORD protect = (buf.Protect & ~(PAGE_GUARD | PAGE_NOCACHE)); - - // check if the page is writable - if (protect != PAGE_READWRITE && protect != PAGE_WRITECOPY && - protect != PAGE_EXECUTE_READWRITE && protect != PAGE_EXECUTE_WRITECOPY) - return 0; - - if (buf.State != MEM_COMMIT) - return 0; +#if PLATFORM(WINCE) +void* g_stackBase = 0; - return buf.RegionSize; -} - -static DWORD systemPageSize() - { - SYSTEM_INFO sysInfo; - GetSystemInfo(&sysInfo); - return sysInfo.dwPageSize; +inline bool isPageWritable(void* page) +{ + MEMORY_BASIC_INFORMATION memoryInformation; + DWORD result = VirtualQuery(page, &memoryInformation, sizeof(memoryInformation)); + + // return false on error, including ptr outside memory + if (result != sizeof(memoryInformation)) + return false; + + DWORD protect = memoryInformation.Protect & ~(PAGE_GUARD | PAGE_NOCACHE); + return protect == PAGE_READWRITE + || protect == PAGE_WRITECOPY + || protect == PAGE_EXECUTE_READWRITE + || protect == PAGE_EXECUTE_WRITECOPY; } -static inline void* currentThreadStackBaseWinCE() +static void* getStackBase(void* previousFrame) { - static DWORD pageSize = systemPageSize(); - int dummy; - void* sp = &dummy; - char* alignedStackPtr = reinterpret_cast<char*>((DWORD)sp & ~(pageSize - 1)); - DWORD size = 0; - while (size = numberOfWritableBytes(alignedStackPtr)) - alignedStackPtr += size; - return alignedStackPtr; + // find the address of this stack frame by taking the address of a local variable + bool isGrowingDownward; + void* thisFrame = (void*)(&isGrowingDownward); + + isGrowingDownward = previousFrame < &thisFrame; + static DWORD pageSize = 0; + if (!pageSize) { + SYSTEM_INFO systemInfo; + GetSystemInfo(&systemInfo); + pageSize = systemInfo.dwPageSize; + } + + // scan all of memory starting from this frame, and return the last writeable page found + register char* currentPage = (char*)((DWORD)thisFrame & ~(pageSize - 1)); + if (isGrowingDownward) { + while (currentPage > 0) { + // check for underflow + if (currentPage >= (char*)pageSize) + currentPage -= pageSize; + else + currentPage = 0; + if (!isPageWritable(currentPage)) + return currentPage + pageSize; + } + return 0; + } else { + while (true) { + // guaranteed to complete because isPageWritable returns false at end of memory + currentPage += pageSize; + if (!isPageWritable(currentPage)) + return currentPage; + } + } } -#endif // PLATFORM(WIN_CE) +#endif static inline void* currentThreadStackBase() { #if PLATFORM(DARWIN) pthread_t thread = pthread_self(); return pthread_get_stackaddr_np(thread); -#elif PLATFORM(WIN_CE) - return currentThreadStackBaseWinCE(); #elif PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(MSVC) // offset 0x18 from the FS segment register gives a pointer to // the thread information block for the current thread @@ -560,6 +574,13 @@ static inline void* currentThreadStackBase() } return static_cast<char*>(stackBase) + stackSize; #endif +#elif PLATFORM(WINCE) + if (g_stackBase) + return g_stackBase; + else { + int dummy; + return getStackBase(&dummy); + } #else #error Need a way to get the stack base on this platform #endif @@ -1094,6 +1115,8 @@ bool Heap::collect() m_globalData->smallStrings.mark(); if (m_globalData->scopeNodeBeingReparsed) m_globalData->scopeNodeBeingReparsed->mark(); + if (m_globalData->firstStringifierToMark) + JSONObject::markStringifiers(m_globalData->firstStringifierToMark); JAVASCRIPTCORE_GC_MARKED(); diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/CommonIdentifiers.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/CommonIdentifiers.cpp index fe0a830..3837817 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/CommonIdentifiers.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/CommonIdentifiers.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2007, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -23,12 +23,13 @@ namespace JSC { -const char* const nullCString = 0; +static const char* const nullCString = 0; #define INITIALIZE_PROPERTY_NAME(name) , name(globalData, #name) CommonIdentifiers::CommonIdentifiers(JSGlobalData* globalData) : nullIdentifier(globalData, nullCString) + , emptyIdentifier(globalData, "") , underscoreProto(globalData, "__proto__") , thisIdentifier(globalData, "this") JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PROPERTY_NAME) diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/CommonIdentifiers.h b/src/3rdparty/webkit/JavaScriptCore/runtime/CommonIdentifiers.h index d4c5d52..408d819 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/CommonIdentifiers.h +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/CommonIdentifiers.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003,2007 Apple Computer, Inc + * Copyright (C) 2003, 2007, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -59,6 +59,8 @@ macro(test) \ macro(toExponential) \ macro(toFixed) \ + macro(toISOString) \ + macro(toJSON) \ macro(toLocaleString) \ macro(toPrecision) \ macro(toString) \ @@ -75,6 +77,7 @@ namespace JSC { public: const Identifier nullIdentifier; + const Identifier emptyIdentifier; const Identifier underscoreProto; const Identifier thisIdentifier; diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/DateConstructor.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/DateConstructor.cpp index 54362d0..6d7d934 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/DateConstructor.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/DateConstructor.cpp @@ -22,8 +22,8 @@ #include "config.h" #include "DateConstructor.h" +#include "DateConversion.h" #include "DateInstance.h" -#include "DateMath.h" #include "DatePrototype.h" #include "JSFunction.h" #include "JSGlobalObject.h" @@ -32,8 +32,13 @@ #include "PrototypeFunction.h" #include <math.h> #include <time.h> +#include <wtf/DateMath.h> #include <wtf/MathExtras.h> +#if PLATFORM(WINCE) && !PLATFORM(QT) +extern "C" time_t time(time_t* timer); //provided by libce +#endif + #if HAVE(SYS_TIME_H) #include <sys/time.h> #endif @@ -42,6 +47,8 @@ #include <sys/timeb.h> #endif +using namespace WTF; + namespace JSC { // TODO: MakeTime (15.9.11.1) etc. ? diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/DateConversion.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/DateConversion.cpp new file mode 100644 index 0000000..a725478 --- /dev/null +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/DateConversion.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Alternatively, the contents of this file may be used under the terms + * of either the Mozilla Public License Version 1.1, found at + * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public + * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html + * (the "GPL"), in which case the provisions of the MPL or the GPL are + * applicable instead of those above. If you wish to allow use of your + * version of this file only under the terms of one of those two + * licenses (the MPL or the GPL) and not to allow others to use your + * version of this file under the LGPL, indicate your decision by + * deletingthe provisions above and replace them with the notice and + * other provisions required by the MPL or the GPL, as the case may be. + * If you do not delete the provisions above, a recipient may use your + * version of this file under any of the LGPL, the MPL or the GPL. + */ + +#include "config.h" +#include "DateConversion.h" + +#include "UString.h" +#include <wtf/DateMath.h> +#include <wtf/StringExtras.h> + +using namespace WTF; + +namespace JSC { + +double parseDate(const UString &date) +{ + return parseDateFromNullTerminatedCharacters(date.UTF8String().c_str()); +} + +UString formatDate(const GregorianDateTime &t) +{ + char buffer[100]; + snprintf(buffer, sizeof(buffer), "%s %s %02d %04d", + weekdayName[(t.weekDay + 6) % 7], + monthName[t.month], t.monthDay, t.year + 1900); + return buffer; +} + +UString formatDateUTCVariant(const GregorianDateTime &t) +{ + char buffer[100]; + snprintf(buffer, sizeof(buffer), "%s, %02d %s %04d", + weekdayName[(t.weekDay + 6) % 7], + t.monthDay, monthName[t.month], t.year + 1900); + return buffer; +} + +UString formatTime(const GregorianDateTime &t, bool utc) +{ + char buffer[100]; + if (utc) { + snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", t.hour, t.minute, t.second); + } else { + int offset = abs(gmtoffset(t)); + char timeZoneName[70]; + struct tm gtm = t; + strftime(timeZoneName, sizeof(timeZoneName), "%Z", >m); + + if (timeZoneName[0]) { + snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d (%s)", + t.hour, t.minute, t.second, + gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60, timeZoneName); + } else { + snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d", + t.hour, t.minute, t.second, + gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60); + } + } + return UString(buffer); +} + +} // namespace JSC diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/DateConversion.h b/src/3rdparty/webkit/JavaScriptCore/runtime/DateConversion.h new file mode 100644 index 0000000..0d12815 --- /dev/null +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/DateConversion.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + */ + +#ifndef DateConversion_h +#define DateConversion_h + +namespace WTF { + struct GregorianDateTime; +} + +namespace JSC { + +class UString; + +double parseDate(const UString&); +UString formatDate(const WTF::GregorianDateTime&); +UString formatDateUTCVariant(const WTF::GregorianDateTime&); +UString formatTime(const WTF::GregorianDateTime&, bool inputIsUTC); + +} // namespace JSC + +#endif // DateConversion_h diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/DateInstance.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/DateInstance.cpp index 8806dec..62791ae 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/DateInstance.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/DateInstance.cpp @@ -22,10 +22,12 @@ #include "config.h" #include "DateInstance.h" -#include "DateMath.h" #include <math.h> +#include <wtf/DateMath.h> #include <wtf/MathExtras.h> +using namespace WTF; + namespace JSC { struct DateInstance::Cache { @@ -58,13 +60,13 @@ void DateInstance::msToGregorianDateTime(double milli, bool outputIsUTC, Gregori if (outputIsUTC) { if (m_cache->m_gregorianDateTimeUTCCachedForMS != milli) { - JSC::msToGregorianDateTime(milli, true, m_cache->m_cachedGregorianDateTimeUTC); + WTF::msToGregorianDateTime(milli, true, m_cache->m_cachedGregorianDateTimeUTC); m_cache->m_gregorianDateTimeUTCCachedForMS = milli; } t.copyFrom(m_cache->m_cachedGregorianDateTimeUTC); } else { if (m_cache->m_gregorianDateTimeCachedForMS != milli) { - JSC::msToGregorianDateTime(milli, false, m_cache->m_cachedGregorianDateTime); + WTF::msToGregorianDateTime(milli, false, m_cache->m_cachedGregorianDateTime); m_cache->m_gregorianDateTimeCachedForMS = milli; } t.copyFrom(m_cache->m_cachedGregorianDateTime); diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/DateInstance.h b/src/3rdparty/webkit/JavaScriptCore/runtime/DateInstance.h index 0ecd1db..3b73521 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/DateInstance.h +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/DateInstance.h @@ -23,9 +23,11 @@ #include "JSWrapperObject.h" -namespace JSC { - +namespace WTF { struct GregorianDateTime; +} + +namespace JSC { class DateInstance : public JSWrapperObject { public: @@ -34,14 +36,14 @@ namespace JSC { double internalNumber() const { return internalValue().uncheckedGetNumber(); } - bool getTime(GregorianDateTime&, int& offset) const; - bool getUTCTime(GregorianDateTime&) const; + bool getTime(WTF::GregorianDateTime&, int& offset) const; + bool getUTCTime(WTF::GregorianDateTime&) const; bool getTime(double& milliseconds, int& offset) const; bool getUTCTime(double& milliseconds) const; static const ClassInfo info; - void msToGregorianDateTime(double, bool outputIsUTC, GregorianDateTime&) const; + void msToGregorianDateTime(double, bool outputIsUTC, WTF::GregorianDateTime&) const; private: virtual const ClassInfo* classInfo() const { return &info; } diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/DateMath.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/DateMath.cpp deleted file mode 100644 index 2f8c88c..0000000 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/DateMath.cpp +++ /dev/null @@ -1,935 +0,0 @@ -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * - * The Original Code is Mozilla Communicator client code, released - * March 31, 1998. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Alternatively, the contents of this file may be used under the terms - * of either the Mozilla Public License Version 1.1, found at - * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public - * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html - * (the "GPL"), in which case the provisions of the MPL or the GPL are - * applicable instead of those above. If you wish to allow use of your - * version of this file only under the terms of one of those two - * licenses (the MPL or the GPL) and not to allow others to use your - * version of this file under the LGPL, indicate your decision by - * deletingthe provisions above and replace them with the notice and - * other provisions required by the MPL or the GPL, as the case may be. - * If you do not delete the provisions above, a recipient may use your - * version of this file under any of the LGPL, the MPL or the GPL. - */ - -#include "config.h" -#include "DateMath.h" - -#include "JSNumberCell.h" -#include <math.h> -#include <stdint.h> -#include <time.h> -#include <wtf/ASCIICType.h> -#include <wtf/Assertions.h> -#include <wtf/CurrentTime.h> -#include <wtf/MathExtras.h> -#include <wtf/StringExtras.h> - -#if HAVE(ERRNO_H) -#include <errno.h> -#endif - -#if PLATFORM(DARWIN) -#include <notify.h> -#endif - -#if HAVE(SYS_TIME_H) -#include <sys/time.h> -#endif - -#if HAVE(SYS_TIMEB_H) -#include <sys/timeb.h> -#endif - -using namespace WTF; - -namespace JSC { - -/* Constants */ - -static const double minutesPerDay = 24.0 * 60.0; -static const double secondsPerDay = 24.0 * 60.0 * 60.0; -static const double secondsPerYear = 24.0 * 60.0 * 60.0 * 365.0; - -static const double usecPerSec = 1000000.0; - -static const double maxUnixTime = 2145859200.0; // 12/31/2037 - -// Day of year for the first day of each month, where index 0 is January, and day 0 is January 1. -// First for non-leap years, then for leap years. -static const int firstDayOfMonth[2][12] = { - {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, - {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} -}; - -static inline bool isLeapYear(int year) -{ - if (year % 4 != 0) - return false; - if (year % 400 == 0) - return true; - if (year % 100 == 0) - return false; - return true; -} - -static inline int daysInYear(int year) -{ - return 365 + isLeapYear(year); -} - -static inline double daysFrom1970ToYear(int year) -{ - // The Gregorian Calendar rules for leap years: - // Every fourth year is a leap year. 2004, 2008, and 2012 are leap years. - // However, every hundredth year is not a leap year. 1900 and 2100 are not leap years. - // Every four hundred years, there's a leap year after all. 2000 and 2400 are leap years. - - static const int leapDaysBefore1971By4Rule = 1970 / 4; - static const int excludedLeapDaysBefore1971By100Rule = 1970 / 100; - static const int leapDaysBefore1971By400Rule = 1970 / 400; - - const double yearMinusOne = year - 1; - const double yearsToAddBy4Rule = floor(yearMinusOne / 4.0) - leapDaysBefore1971By4Rule; - const double yearsToExcludeBy100Rule = floor(yearMinusOne / 100.0) - excludedLeapDaysBefore1971By100Rule; - const double yearsToAddBy400Rule = floor(yearMinusOne / 400.0) - leapDaysBefore1971By400Rule; - - return 365.0 * (year - 1970) + yearsToAddBy4Rule - yearsToExcludeBy100Rule + yearsToAddBy400Rule; -} - -static inline double msToDays(double ms) -{ - return floor(ms / msPerDay); -} - -static inline int msToYear(double ms) -{ - int approxYear = static_cast<int>(floor(ms / (msPerDay * 365.2425)) + 1970); - double msFromApproxYearTo1970 = msPerDay * daysFrom1970ToYear(approxYear); - if (msFromApproxYearTo1970 > ms) - return approxYear - 1; - if (msFromApproxYearTo1970 + msPerDay * daysInYear(approxYear) <= ms) - return approxYear + 1; - return approxYear; -} - -static inline int dayInYear(double ms, int year) -{ - return static_cast<int>(msToDays(ms) - daysFrom1970ToYear(year)); -} - -static inline double msToMilliseconds(double ms) -{ - double result = fmod(ms, msPerDay); - if (result < 0) - result += msPerDay; - return result; -} - -// 0: Sunday, 1: Monday, etc. -static inline int msToWeekDay(double ms) -{ - int wd = (static_cast<int>(msToDays(ms)) + 4) % 7; - if (wd < 0) - wd += 7; - return wd; -} - -static inline int msToSeconds(double ms) -{ - double result = fmod(floor(ms / msPerSecond), secondsPerMinute); - if (result < 0) - result += secondsPerMinute; - return static_cast<int>(result); -} - -static inline int msToMinutes(double ms) -{ - double result = fmod(floor(ms / msPerMinute), minutesPerHour); - if (result < 0) - result += minutesPerHour; - return static_cast<int>(result); -} - -static inline int msToHours(double ms) -{ - double result = fmod(floor(ms/msPerHour), hoursPerDay); - if (result < 0) - result += hoursPerDay; - return static_cast<int>(result); -} - -static inline int monthFromDayInYear(int dayInYear, bool leapYear) -{ - const int d = dayInYear; - int step; - - if (d < (step = 31)) - return 0; - step += (leapYear ? 29 : 28); - if (d < step) - return 1; - if (d < (step += 31)) - return 2; - if (d < (step += 30)) - return 3; - if (d < (step += 31)) - return 4; - if (d < (step += 30)) - return 5; - if (d < (step += 31)) - return 6; - if (d < (step += 31)) - return 7; - if (d < (step += 30)) - return 8; - if (d < (step += 31)) - return 9; - if (d < (step += 30)) - return 10; - return 11; -} - -static inline bool checkMonth(int dayInYear, int& startDayOfThisMonth, int& startDayOfNextMonth, int daysInThisMonth) -{ - startDayOfThisMonth = startDayOfNextMonth; - startDayOfNextMonth += daysInThisMonth; - return (dayInYear <= startDayOfNextMonth); -} - -static inline int dayInMonthFromDayInYear(int dayInYear, bool leapYear) -{ - const int d = dayInYear; - int step; - int next = 30; - - if (d <= next) - return d + 1; - const int daysInFeb = (leapYear ? 29 : 28); - if (checkMonth(d, step, next, daysInFeb)) - return d - step; - if (checkMonth(d, step, next, 31)) - return d - step; - if (checkMonth(d, step, next, 30)) - return d - step; - if (checkMonth(d, step, next, 31)) - return d - step; - if (checkMonth(d, step, next, 30)) - return d - step; - if (checkMonth(d, step, next, 31)) - return d - step; - if (checkMonth(d, step, next, 31)) - return d - step; - if (checkMonth(d, step, next, 30)) - return d - step; - if (checkMonth(d, step, next, 31)) - return d - step; - if (checkMonth(d, step, next, 30)) - return d - step; - step = next; - return d - step; -} - -static inline int monthToDayInYear(int month, bool isLeapYear) -{ - return firstDayOfMonth[isLeapYear][month]; -} - -static inline double timeToMS(double hour, double min, double sec, double ms) -{ - return (((hour * minutesPerHour + min) * secondsPerMinute + sec) * msPerSecond + ms); -} - -static int dateToDayInYear(int year, int month, int day) -{ - year += month / 12; - - month %= 12; - if (month < 0) { - month += 12; - --year; - } - - int yearday = static_cast<int>(floor(daysFrom1970ToYear(year))); - int monthday = monthToDayInYear(month, isLeapYear(year)); - - return yearday + monthday + day - 1; -} - -double getCurrentUTCTime() -{ - return floor(getCurrentUTCTimeWithMicroseconds()); -} - -// Returns current time in milliseconds since 1 Jan 1970. -double getCurrentUTCTimeWithMicroseconds() -{ - return currentTime() * 1000.0; -} - -void getLocalTime(const time_t* localTime, struct tm* localTM) -{ -#if COMPILER(MSVC7) || COMPILER(MINGW) || PLATFORM(WIN_CE) - *localTM = *localtime(localTime); -#elif COMPILER(MSVC) - localtime_s(localTM, localTime); -#else - localtime_r(localTime, localTM); -#endif -} - -// There is a hard limit at 2038 that we currently do not have a workaround -// for (rdar://problem/5052975). -static inline int maximumYearForDST() -{ - return 2037; -} - -static inline int minimumYearForDST() -{ - // Because of the 2038 issue (see maximumYearForDST) if the current year is - // greater than the max year minus 27 (2010), we want to use the max year - // minus 27 instead, to ensure there is a range of 28 years that all years - // can map to. - return std::min(msToYear(getCurrentUTCTime()), maximumYearForDST() - 27) ; -} - -/* - * Find an equivalent year for the one given, where equivalence is deterined by - * the two years having the same leapness and the first day of the year, falling - * on the same day of the week. - * - * This function returns a year between this current year and 2037, however this - * function will potentially return incorrect results if the current year is after - * 2010, (rdar://problem/5052975), if the year passed in is before 1900 or after - * 2100, (rdar://problem/5055038). - */ -int equivalentYearForDST(int year) -{ - // It is ok if the cached year is not the current year as long as the rules - // for DST did not change between the two years; if they did the app would need - // to be restarted. - static int minYear = minimumYearForDST(); - int maxYear = maximumYearForDST(); - - int difference; - if (year > maxYear) - difference = minYear - year; - else if (year < minYear) - difference = maxYear - year; - else - return year; - - int quotient = difference / 28; - int product = (quotient) * 28; - - year += product; - ASSERT((year >= minYear && year <= maxYear) || (product - year == static_cast<int>(NaN))); - return year; -} - -static int32_t calculateUTCOffset() -{ - tm localt; - memset(&localt, 0, sizeof(localt)); - - // get the difference between this time zone and UTC on Jan 01, 2000 12:00:00 AM - localt.tm_mday = 1; - localt.tm_year = 100; - time_t utcOffset = 946684800 - mktime(&localt); - - return static_cast<int32_t>(utcOffset * 1000); -} - -#if PLATFORM(DARWIN) -static int32_t s_cachedUTCOffset; // In milliseconds. An assumption here is that access to an int32_t variable is atomic on platforms that take this code path. -static bool s_haveCachedUTCOffset; -static int s_notificationToken; -#endif - -/* - * Get the difference in milliseconds between this time zone and UTC (GMT) - * NOT including DST. - */ -double getUTCOffset() -{ -#if PLATFORM(DARWIN) - if (s_haveCachedUTCOffset) { - int notified; - uint32_t status = notify_check(s_notificationToken, ¬ified); - if (status == NOTIFY_STATUS_OK && !notified) - return s_cachedUTCOffset; - } -#endif - - int32_t utcOffset = calculateUTCOffset(); - -#if PLATFORM(DARWIN) - // Theoretically, it is possible that several threads will be executing this code at once, in which case we will have a race condition, - // and a newer value may be overwritten. In practice, time zones don't change that often. - s_cachedUTCOffset = utcOffset; -#endif - - return utcOffset; -} - -/* - * Get the DST offset for the time passed in. Takes - * seconds (not milliseconds) and cannot handle dates before 1970 - * on some OS' - */ -static double getDSTOffsetSimple(double localTimeSeconds, double utcOffset) -{ - if (localTimeSeconds > maxUnixTime) - localTimeSeconds = maxUnixTime; - else if (localTimeSeconds < 0) // Go ahead a day to make localtime work (does not work with 0) - localTimeSeconds += secondsPerDay; - - //input is UTC so we have to shift back to local time to determine DST thus the + getUTCOffset() - double offsetTime = (localTimeSeconds * msPerSecond) + utcOffset; - - // Offset from UTC but doesn't include DST obviously - int offsetHour = msToHours(offsetTime); - int offsetMinute = msToMinutes(offsetTime); - - // FIXME: time_t has a potential problem in 2038 - time_t localTime = static_cast<time_t>(localTimeSeconds); - - tm localTM; - getLocalTime(&localTime, &localTM); - - double diff = ((localTM.tm_hour - offsetHour) * secondsPerHour) + ((localTM.tm_min - offsetMinute) * 60); - - if (diff < 0) - diff += secondsPerDay; - - return (diff * msPerSecond); -} - -// Get the DST offset, given a time in UTC -static double getDSTOffset(double ms, double utcOffset) -{ - // On Mac OS X, the call to localtime (see getDSTOffsetSimple) will return historically accurate - // DST information (e.g. New Zealand did not have DST from 1946 to 1974) however the JavaScript - // standard explicitly dictates that historical information should not be considered when - // determining DST. For this reason we shift away from years that localtime can handle but would - // return historically accurate information. - int year = msToYear(ms); - int equivalentYear = equivalentYearForDST(year); - if (year != equivalentYear) { - bool leapYear = isLeapYear(year); - int dayInYearLocal = dayInYear(ms, year); - int dayInMonth = dayInMonthFromDayInYear(dayInYearLocal, leapYear); - int month = monthFromDayInYear(dayInYearLocal, leapYear); - int day = dateToDayInYear(equivalentYear, month, dayInMonth); - ms = (day * msPerDay) + msToMilliseconds(ms); - } - - return getDSTOffsetSimple(ms / msPerSecond, utcOffset); -} - -double gregorianDateTimeToMS(const GregorianDateTime& t, double milliSeconds, bool inputIsUTC) -{ - int day = dateToDayInYear(t.year + 1900, t.month, t.monthDay); - double ms = timeToMS(t.hour, t.minute, t.second, milliSeconds); - double result = (day * msPerDay) + ms; - - if (!inputIsUTC) { // convert to UTC - double utcOffset = getUTCOffset(); - result -= utcOffset; - result -= getDSTOffset(result, utcOffset); - } - - return result; -} - -void msToGregorianDateTime(double ms, bool outputIsUTC, GregorianDateTime& tm) -{ - // input is UTC - double dstOff = 0.0; - const double utcOff = getUTCOffset(); - - if (!outputIsUTC) { // convert to local time - dstOff = getDSTOffset(ms, utcOff); - ms += dstOff + utcOff; - } - - const int year = msToYear(ms); - tm.second = msToSeconds(ms); - tm.minute = msToMinutes(ms); - tm.hour = msToHours(ms); - tm.weekDay = msToWeekDay(ms); - tm.yearDay = dayInYear(ms, year); - tm.monthDay = dayInMonthFromDayInYear(tm.yearDay, isLeapYear(year)); - tm.month = monthFromDayInYear(tm.yearDay, isLeapYear(year)); - tm.year = year - 1900; - tm.isDST = dstOff != 0.0; - - tm.utcOffset = static_cast<long>((dstOff + utcOff) / msPerSecond); - tm.timeZone = NULL; -} - -void initDateMath() -{ -#ifndef NDEBUG - static bool alreadyInitialized; - ASSERT(!alreadyInitialized++); -#endif - - equivalentYearForDST(2000); // Need to call once to initialize a static used in this function. -#if PLATFORM(DARWIN) - // Register for a notification whenever the time zone changes. - uint32_t status = notify_register_check("com.apple.system.timezone", &s_notificationToken); - if (status == NOTIFY_STATUS_OK) { - s_cachedUTCOffset = calculateUTCOffset(); - s_haveCachedUTCOffset = true; - } -#endif -} - -static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, int second) -{ - double days = (day - 32075) - + floor(1461 * (year + 4800.0 + (mon - 14) / 12) / 4) - + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12 - - floor(3 * ((year + 4900.0 + (mon - 14) / 12) / 100) / 4) - - 2440588; - return ((days * hoursPerDay + hour) * minutesPerHour + minute) * secondsPerMinute + second; -} - -// We follow the recommendation of RFC 2822 to consider all -// obsolete time zones not listed here equivalent to "-0000". -static const struct KnownZone { -#if !PLATFORM(WIN_OS) - const -#endif - char tzName[4]; - int tzOffset; -} known_zones[] = { - { "UT", 0 }, - { "GMT", 0 }, - { "EST", -300 }, - { "EDT", -240 }, - { "CST", -360 }, - { "CDT", -300 }, - { "MST", -420 }, - { "MDT", -360 }, - { "PST", -480 }, - { "PDT", -420 } -}; - -inline static void skipSpacesAndComments(const char*& s) -{ - int nesting = 0; - char ch; - while ((ch = *s)) { - if (!isASCIISpace(ch)) { - if (ch == '(') - nesting++; - else if (ch == ')' && nesting > 0) - nesting--; - else if (nesting == 0) - break; - } - s++; - } -} - -// returns 0-11 (Jan-Dec); -1 on failure -static int findMonth(const char* monthStr) -{ - ASSERT(monthStr); - char needle[4]; - for (int i = 0; i < 3; ++i) { - if (!*monthStr) - return -1; - needle[i] = static_cast<char>(toASCIILower(*monthStr++)); - } - needle[3] = '\0'; - const char *haystack = "janfebmaraprmayjunjulaugsepoctnovdec"; - const char *str = strstr(haystack, needle); - if (str) { - int position = static_cast<int>(str - haystack); - if (position % 3 == 0) - return position / 3; - } - return -1; -} - -static bool parseLong(const char* string, char** stopPosition, int base, long* result) -{ - *result = strtol(string, stopPosition, base); - // Avoid the use of errno as it is not available on Windows CE - if (string == *stopPosition || *result == LONG_MIN || *result == LONG_MAX) - return false; - return true; -} - -double parseDate(const UString &date) -{ - // This parses a date in the form: - // Tuesday, 09-Nov-99 23:12:40 GMT - // or - // Sat, 01-Jan-2000 08:00:00 GMT - // or - // Sat, 01 Jan 2000 08:00:00 GMT - // or - // 01 Jan 99 22:00 +0100 (exceptions in rfc822/rfc2822) - // ### non RFC formats, added for Javascript: - // [Wednesday] January 09 1999 23:12:40 GMT - // [Wednesday] January 09 23:12:40 GMT 1999 - // - // We ignore the weekday. - - CString dateCString = date.UTF8String(); - const char *dateString = dateCString.c_str(); - - // Skip leading space - skipSpacesAndComments(dateString); - - long month = -1; - const char *wordStart = dateString; - // Check contents of first words if not number - while (*dateString && !isASCIIDigit(*dateString)) { - if (isASCIISpace(*dateString) || *dateString == '(') { - if (dateString - wordStart >= 3) - month = findMonth(wordStart); - skipSpacesAndComments(dateString); - wordStart = dateString; - } else - dateString++; - } - - // Missing delimiter between month and day (like "January29")? - if (month == -1 && wordStart != dateString) - month = findMonth(wordStart); - - skipSpacesAndComments(dateString); - - if (!*dateString) - return NaN; - - // ' 09-Nov-99 23:12:40 GMT' - char* newPosStr; - long day; - if (!parseLong(dateString, &newPosStr, 10, &day)) - return NaN; - dateString = newPosStr; - - if (!*dateString) - return NaN; - - if (day < 0) - return NaN; - - long year = 0; - if (day > 31) { - // ### where is the boundary and what happens below? - if (*dateString != '/') - return NaN; - // looks like a YYYY/MM/DD date - if (!*++dateString) - return NaN; - year = day; - if (!parseLong(dateString, &newPosStr, 10, &month)) - return NaN; - month -= 1; - dateString = newPosStr; - if (*dateString++ != '/' || !*dateString) - return NaN; - if (!parseLong(dateString, &newPosStr, 10, &day)) - return NaN; - dateString = newPosStr; - } else if (*dateString == '/' && month == -1) { - dateString++; - // This looks like a MM/DD/YYYY date, not an RFC date. - month = day - 1; // 0-based - if (!parseLong(dateString, &newPosStr, 10, &day)) - return NaN; - if (day < 1 || day > 31) - return NaN; - dateString = newPosStr; - if (*dateString == '/') - dateString++; - if (!*dateString) - return NaN; - } else { - if (*dateString == '-') - dateString++; - - skipSpacesAndComments(dateString); - - if (*dateString == ',') - dateString++; - - if (month == -1) { // not found yet - month = findMonth(dateString); - if (month == -1) - return NaN; - - while (*dateString && *dateString != '-' && *dateString != ',' && !isASCIISpace(*dateString)) - dateString++; - - if (!*dateString) - return NaN; - - // '-99 23:12:40 GMT' - if (*dateString != '-' && *dateString != '/' && *dateString != ',' && !isASCIISpace(*dateString)) - return NaN; - dateString++; - } - } - - if (month < 0 || month > 11) - return NaN; - - // '99 23:12:40 GMT' - if (year <= 0 && *dateString) { - if (!parseLong(dateString, &newPosStr, 10, &year)) - return NaN; - } - - // Don't fail if the time is missing. - long hour = 0; - long minute = 0; - long second = 0; - if (!*newPosStr) - dateString = newPosStr; - else { - // ' 23:12:40 GMT' - if (!(isASCIISpace(*newPosStr) || *newPosStr == ',')) { - if (*newPosStr != ':') - return NaN; - // There was no year; the number was the hour. - year = -1; - } else { - // in the normal case (we parsed the year), advance to the next number - dateString = ++newPosStr; - skipSpacesAndComments(dateString); - } - - parseLong(dateString, &newPosStr, 10, &hour); - // Do not check for errno here since we want to continue - // even if errno was set becasue we are still looking - // for the timezone! - - // Read a number? If not, this might be a timezone name. - if (newPosStr != dateString) { - dateString = newPosStr; - - if (hour < 0 || hour > 23) - return NaN; - - if (!*dateString) - return NaN; - - // ':12:40 GMT' - if (*dateString++ != ':') - return NaN; - - if (!parseLong(dateString, &newPosStr, 10, &minute)) - return NaN; - dateString = newPosStr; - - if (minute < 0 || minute > 59) - return NaN; - - // ':40 GMT' - if (*dateString && *dateString != ':' && !isASCIISpace(*dateString)) - return NaN; - - // seconds are optional in rfc822 + rfc2822 - if (*dateString ==':') { - dateString++; - - if (!parseLong(dateString, &newPosStr, 10, &second)) - return NaN; - dateString = newPosStr; - - if (second < 0 || second > 59) - return NaN; - } - - skipSpacesAndComments(dateString); - - if (strncasecmp(dateString, "AM", 2) == 0) { - if (hour > 12) - return NaN; - if (hour == 12) - hour = 0; - dateString += 2; - skipSpacesAndComments(dateString); - } else if (strncasecmp(dateString, "PM", 2) == 0) { - if (hour > 12) - return NaN; - if (hour != 12) - hour += 12; - dateString += 2; - skipSpacesAndComments(dateString); - } - } - } - - bool haveTZ = false; - int offset = 0; - - // Don't fail if the time zone is missing. - // Some websites omit the time zone (4275206). - if (*dateString) { - if (strncasecmp(dateString, "GMT", 3) == 0 || strncasecmp(dateString, "UTC", 3) == 0) { - dateString += 3; - haveTZ = true; - } - - if (*dateString == '+' || *dateString == '-') { - long o; - if (!parseLong(dateString, &newPosStr, 10, &o)) - return NaN; - dateString = newPosStr; - - if (o < -9959 || o > 9959) - return NaN; - - int sgn = (o < 0) ? -1 : 1; - o = abs(o); - if (*dateString != ':') { - offset = ((o / 100) * 60 + (o % 100)) * sgn; - } else { // GMT+05:00 - long o2; - if (!parseLong(dateString, &newPosStr, 10, &o2)) - return NaN; - dateString = newPosStr; - offset = (o * 60 + o2) * sgn; - } - haveTZ = true; - } else { - for (int i = 0; i < int(sizeof(known_zones) / sizeof(KnownZone)); i++) { - if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) { - offset = known_zones[i].tzOffset; - dateString += strlen(known_zones[i].tzName); - haveTZ = true; - break; - } - } - } - } - - skipSpacesAndComments(dateString); - - if (*dateString && year == -1) { - if (!parseLong(dateString, &newPosStr, 10, &year)) - return NaN; - dateString = newPosStr; - } - - skipSpacesAndComments(dateString); - - // Trailing garbage - if (*dateString) - return NaN; - - // Y2K: Handle 2 digit years. - if (year >= 0 && year < 100) { - if (year < 50) - year += 2000; - else - year += 1900; - } - - // fall back to local timezone - if (!haveTZ) { - GregorianDateTime t; - t.monthDay = day; - t.month = month; - t.year = year - 1900; - t.isDST = -1; - t.second = second; - t.minute = minute; - t.hour = hour; - - // Use our gregorianDateTimeToMS() rather than mktime() as the latter can't handle the full year range. - return gregorianDateTimeToMS(t, 0, false); - } - - return (ymdhmsToSeconds(year, month + 1, day, hour, minute, second) - (offset * 60.0)) * msPerSecond; -} - -double timeClip(double t) -{ - if (!isfinite(t)) - return NaN; - if (fabs(t) > 8.64E15) - return NaN; - return trunc(t); -} - -UString formatDate(const GregorianDateTime &t) -{ - char buffer[100]; - snprintf(buffer, sizeof(buffer), "%s %s %02d %04d", - weekdayName[(t.weekDay + 6) % 7], - monthName[t.month], t.monthDay, t.year + 1900); - return buffer; -} - -UString formatDateUTCVariant(const GregorianDateTime &t) -{ - char buffer[100]; - snprintf(buffer, sizeof(buffer), "%s, %02d %s %04d", - weekdayName[(t.weekDay + 6) % 7], - t.monthDay, monthName[t.month], t.year + 1900); - return buffer; -} - -UString formatTime(const GregorianDateTime &t, bool utc) -{ - char buffer[100]; - if (utc) { - snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", t.hour, t.minute, t.second); - } else { - int offset = abs(gmtoffset(t)); - char timeZoneName[70]; - struct tm gtm = t; - strftime(timeZoneName, sizeof(timeZoneName), "%Z", >m); - - if (timeZoneName[0]) { - snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d (%s)", - t.hour, t.minute, t.second, - gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60, timeZoneName); - } else { - snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d", - t.hour, t.minute, t.second, - gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60); - } - } - return UString(buffer); -} - -} // namespace JSC diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/DateMath.h b/src/3rdparty/webkit/JavaScriptCore/runtime/DateMath.h deleted file mode 100644 index 8a15c80..0000000 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/DateMath.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Communicator client code, released - * March 31, 1998. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - */ - -#ifndef DateMath_h -#define DateMath_h - -#include <time.h> -#include <string.h> -#include <wtf/Noncopyable.h> - -namespace JSC { - -class UString; -struct GregorianDateTime; - -void initDateMath(); -void msToGregorianDateTime(double, bool outputIsUTC, GregorianDateTime&); -double gregorianDateTimeToMS(const GregorianDateTime&, double, bool inputIsUTC); -double getUTCOffset(); -int equivalentYearForDST(int year); -double getCurrentUTCTime(); -double getCurrentUTCTimeWithMicroseconds(); -void getLocalTime(const time_t*, tm*); - -// Not really math related, but this is currently the only shared place to put these. -double parseDate(const UString&); -double timeClip(double); -UString formatDate(const GregorianDateTime&); -UString formatDateUTCVariant(const GregorianDateTime&); -UString formatTime(const GregorianDateTime&, bool inputIsUTC); - - -const char * const weekdayName[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; -const char * const monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - -const double hoursPerDay = 24.0; -const double minutesPerHour = 60.0; -const double secondsPerHour = 60.0 * 60.0; -const double secondsPerMinute = 60.0; -const double msPerSecond = 1000.0; -const double msPerMinute = 60.0 * 1000.0; -const double msPerHour = 60.0 * 60.0 * 1000.0; -const double msPerDay = 24.0 * 60.0 * 60.0 * 1000.0; - -// Intentionally overridding the default tm of the system -// Tee members of tm differ on various operating systems. -struct GregorianDateTime : Noncopyable { - GregorianDateTime() - : second(0) - , minute(0) - , hour(0) - , weekDay(0) - , monthDay(0) - , yearDay(0) - , month(0) - , year(0) - , isDST(0) - , utcOffset(0) - , timeZone(0) - { - } - - ~GregorianDateTime() - { - delete [] timeZone; - } - - GregorianDateTime(const tm& inTm) - : second(inTm.tm_sec) - , minute(inTm.tm_min) - , hour(inTm.tm_hour) - , weekDay(inTm.tm_wday) - , monthDay(inTm.tm_mday) - , yearDay(inTm.tm_yday) - , month(inTm.tm_mon) - , year(inTm.tm_year) - , isDST(inTm.tm_isdst) - { -#if !PLATFORM(WIN_OS) && !PLATFORM(SOLARIS) && !COMPILER(RVCT) - utcOffset = static_cast<int>(inTm.tm_gmtoff); - - int inZoneSize = strlen(inTm.tm_zone) + 1; - timeZone = new char[inZoneSize]; - strncpy(timeZone, inTm.tm_zone, inZoneSize); -#else - utcOffset = static_cast<int>(getUTCOffset() / msPerSecond + (isDST ? secondsPerHour : 0)); - timeZone = 0; -#endif - } - - operator tm() const - { - tm ret; - memset(&ret, 0, sizeof(ret)); - - ret.tm_sec = second; - ret.tm_min = minute; - ret.tm_hour = hour; - ret.tm_wday = weekDay; - ret.tm_mday = monthDay; - ret.tm_yday = yearDay; - ret.tm_mon = month; - ret.tm_year = year; - ret.tm_isdst = isDST; - -#if !PLATFORM(WIN_OS) && !PLATFORM(SOLARIS) && !COMPILER(RVCT) - ret.tm_gmtoff = static_cast<long>(utcOffset); - ret.tm_zone = timeZone; -#endif - - return ret; - } - - void copyFrom(const GregorianDateTime& rhs) - { - second = rhs.second; - minute = rhs.minute; - hour = rhs.hour; - weekDay = rhs.weekDay; - monthDay = rhs.monthDay; - yearDay = rhs.yearDay; - month = rhs.month; - year = rhs.year; - isDST = rhs.isDST; - utcOffset = rhs.utcOffset; - if (rhs.timeZone) { - int inZoneSize = strlen(rhs.timeZone) + 1; - timeZone = new char[inZoneSize]; - strncpy(timeZone, rhs.timeZone, inZoneSize); - } else - timeZone = 0; - } - - int second; - int minute; - int hour; - int weekDay; - int monthDay; - int yearDay; - int month; - int year; - int isDST; - int utcOffset; - char* timeZone; -}; - -static inline int gmtoffset(const GregorianDateTime& t) -{ - return t.utcOffset; -} - -} // namespace JSC - -#endif // DateMath_h diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/DatePrototype.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/DatePrototype.cpp index ff3fb19..e2482f4 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/DatePrototype.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/DatePrototype.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Torch Mobile, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,7 +23,7 @@ #include "config.h" #include "DatePrototype.h" -#include "DateMath.h" +#include "DateConversion.h" #include "Error.h" #include "JSString.h" #include "ObjectPrototype.h" @@ -38,6 +39,7 @@ #include <math.h> #include <time.h> #include <wtf/Assertions.h> +#include <wtf/DateMath.h> #include <wtf/MathExtras.h> #include <wtf/StringExtras.h> #include <wtf/UnusedParam.h> @@ -58,6 +60,10 @@ #include <CoreFoundation/CoreFoundation.h> #endif +#if PLATFORM(WINCE) && !PLATFORM(QT) +extern "C" size_t strftime(char * const s, const size_t maxsize, const char * const format, const struct tm * const t); //provided by libce +#endif + using namespace WTF; namespace JSC { @@ -107,6 +113,9 @@ static JSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*, JSObjec static JSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&); static JSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*, JSObject*, JSValue, const ArgList&); static JSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*, JSObject*, JSValue, const ArgList&); + +static JSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*, JSObject*, JSValue, const ArgList&); } @@ -189,6 +198,9 @@ static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, L { #if HAVE(LANGINFO_H) static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT }; +#elif PLATFORM(WINCE) && !PLATFORM(QT) + // strftime() we are using does not support # + static const char* const formatStrings[] = { "%c", "%x", "%X" }; #else static const char* const formatStrings[] = { "%#c", "%#x", "%X" }; #endif @@ -333,6 +345,7 @@ const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, 0, ExecState /* Source for DatePrototype.lut.h @begin dateTable toString dateProtoFuncToString DontEnum|Function 0 + toISOString dateProtoFuncToISOString DontEnum|Function 0 toUTCString dateProtoFuncToUTCString DontEnum|Function 0 toDateString dateProtoFuncToDateString DontEnum|Function 0 toTimeString dateProtoFuncToTimeString DontEnum|Function 0 @@ -376,6 +389,7 @@ const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, 0, ExecState setUTCFullYear dateProtoFuncSetUTCFullYear DontEnum|Function 3 setYear dateProtoFuncSetYear DontEnum|Function 1 getYear dateProtoFuncGetYear DontEnum|Function 0 + toJSON dateProtoFuncToJSON DontEnum|Function 0 @end */ @@ -429,6 +443,28 @@ JSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec, JSObject*, JSVal return jsNontrivialString(exec, formatDateUTCVariant(t) + " " + formatTime(t, utc)); } +JSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + if (!thisValue.isObject(&DateInstance::info)) + return throwError(exec, TypeError); + + const bool utc = true; + + DateInstance* thisDateObj = asDateInstance(thisValue); + double milli = thisDateObj->internalNumber(); + if (!isfinite(milli)) + return jsNontrivialString(exec, "Invalid Date"); + + GregorianDateTime t; + thisDateObj->msToGregorianDateTime(milli, utc, t); + // Maximum amount of space we need in buffer: 6 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + // 6 for formatting and one for null termination = 23. We add one extra character to allow us to force null termination. + char buffer[24]; + snprintf(buffer, sizeof(buffer) - 1, "%04d-%02d-%02dT%02d:%02d:%02dZ", 1900 + t.year, t.month + 1, t.monthDay, t.hour, t.minute, t.second); + buffer[sizeof(buffer) - 1] = 0; + return jsNontrivialString(exec, buffer); +} + JSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { if (!thisValue.isObject(&DateInstance::info)) @@ -1043,4 +1079,27 @@ JSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec, JSObject*, JSValue t return jsNumber(exec, t.year); } +JSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + JSObject* object = thisValue.toThisObject(exec); + if (exec->hadException()) + return jsNull(); + + JSValue toISOValue = object->get(exec, exec->globalData().propertyNames->toISOString); + if (exec->hadException()) + return jsNull(); + + CallData callData; + CallType callType = toISOValue.getCallData(callData); + if (callType == CallTypeNone) + return throwError(exec, TypeError, "toISOString is not a function"); + + JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList()); + if (exec->hadException()) + return jsNull(); + if (result.isObject()) + return throwError(exec, TypeError, "toISOString did not return a primitive value"); + return result; +} + } // namespace JSC diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/InitializeThreading.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/InitializeThreading.cpp index cda9fb1..a0620e7 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/InitializeThreading.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/InitializeThreading.cpp @@ -31,11 +31,11 @@ #include "JSImmediate.h" #include "Collector.h" -#include "DateMath.h" #include "dtoa.h" #include "Identifier.h" #include "JSGlobalObject.h" #include "UString.h" +#include <wtf/DateMath.h> #include <wtf/Threading.h> using namespace WTF; @@ -52,7 +52,7 @@ static void initializeThreadingOnce() initializeUString(); #if ENABLE(JSC_MULTIPLE_THREADS) s_dtoaP5Mutex = new Mutex; - initDateMath(); + WTF::initializeDates(); #endif } diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/JSFunction.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/JSFunction.cpp index f456451..b79074f 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/JSFunction.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/JSFunction.cpp @@ -48,7 +48,7 @@ const ClassInfo JSFunction::info = { "Function", &InternalFunction::info, 0, 0 } JSFunction::JSFunction(ExecState* exec, PassRefPtr<Structure> structure, int length, const Identifier& name, NativeFunction func) : Base(&exec->globalData(), structure, name) #if ENABLE(JIT) - , m_body(exec->globalData().nativeFunctionThunk()) + , m_body(FunctionBodyNode::createNativeThunk(&exec->globalData())) #else , m_body(0) #endif @@ -76,22 +76,19 @@ JSFunction::~JSFunction() // JIT code for other functions may have had calls linked directly to the code for this function; these links // are based on a check for the this pointer value for this JSFunction - which will no longer be valid once // this memory is freed and may be reused (potentially for another, different JSFunction). - if (!isHostFunction()) { - if (m_body && m_body->isGenerated()) - m_body->generatedBytecode().unlinkCallers(); - scopeChain().~ScopeChain(); - } - + if (m_body && m_body->isGenerated()) + m_body->generatedBytecode().unlinkCallers(); #endif + if (!isHostFunction()) + scopeChain().~ScopeChain(); } void JSFunction::mark() { Base::mark(); - if (!isHostFunction()) { - m_body->mark(); + m_body->mark(); + if (!isHostFunction()) scopeChain().mark(); - } } CallType JSFunction::getCallData(CallData& callData) diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalData.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalData.cpp index 1594848..d5c4ee4 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalData.cpp @@ -60,6 +60,7 @@ using namespace WTF; namespace JSC { extern const HashTable arrayTable; +extern const HashTable jsonTable; extern const HashTable dateTable; extern const HashTable mathTable; extern const HashTable numberTable; @@ -105,6 +106,7 @@ JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet) , clientData(0) , arrayTable(fastNew<HashTable>(JSC::arrayTable)) , dateTable(fastNew<HashTable>(JSC::dateTable)) + , jsonTable(fastNew<HashTable>(JSC::jsonTable)) , mathTable(fastNew<HashTable>(JSC::mathTable)) , numberTable(fastNew<HashTable>(JSC::numberTable)) , regExpTable(fastNew<HashTable>(JSC::regExpTable)) @@ -137,6 +139,7 @@ JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet) , head(0) , dynamicGlobalObject(0) , scopeNodeBeingReparsed(0) + , firstStringifierToMark(0) { #if PLATFORM(MAC) startProfilerServerIfNeeded(); @@ -155,17 +158,16 @@ JSGlobalData::~JSGlobalData() arrayTable->deleteTable(); dateTable->deleteTable(); + jsonTable->deleteTable(); mathTable->deleteTable(); numberTable->deleteTable(); regExpTable->deleteTable(); regExpConstructorTable->deleteTable(); stringTable->deleteTable(); -#if ENABLE(JIT) - lazyNativeFunctionThunk.clear(); -#endif fastDelete(const_cast<HashTable*>(arrayTable)); fastDelete(const_cast<HashTable*>(dateTable)); + fastDelete(const_cast<HashTable*>(jsonTable)); fastDelete(const_cast<HashTable*>(mathTable)); fastDelete(const_cast<HashTable*>(numberTable)); fastDelete(const_cast<HashTable*>(regExpTable)); @@ -222,15 +224,6 @@ JSGlobalData*& JSGlobalData::sharedInstanceInternal() return sharedInstance; } -#if ENABLE(JIT) - -void JSGlobalData::createNativeThunk() -{ - lazyNativeFunctionThunk = FunctionBodyNode::createNativeThunk(this); -} - -#endif - // FIXME: We can also detect forms like v1 < v2 ? -1 : 0, reverse comparison, etc. const Vector<Instruction>& JSGlobalData::numericCompareFunction(ExecState* exec) { diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalData.h b/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalData.h index e53746b..96a3c2c 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalData.h +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalData.h @@ -54,8 +54,10 @@ namespace JSC { class Lexer; class Parser; class ScopeNode; + class Stringifier; class Structure; class UString; + struct HashTable; struct VPtrSet; @@ -82,6 +84,7 @@ namespace JSC { const HashTable* arrayTable; const HashTable* dateTable; + const HashTable* jsonTable; const HashTable* mathTable; const HashTable* numberTable; const HashTable* regExpTable; @@ -117,20 +120,13 @@ namespace JSC { Interpreter* interpreter; #if ENABLE(JIT) JITThunks jitStubs; - FunctionBodyNode* nativeFunctionThunk() - { - if (!lazyNativeFunctionThunk) - createNativeThunk(); - return lazyNativeFunctionThunk.get(); - } - RefPtr<FunctionBodyNode> lazyNativeFunctionThunk; #endif TimeoutChecker timeoutChecker; Heap heap; JSValue exception; #if ENABLE(JIT) - void* exceptionLocation; + ReturnAddressPtr exceptionLocation; #endif const Vector<Instruction>& numericCompareFunction(ExecState*); @@ -145,6 +141,7 @@ namespace JSC { HashSet<JSObject*> arrayVisitedElements; ScopeNode* scopeNodeBeingReparsed; + Stringifier* firstStringifierToMark; private: JSGlobalData(bool isShared, const VPtrSet&); diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalObject.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalObject.cpp index 1e9f670..c56b84b 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -50,6 +50,7 @@ #include "JSFunction.h" #include "JSGlobalObjectFunctions.h" #include "JSLock.h" +#include "JSONObject.h" #include "Interpreter.h" #include "MathObject.h" #include "NativeErrorConstructor.h" @@ -318,7 +319,8 @@ void JSGlobalObject::reset(JSValue prototype) GlobalPropertyInfo(Identifier(exec, "Math"), new (exec) MathObject(exec, MathObject::createStructure(d()->objectPrototype)), DontEnum | DontDelete), GlobalPropertyInfo(Identifier(exec, "NaN"), jsNaN(exec), DontEnum | DontDelete), GlobalPropertyInfo(Identifier(exec, "Infinity"), jsNumber(exec, Inf), DontEnum | DontDelete), - GlobalPropertyInfo(Identifier(exec, "undefined"), jsUndefined(), DontEnum | DontDelete) + GlobalPropertyInfo(Identifier(exec, "undefined"), jsUndefined(), DontEnum | DontDelete), + GlobalPropertyInfo(Identifier(exec, "JSON"), new (exec) JSONObject(JSONObject::createStructure(d()->objectPrototype)), DontEnum | DontDelete) }; addStaticGlobals(staticGlobals, sizeof(staticGlobals) / sizeof(GlobalPropertyInfo)); diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalObject.h b/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalObject.h index da9a819..983274b 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalObject.h +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalObject.h @@ -169,7 +169,7 @@ namespace JSC { virtual void mark(); virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); - virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable); + virtual bool hasOwnPropertyForWrite(ExecState*, const Identifier&); virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes); @@ -325,10 +325,12 @@ namespace JSC { return symbolTableGet(propertyName, slot); } - inline bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot, bool& slotIsWriteable) + inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, const Identifier& propertyName) { - if (JSVariableObject::getOwnPropertySlotForWrite(exec, propertyName, slot, slotIsWriteable)) + PropertySlot slot; + if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot)) return true; + bool slotIsWriteable; return symbolTableGet(propertyName, slot, slotIsWriteable); } diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp index b013957..85f92f2 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp @@ -282,7 +282,7 @@ JSValue JSC_HOST_CALL globalFuncEval(ExecState* exec, JSObject* function, JSValu UString s = x.toString(exec); - LiteralParser preparser(exec, s); + LiteralParser preparser(exec, s, LiteralParser::NonStrictJSON); if (JSValue parsedObject = preparser.tryLiteralParse()) return parsedObject; diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/JSONObject.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/JSONObject.cpp new file mode 100644 index 0000000..4a89c55 --- /dev/null +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/JSONObject.cpp @@ -0,0 +1,766 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "config.h" +#include "JSONObject.h" + +#include "BooleanObject.h" +#include "Error.h" +#include "ExceptionHelpers.h" +#include "JSArray.h" +#include "LiteralParser.h" +#include "PropertyNameArray.h" +#include <wtf/MathExtras.h> + +namespace JSC { + +ASSERT_CLASS_FITS_IN_CELL(JSONObject); + +static JSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*, JSObject*, JSValue, const ArgList&); + +} + +#include "JSONObject.lut.h" + +namespace JSC { + +// PropertyNameForFunctionCall objects must be on the stack, since the JSValue that they create is not marked. +class PropertyNameForFunctionCall { +public: + PropertyNameForFunctionCall(const Identifier&); + PropertyNameForFunctionCall(unsigned); + + JSValue value(ExecState*) const; + +private: + const Identifier* m_identifier; + unsigned m_number; + mutable JSValue m_value; +}; + +class Stringifier : Noncopyable { +public: + Stringifier(ExecState*, JSValue replacer, JSValue space); + ~Stringifier(); + JSValue stringify(JSValue); + + void mark(); + +private: + typedef UString StringBuilder; + + class Holder { + public: + Holder(JSObject*); + + JSObject* object() const { return m_object; } + + bool appendNextProperty(Stringifier&, StringBuilder&); + + private: + JSObject* const m_object; + const bool m_isArray; + bool m_isJSArray; + unsigned m_index; + unsigned m_size; + RefPtr<PropertyNameArrayData> m_propertyNames; + }; + + friend class Holder; + + static void appendQuotedString(StringBuilder&, const UString&); + + JSValue toJSON(JSValue, const PropertyNameForFunctionCall&); + + enum StringifyResult { StringifyFailed, StringifySucceeded, StringifyFailedDueToUndefinedValue }; + StringifyResult appendStringifiedValue(StringBuilder&, JSValue, JSObject* holder, const PropertyNameForFunctionCall&); + + bool willIndent() const; + void indent(); + void unindent(); + void startNewLine(StringBuilder&) const; + + Stringifier* const m_nextStringifierToMark; + ExecState* const m_exec; + const JSValue m_replacer; + bool m_usingArrayReplacer; + PropertyNameArray m_arrayReplacerPropertyNames; + CallType m_replacerCallType; + CallData m_replacerCallData; + const UString m_gap; + + HashSet<JSObject*> m_holderCycleDetector; + Vector<Holder, 16> m_holderStack; + UString m_repeatedGap; + UString m_indent; +}; + +// ------------------------------ helper functions -------------------------------- + +static inline JSValue unwrapBoxedPrimitive(JSValue value) +{ + if (!value.isObject()) + return value; + if (!asObject(value)->inherits(&NumberObject::info) && !asObject(value)->inherits(&StringObject::info) && !asObject(value)->inherits(&BooleanObject::info)) + return value; + return static_cast<JSWrapperObject*>(asObject(value))->internalValue(); +} + +static inline UString gap(JSValue space) +{ + space = unwrapBoxedPrimitive(space); + + // If the space value is a number, create a gap string with that number of spaces. + double spaceCount; + if (space.getNumber(spaceCount)) { + const int maxSpaceCount = 100; + int count; + if (spaceCount > maxSpaceCount) + count = maxSpaceCount; + else if (!(spaceCount > 0)) + count = 0; + else + count = static_cast<int>(spaceCount); + UChar spaces[maxSpaceCount]; + for (int i = 0; i < count; ++i) + spaces[i] = ' '; + return UString(spaces, count); + } + + // If the space value is a string, use it as the gap string, otherwise use no gap string. + return space.getString(); +} + +// ------------------------------ PropertyNameForFunctionCall -------------------------------- + +inline PropertyNameForFunctionCall::PropertyNameForFunctionCall(const Identifier& identifier) + : m_identifier(&identifier) +{ +} + +inline PropertyNameForFunctionCall::PropertyNameForFunctionCall(unsigned number) + : m_identifier(0) + , m_number(number) +{ +} + +JSValue PropertyNameForFunctionCall::value(ExecState* exec) const +{ + if (!m_value) { + if (m_identifier) + m_value = jsString(exec, m_identifier->ustring()); + else + m_value = jsNumber(exec, m_number); + } + return m_value; +} + +// ------------------------------ Stringifier -------------------------------- + +Stringifier::Stringifier(ExecState* exec, JSValue replacer, JSValue space) + : m_nextStringifierToMark(exec->globalData().firstStringifierToMark) + , m_exec(exec) + , m_replacer(replacer) + , m_usingArrayReplacer(false) + , m_arrayReplacerPropertyNames(exec) + , m_replacerCallType(CallTypeNone) + , m_gap(gap(space)) +{ + exec->globalData().firstStringifierToMark = this; + + if (!m_replacer.isObject()) + return; + + if (asObject(m_replacer)->inherits(&JSArray::info)) { + m_usingArrayReplacer = true; + JSObject* array = asObject(m_replacer); + unsigned length = array->get(exec, exec->globalData().propertyNames->length).toUInt32(exec); + for (unsigned i = 0; i < length; ++i) { + JSValue name = array->get(exec, i); + if (exec->hadException()) + break; + UString propertyName; + if (!name.getString(propertyName)) + continue; + if (exec->hadException()) + return; + m_arrayReplacerPropertyNames.add(Identifier(exec, propertyName)); + } + return; + } + + m_replacerCallType = asObject(m_replacer)->getCallData(m_replacerCallData); +} + +Stringifier::~Stringifier() +{ + ASSERT(m_exec->globalData().firstStringifierToMark == this); + m_exec->globalData().firstStringifierToMark = m_nextStringifierToMark; +} + +void Stringifier::mark() +{ + for (Stringifier* stringifier = this; stringifier; stringifier = stringifier->m_nextStringifierToMark) { + size_t size = m_holderStack.size(); + for (size_t i = 0; i < size; ++i) { + JSObject* object = m_holderStack[i].object(); + if (!object->marked()) + object->mark(); + } + } +} + +JSValue Stringifier::stringify(JSValue value) +{ + JSObject* object = constructEmptyObject(m_exec); + if (m_exec->hadException()) + return jsNull(); + + PropertyNameForFunctionCall emptyPropertyName(m_exec->globalData().propertyNames->emptyIdentifier); + object->putDirect(m_exec->globalData().propertyNames->emptyIdentifier, value); + + StringBuilder result; + if (appendStringifiedValue(result, value, object, emptyPropertyName) != StringifySucceeded) + return jsUndefined(); + if (m_exec->hadException()) + return jsNull(); + + return jsString(m_exec, result); +} + +void Stringifier::appendQuotedString(StringBuilder& builder, const UString& value) +{ + int length = value.size(); + + // String length plus 2 for quote marks plus 8 so we can accomodate a few escaped characters. + builder.reserveCapacity(builder.size() + length + 2 + 8); + + builder.append('"'); + + const UChar* data = value.data(); + for (int i = 0; i < length; ++i) { + int start = i; + while (i < length && (data[i] > 0x1F && data[i] != '"' && data[i] != '\\')) + ++i; + builder.append(data + start, i - start); + if (i >= length) + break; + switch (data[i]) { + case '\t': + builder.append('\\'); + builder.append('t'); + break; + case '\r': + builder.append('\\'); + builder.append('r'); + break; + case '\n': + builder.append('\\'); + builder.append('n'); + break; + case '\f': + builder.append('\\'); + builder.append('f'); + break; + case '\b': + builder.append('\\'); + builder.append('b'); + break; + case '"': + builder.append('\\'); + builder.append('"'); + break; + case '\\': + builder.append('\\'); + builder.append('\\'); + break; + default: + static const char hexDigits[] = "0123456789abcdef"; + UChar ch = data[i]; + UChar hex[] = { '\\', 'u', hexDigits[(ch >> 12) & 0xF], hexDigits[(ch >> 8) & 0xF], hexDigits[(ch >> 4) & 0xF], hexDigits[ch & 0xF] }; + builder.append(hex, sizeof(hex) / sizeof(UChar)); + break; + } + } + + builder.append('"'); +} + +inline JSValue Stringifier::toJSON(JSValue value, const PropertyNameForFunctionCall& propertyName) +{ + ASSERT(!m_exec->hadException()); + if (!value.isObject() || !asObject(value)->hasProperty(m_exec, m_exec->globalData().propertyNames->toJSON)) + return value; + + JSValue toJSONFunction = asObject(value)->get(m_exec, m_exec->globalData().propertyNames->toJSON); + if (m_exec->hadException()) + return jsNull(); + + if (!toJSONFunction.isObject()) + return value; + + JSObject* object = asObject(toJSONFunction); + CallData callData; + CallType callType = object->getCallData(callData); + if (callType == CallTypeNone) + return value; + + JSValue list[] = { propertyName.value(m_exec) }; + ArgList args(list, sizeof(list) / sizeof(JSValue)); + return call(m_exec, object, callType, callData, value, args); +} + +Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& builder, JSValue value, JSObject* holder, const PropertyNameForFunctionCall& propertyName) +{ + // Call the toJSON function. + value = toJSON(value, propertyName); + if (m_exec->hadException()) + return StringifyFailed; + if (value.isUndefined() && !holder->inherits(&JSArray::info)) + return StringifyFailedDueToUndefinedValue; + + // Call the replacer function. + if (m_replacerCallType != CallTypeNone) { + JSValue list[] = { propertyName.value(m_exec), value }; + ArgList args(list, sizeof(list) / sizeof(JSValue)); + value = call(m_exec, m_replacer, m_replacerCallType, m_replacerCallData, holder, args); + if (m_exec->hadException()) + return StringifyFailed; + } + + if (value.isNull()) { + builder.append("null"); + return StringifySucceeded; + } + + value = unwrapBoxedPrimitive(value); + + if (value.isBoolean()) { + builder.append(value.getBoolean() ? "true" : "false"); + return StringifySucceeded; + } + + UString stringValue; + if (value.getString(stringValue)) { + appendQuotedString(builder, stringValue); + return StringifySucceeded; + } + + double numericValue; + if (value.getNumber(numericValue)) { + if (!isfinite(numericValue)) + builder.append("null"); + else + builder.append(UString::from(numericValue)); + return StringifySucceeded; + } + + if (!value.isObject()) + return StringifyFailed; + + JSObject* object = asObject(value); + + // Handle cycle detection, and put the holder on the stack. + if (!m_holderCycleDetector.add(object).second) { + throwError(m_exec, TypeError); + return StringifyFailed; + } + bool holderStackWasEmpty = m_holderStack.isEmpty(); + m_holderStack.append(object); + if (!holderStackWasEmpty) + return StringifySucceeded; + + // If this is the outermost call, then loop to handle everything on the holder stack. + TimeoutChecker localTimeoutChecker(m_exec->globalData().timeoutChecker); + localTimeoutChecker.reset(); + unsigned tickCount = localTimeoutChecker.ticksUntilNextCheck(); + do { + while (m_holderStack.last().appendNextProperty(*this, builder)) { + if (m_exec->hadException()) + return StringifyFailed; + if (!--tickCount) { + if (localTimeoutChecker.didTimeOut(m_exec)) { + m_exec->setException(createInterruptedExecutionException(&m_exec->globalData())); + return StringifyFailed; + } + tickCount = localTimeoutChecker.ticksUntilNextCheck(); + } + } + m_holderCycleDetector.remove(m_holderStack.last().object()); + m_holderStack.removeLast(); + } while (!m_holderStack.isEmpty()); + return StringifySucceeded; +} + +inline bool Stringifier::willIndent() const +{ + return !m_gap.isEmpty(); +} + +inline void Stringifier::indent() +{ + // Use a single shared string, m_repeatedGap, so we don't keep allocating new ones as we indent and unindent. + int newSize = m_indent.size() + m_gap.size(); + if (newSize > m_repeatedGap.size()) + m_repeatedGap.append(m_gap); + ASSERT(newSize <= m_repeatedGap.size()); + m_indent = m_repeatedGap.substr(0, newSize); +} + +inline void Stringifier::unindent() +{ + ASSERT(m_indent.size() >= m_gap.size()); + m_indent = m_repeatedGap.substr(0, m_indent.size() - m_gap.size()); +} + +inline void Stringifier::startNewLine(StringBuilder& builder) const +{ + if (m_gap.isEmpty()) + return; + builder.append('\n'); + builder.append(m_indent); +} + +inline Stringifier::Holder::Holder(JSObject* object) + : m_object(object) + , m_isArray(object->inherits(&JSArray::info)) + , m_index(0) +{ +} + +bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBuilder& builder) +{ + ASSERT(m_index <= m_size); + + ExecState* exec = stringifier.m_exec; + + // First time through, initialize. + if (!m_index) { + if (m_isArray) { + m_isJSArray = isJSArray(&exec->globalData(), m_object); + m_size = m_object->get(exec, exec->globalData().propertyNames->length).toUInt32(exec); + builder.append('['); + } else { + if (stringifier.m_usingArrayReplacer) + m_propertyNames = stringifier.m_arrayReplacerPropertyNames.data(); + else { + PropertyNameArray objectPropertyNames(exec); + m_object->getPropertyNames(exec, objectPropertyNames); + m_propertyNames = objectPropertyNames.releaseData(); + } + m_size = m_propertyNames->propertyNameVector().size(); + builder.append('{'); + } + stringifier.indent(); + } + + // Last time through, finish up and return false. + if (m_index == m_size) { + stringifier.unindent(); + if (m_size && builder[builder.size() - 1] != '{') + stringifier.startNewLine(builder); + builder.append(m_isArray ? ']' : '}'); + return false; + } + + // Handle a single element of the array or object. + unsigned index = m_index++; + unsigned rollBackPoint = 0; + StringifyResult stringifyResult; + if (m_isArray) { + // Get the value. + JSValue value; + if (m_isJSArray && asArray(m_object)->canGetIndex(index)) + value = asArray(m_object)->getIndex(index); + else { + PropertySlot slot(m_object); + if (!m_object->getOwnPropertySlot(exec, index, slot)) + slot.setUndefined(); + if (exec->hadException()) + return false; + value = slot.getValue(exec, index); + } + + // Append the separator string. + if (index) + builder.append(','); + stringifier.startNewLine(builder); + + // Append the stringified value. + stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object, index); + } else { + // Get the value. + PropertySlot slot(m_object); + Identifier& propertyName = m_propertyNames->propertyNameVector()[index]; + if (!m_object->getOwnPropertySlot(exec, propertyName, slot)) + return true; + JSValue value = slot.getValue(exec, propertyName); + if (exec->hadException()) + return false; + + rollBackPoint = builder.size(); + + // Append the separator string. + if (builder[rollBackPoint - 1] != '{') + builder.append(','); + stringifier.startNewLine(builder); + + // Append the property name. + appendQuotedString(builder, propertyName.ustring()); + builder.append(':'); + if (stringifier.willIndent()) + builder.append(' '); + + // Append the stringified value. + stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object, propertyName); + } + + // From this point on, no access to the this pointer or to any members, because the + // Holder object may have moved if the call to stringify pushed a new Holder onto + // m_holderStack. + + switch (stringifyResult) { + case StringifyFailed: + builder.append("null"); + break; + case StringifySucceeded: + break; + case StringifyFailedDueToUndefinedValue: + // This only occurs when get an undefined value for an object property. + // In this case we don't want the separator and property name that we + // already appended, so roll back. + builder = builder.substr(0, rollBackPoint); + break; + } + + return true; +} + +// ------------------------------ JSONObject -------------------------------- + +const ClassInfo JSONObject::info = { "JSON", 0, 0, ExecState::jsonTable }; + +/* Source for JSONObject.lut.h +@begin jsonTable + parse JSONProtoFuncParse DontEnum|Function 1 + stringify JSONProtoFuncStringify DontEnum|Function 1 +@end +*/ + +// ECMA 15.8 + +bool JSONObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + const HashEntry* entry = ExecState::jsonTable(exec)->entry(exec, propertyName); + if (!entry) + return JSObject::getOwnPropertySlot(exec, propertyName, slot); + + ASSERT(entry->attributes() & Function); + setUpStaticFunctionSlot(exec, entry, this, propertyName, slot); + return true; +} + +void JSONObject::markStringifiers(Stringifier* stringifier) +{ + stringifier->mark(); +} + +class Walker { +public: + Walker(ExecState* exec, JSObject* function, CallType callType, CallData callData) + : m_exec(exec) + , m_function(function) + , m_callType(callType) + , m_callData(callData) + { + } + JSValue walk(JSValue unfiltered); +private: + JSValue callReviver(JSValue property, JSValue unfiltered) + { + JSValue args[] = { property, unfiltered }; + ArgList argList(args, 2); + return call(m_exec, m_function, m_callType, m_callData, jsNull(), argList); + } + + friend class Holder; + + ExecState* m_exec; + JSObject* m_function; + CallType m_callType; + CallData m_callData; +}; + +enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember, + ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember }; +NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) +{ + Vector<PropertyNameArray, 16> propertyStack; + Vector<uint32_t, 16> indexStack; + Vector<JSObject*, 16> objectStack; + Vector<JSArray*, 16> arrayStack; + + Vector<WalkerState, 16> stateStack; + WalkerState state = StateUnknown; + JSValue inValue = unfiltered; + JSValue outValue = jsNull(); + while (1) { + switch (state) { + arrayStartState: + case ArrayStartState: { + ASSERT(inValue.isObject()); + ASSERT(isJSArray(&m_exec->globalData(), asObject(inValue))); + JSArray* array = asArray(inValue); + arrayStack.append(array); + indexStack.append(0); + // fallthrough + } + arrayStartVisitMember: + case ArrayStartVisitMember: { + JSArray* array = arrayStack.last(); + uint32_t index = indexStack.last(); + if (index == array->length()) { + outValue = array; + arrayStack.removeLast(); + indexStack.removeLast(); + break; + } + inValue = array->getIndex(index); + if (inValue.isObject()) { + stateStack.append(ArrayEndVisitMember); + goto stateUnknown; + } else + outValue = inValue; + // fallthrough + } + case ArrayEndVisitMember: { + JSArray* array = arrayStack.last(); + array->setIndex(indexStack.last(), callReviver(jsString(m_exec, UString::from(indexStack.last())), outValue)); + if (m_exec->hadException()) + return jsNull(); + indexStack.last()++; + goto arrayStartVisitMember; + } + objectStartState: + case ObjectStartState: { + ASSERT(inValue.isObject()); + ASSERT(!isJSArray(&m_exec->globalData(), asObject(inValue))); + JSObject* object = asObject(inValue); + objectStack.append(object); + indexStack.append(0); + propertyStack.append(PropertyNameArray(m_exec)); + object->getPropertyNames(m_exec, propertyStack.last()); + // fallthrough + } + objectStartVisitMember: + case ObjectStartVisitMember: { + JSObject* object = objectStack.last(); + uint32_t index = indexStack.last(); + PropertyNameArray& properties = propertyStack.last(); + if (index == properties.size()) { + outValue = object; + objectStack.removeLast(); + indexStack.removeLast(); + propertyStack.removeLast(); + break; + } + PropertySlot slot; + object->getOwnPropertySlot(m_exec, properties[index], slot); + inValue = slot.getValue(m_exec, properties[index]); + ASSERT(!m_exec->hadException()); + if (inValue.isObject()) { + stateStack.append(ObjectEndVisitMember); + goto stateUnknown; + } else + outValue = inValue; + // fallthrough + } + case ObjectEndVisitMember: { + JSObject* object = objectStack.last(); + Identifier prop = propertyStack.last()[indexStack.last()]; + PutPropertySlot slot; + object->put(m_exec, prop, callReviver(jsString(m_exec, prop.ustring()), outValue), slot); + if (m_exec->hadException()) + return jsNull(); + indexStack.last()++; + goto objectStartVisitMember; + } + stateUnknown: + case StateUnknown: + if (!inValue.isObject()) { + outValue = inValue; + break; + } + if (isJSArray(&m_exec->globalData(), asObject(inValue))) + goto arrayStartState; + goto objectStartState; + } + if (stateStack.isEmpty()) + break; + state = stateStack.last(); + stateStack.removeLast(); + } + return callReviver(jsEmptyString(m_exec), outValue); +} + +// ECMA-262 v5 15.12.2 +JSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + if (args.isEmpty()) + return throwError(exec, GeneralError, "JSON.parse requires at least one parameter"); + JSValue value = args.at(0); + UString source = value.toString(exec); + if (exec->hadException()) + return jsNull(); + + LiteralParser jsonParser(exec, source, LiteralParser::StrictJSON); + JSValue unfiltered = jsonParser.tryLiteralParse(); + if (!unfiltered) + return throwError(exec, SyntaxError, "Unable to parse JSON string"); + + if (args.size() < 2) + return unfiltered; + + JSValue function = args.at(1); + CallData callData; + CallType callType = function.getCallData(callData); + if (callType == CallTypeNone) + return unfiltered; + return Walker(exec, asObject(function), callType, callData).walk(unfiltered); +} + +// ECMA-262 v5 15.12.3 +JSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + if (args.isEmpty()) + return throwError(exec, GeneralError, "No input to stringify"); + JSValue value = args.at(0); + JSValue replacer = args.at(1); + JSValue space = args.at(2); + return Stringifier(exec, replacer, space).stringify(value); +} + +} // namespace JSC diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/JSONObject.h b/src/3rdparty/webkit/JavaScriptCore/runtime/JSONObject.h new file mode 100644 index 0000000..8d5364a --- /dev/null +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/JSONObject.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 JSONObject_h +#define JSONObject_h + +#include "JSObject.h" + +namespace JSC { + + class Stringifier; + + class JSONObject : public JSObject { + public: + JSONObject(PassRefPtr<Structure> structure) + : JSObject(structure) + { + } + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType)); + } + + static void markStringifiers(Stringifier*); + + private: + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + +} // namespace JSC + +#endif // JSONObject_h diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/JSObject.h b/src/3rdparty/webkit/JavaScriptCore/runtime/JSObject.h index 54805f2..db47ac7 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/JSObject.h +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/JSObject.h @@ -203,9 +203,6 @@ namespace JSC { return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot)); } - protected: - bool getOwnPropertySlotForWrite(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable); - private: ConstPropertyStorage propertyStorage() const { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); } PropertyStorage propertyStorage() { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); } @@ -328,30 +325,6 @@ ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Ide return false; } -ALWAYS_INLINE bool JSObject::getOwnPropertySlotForWrite(ExecState* exec, const Identifier& propertyName, PropertySlot& slot, bool& slotIsWriteable) -{ - unsigned attributes; - if (JSValue* location = getDirectLocation(propertyName, attributes)) { - if (m_structure->hasGetterSetterProperties() && location[0].isGetterSetter()) { - slotIsWriteable = false; - fillGetterPropertySlot(slot, location); - } else { - slotIsWriteable = !(attributes & ReadOnly); - slot.setValueSlot(this, location, offsetForLocation(location)); - } - return true; - } - - // non-standard Netscape extension - if (propertyName == exec->propertyNames().underscoreProto) { - slot.setValue(prototype()); - slotIsWriteable = false; - return true; - } - - return false; -} - // It may seem crazy to inline a function this large, especially a virtual function, // but it makes a big difference to property lookup that derived classes can inline their // base class call to this. diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/JSStaticScopeObject.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/JSStaticScopeObject.cpp index 0253fdd..85907c8 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/JSStaticScopeObject.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/JSStaticScopeObject.cpp @@ -76,9 +76,4 @@ inline bool JSStaticScopeObject::getOwnPropertySlot(ExecState*, const Identifier return symbolTableGet(propertyName, slot); } -inline bool JSStaticScopeObject::getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot& slot, bool& slotIsWriteable) -{ - return symbolTableGet(propertyName, slot, slotIsWriteable); -} - } diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/JSStaticScopeObject.h b/src/3rdparty/webkit/JavaScriptCore/runtime/JSStaticScopeObject.h index 7e7ce65..2caf540 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/JSStaticScopeObject.h +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/JSStaticScopeObject.h @@ -54,7 +54,6 @@ namespace JSC{ bool isDynamicScope() const; virtual JSObject* toThisObject(ExecState*) const; virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); - virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable); virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes); diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/LiteralParser.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/LiteralParser.cpp index 10f9a13..3f3fab9 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/LiteralParser.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/LiteralParser.cpp @@ -28,31 +28,12 @@ #include "JSArray.h" #include "JSString.h" +#include "Lexer.h" #include <wtf/ASCIICType.h> +#include <wtf/dtoa.h> namespace JSC { -class LiteralParser::StackGuard { -public: - StackGuard(LiteralParser* parser) - : m_parser(parser) - { - m_parser->m_depth++; - } - ~StackGuard() - { - m_parser->m_depth--; - } - bool isSafe() { return m_parser->m_depth < 10; } -private: - LiteralParser* m_parser; -}; - -static bool isSafeStringCharacter(UChar c) -{ - return (c >= ' ' && c <= 0xff && c != '\\') || c == '\t'; -} - LiteralParser::TokenType LiteralParser::Lexer::lex(LiteralParserToken& token) { while (m_ptr < m_end && isASCIISpace(*m_ptr)) @@ -100,8 +81,33 @@ LiteralParser::TokenType LiteralParser::Lexer::lex(LiteralParserToken& token) token.end = ++m_ptr; return TokColon; case '"': - return lexString(token); - + if (m_mode == StrictJSON) + return lexString<StrictJSON>(token); + return lexString<NonStrictJSON>(token); + case 't': + if (m_end - m_ptr >= 4 && m_ptr[1] == 'r' && m_ptr[2] == 'u' && m_ptr[3] == 'e') { + m_ptr += 4; + token.type = TokTrue; + token.end = m_ptr; + return TokTrue; + } + break; + case 'f': + if (m_end - m_ptr >= 5 && m_ptr[1] == 'a' && m_ptr[2] == 'l' && m_ptr[3] == 's' && m_ptr[4] == 'e') { + m_ptr += 5; + token.type = TokFalse; + token.end = m_ptr; + return TokFalse; + } + break; + case 'n': + if (m_end - m_ptr >= 4 && m_ptr[1] == 'u' && m_ptr[2] == 'l' && m_ptr[3] == 'l') { + m_ptr += 4; + token.type = TokNull; + token.end = m_ptr; + return TokNull; + } + break; case '-': case '0': case '1': @@ -118,16 +124,80 @@ LiteralParser::TokenType LiteralParser::Lexer::lex(LiteralParserToken& token) return TokError; } -LiteralParser::TokenType LiteralParser::Lexer::lexString(LiteralParserToken& token) +static inline bool isSafeStringCharacter(UChar c) +{ + return (c >= ' ' && c <= 0xff && c != '\\' && c != '"') || c == '\t'; +} + +template <LiteralParser::ParserMode mode> LiteralParser::TokenType LiteralParser::Lexer::lexString(LiteralParserToken& token) { ++m_ptr; - while (m_ptr < m_end && isSafeStringCharacter(*m_ptr) && *m_ptr != '"') - ++m_ptr; - if (m_ptr >= m_end || *m_ptr != '"') { - token.type = TokError; - token.end = ++m_ptr; + const UChar* runStart; + token.stringToken = UString(); + do { + runStart = m_ptr; + while (m_ptr < m_end && isSafeStringCharacter(*m_ptr)) + ++m_ptr; + if (runStart < m_ptr) + token.stringToken.append(runStart, m_ptr - runStart); + if ((mode == StrictJSON) && m_ptr < m_end && *m_ptr == '\\') { + ++m_ptr; + if (m_ptr >= m_end) + return TokError; + switch (*m_ptr) { + case '"': + token.stringToken.append('"'); + m_ptr++; + break; + case '\\': + token.stringToken.append('\\'); + m_ptr++; + break; + case '/': + token.stringToken.append('/'); + m_ptr++; + break; + case 'b': + token.stringToken.append('\b'); + m_ptr++; + break; + case 'f': + token.stringToken.append('\f'); + m_ptr++; + break; + case 'n': + token.stringToken.append('\n'); + m_ptr++; + break; + case 'r': + token.stringToken.append('\r'); + m_ptr++; + break; + case 't': + token.stringToken.append('\t'); + m_ptr++; + break; + + case 'u': + if ((m_end - m_ptr) < 5) // uNNNN == 5 characters + return TokError; + for (int i = 1; i < 5; i++) { + if (!isASCIIHexDigit(m_ptr[i])) + return TokError; + } + token.stringToken.append(JSC::Lexer::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4])); + m_ptr += 5; + break; + + default: + return TokError; + } + } + } while ((mode == StrictJSON) && m_ptr != runStart && (m_ptr < m_end) && *m_ptr != '"'); + + if (m_ptr >= m_end || *m_ptr != '"') return TokError; - } + token.type = TokString; token.end = ++m_ptr; return TokString; @@ -167,7 +237,7 @@ LiteralParser::TokenType LiteralParser::Lexer::lexNumber(LiteralParserToken& tok if (m_ptr < m_end && *m_ptr == '.') { ++m_ptr; // [0-9]+ - if (m_ptr >= m_end && !isASCIIDigit(*m_ptr)) + if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) return TokError; ++m_ptr; @@ -184,7 +254,7 @@ LiteralParser::TokenType LiteralParser::Lexer::lexNumber(LiteralParserToken& tok ++m_ptr; // [0-9]+ - if (m_ptr >= m_end && !isASCIIDigit(*m_ptr)) + if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) return TokError; ++m_ptr; @@ -194,113 +264,186 @@ LiteralParser::TokenType LiteralParser::Lexer::lexNumber(LiteralParserToken& tok token.type = TokNumber; token.end = m_ptr; + Vector<char, 64> buffer(token.end - token.start + 1); + int i; + for (i = 0; i < token.end - token.start; i++) { + ASSERT(static_cast<char>(token.start[i]) == token.start[i]); + buffer[i] = static_cast<char>(token.start[i]); + } + buffer[i] = 0; + char* end; + token.numberToken = WTF::strtod(buffer.data(), &end); + ASSERT(buffer.data() + (token.end - token.start) == end); return TokNumber; } -JSValue LiteralParser::parseStatement() +JSValue LiteralParser::parse(ParserState initialState) { - StackGuard guard(this); - if (!guard.isSafe()) - return abortParse(); + ParserState state = initialState; + MarkedArgumentBuffer objectStack; + JSValue lastValue; + Vector<ParserState, 16> stateStack; + Vector<Identifier, 16> identifierStack; + while (1) { + switch(state) { + startParseArray: + case StartParseArray: { + JSArray* array = constructEmptyArray(m_exec); + objectStack.append(array); + // fallthrough + } + doParseArrayStartExpression: + case DoParseArrayStartExpression: { + if (m_lexer.next() == TokRBracket) { + m_lexer.next(); + lastValue = objectStack.last(); + objectStack.removeLast(); + break; + } - switch (m_lexer.currentToken().type) { - case TokLBracket: - case TokNumber: - case TokString: - return parseExpression(); - case TokLParen: { - m_lexer.next(); - JSValue result = parseExpression(); - if (m_aborted || m_lexer.currentToken().type != TokRParen) - return abortParse(); - m_lexer.next(); - return result; - } - default: - return abortParse(); - } -} + stateStack.append(DoParseArrayEndExpression); + goto startParseExpression; + } + case DoParseArrayEndExpression: { + asArray(objectStack.last())->push(m_exec, lastValue); + + if (m_lexer.currentToken().type == TokComma) + goto doParseArrayStartExpression; -JSValue LiteralParser::parseExpression() -{ - StackGuard guard(this); - if (!guard.isSafe()) - return abortParse(); - switch (m_lexer.currentToken().type) { - case TokLBracket: - return parseArray(); - case TokLBrace: - return parseObject(); - case TokString: { - Lexer::LiteralParserToken stringToken = m_lexer.currentToken(); - m_lexer.next(); - return jsString(m_exec, UString(stringToken.start + 1, stringToken.end - stringToken.start - 2)); - } - case TokNumber: { - Lexer::LiteralParserToken numberToken = m_lexer.currentToken(); - m_lexer.next(); - return jsNumber(m_exec, UString(numberToken.start, numberToken.end - numberToken.start).toDouble()); - } - default: - return JSValue(); - } -} + if (m_lexer.currentToken().type != TokRBracket) + return JSValue(); + + m_lexer.next(); + lastValue = objectStack.last(); + objectStack.removeLast(); + break; + } + startParseObject: + case StartParseObject: { + JSObject* object = constructEmptyObject(m_exec); + objectStack.append(object); -JSValue LiteralParser::parseArray() -{ - StackGuard guard(this); - if (!guard.isSafe()) - return abortParse(); - JSArray* array = constructEmptyArray(m_exec); - while (true) { - m_lexer.next(); - JSValue value = parseExpression(); - if (m_aborted) - return JSValue(); - if (!value) - break; - array->push(m_exec, value); + TokenType type = m_lexer.next(); + if (type == TokString) { + Lexer::LiteralParserToken identifierToken = m_lexer.currentToken(); - if (m_lexer.currentToken().type != TokComma) - break; - } - if (m_lexer.currentToken().type != TokRBracket) - return abortParse(); + // Check for colon + if (m_lexer.next() != TokColon) + return JSValue(); + + m_lexer.next(); + identifierStack.append(Identifier(m_exec, identifierToken.stringToken)); + stateStack.append(DoParseObjectEndExpression); + goto startParseExpression; + } else if (type != TokRBrace) + return JSValue(); + m_lexer.next(); + lastValue = objectStack.last(); + objectStack.removeLast(); + break; + } + doParseObjectStartExpression: + case DoParseObjectStartExpression: { + TokenType type = m_lexer.next(); + if (type != TokString) + return JSValue(); + Lexer::LiteralParserToken identifierToken = m_lexer.currentToken(); - m_lexer.next(); - return array; -} + // Check for colon + if (m_lexer.next() != TokColon) + return JSValue(); -JSValue LiteralParser::parseObject() -{ - StackGuard guard(this); - if (!guard.isSafe()) - return abortParse(); - JSObject* object = constructEmptyObject(m_exec); - - while (m_lexer.next() == TokString) { - Lexer::LiteralParserToken identifierToken = m_lexer.currentToken(); - - // Check for colon - if (m_lexer.next() != TokColon) - return abortParse(); - m_lexer.next(); - - JSValue value = parseExpression(); - if (!value || m_aborted) - return abortParse(); - - Identifier ident(m_exec, identifierToken.start + 1, identifierToken.end - identifierToken.start - 2); - object->putDirect(ident, value); - - if (m_lexer.currentToken().type != TokComma) - break; + m_lexer.next(); + identifierStack.append(Identifier(m_exec, identifierToken.stringToken)); + stateStack.append(DoParseObjectEndExpression); + goto startParseExpression; + } + case DoParseObjectEndExpression: + { + asObject(objectStack.last())->putDirect(identifierStack.last(), lastValue); + identifierStack.removeLast(); + if (m_lexer.currentToken().type == TokComma) + goto doParseObjectStartExpression; + if (m_lexer.currentToken().type != TokRBrace) + return JSValue(); + m_lexer.next(); + lastValue = objectStack.last(); + objectStack.removeLast(); + break; + } + startParseExpression: + case StartParseExpression: { + switch (m_lexer.currentToken().type) { + case TokLBracket: + goto startParseArray; + case TokLBrace: + goto startParseObject; + case TokString: { + Lexer::LiteralParserToken stringToken = m_lexer.currentToken(); + m_lexer.next(); + lastValue = jsString(m_exec, stringToken.stringToken); + break; + } + case TokNumber: { + Lexer::LiteralParserToken numberToken = m_lexer.currentToken(); + m_lexer.next(); + lastValue = jsNumber(m_exec, numberToken.numberToken); + break; + } + case TokNull: + m_lexer.next(); + lastValue = jsNull(); + break; + + case TokTrue: + m_lexer.next(); + lastValue = jsBoolean(true); + break; + + case TokFalse: + m_lexer.next(); + lastValue = jsBoolean(false); + break; + + default: + // Error + return JSValue(); + } + break; + } + case StartParseStatement: { + switch (m_lexer.currentToken().type) { + case TokLBracket: + case TokNumber: + case TokString: + goto startParseExpression; + + case TokLParen: { + m_lexer.next(); + stateStack.append(StartParseStatementEndStatement); + goto startParseExpression; + } + default: + return JSValue(); + } + } + case StartParseStatementEndStatement: { + ASSERT(stateStack.isEmpty()); + if (m_lexer.currentToken().type != TokRParen) + return JSValue(); + if (m_lexer.next() == TokEnd) + return lastValue; + return JSValue(); + } + default: + ASSERT_NOT_REACHED(); + } + if (stateStack.isEmpty()) + return lastValue; + state = stateStack.last(); + stateStack.removeLast(); + continue; } - - if (m_lexer.currentToken().type != TokRBrace) - return abortParse(); - m_lexer.next(); - return object; } } diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/LiteralParser.h b/src/3rdparty/webkit/JavaScriptCore/runtime/LiteralParser.h index a72e3d0..bceee7c 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/LiteralParser.h +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/LiteralParser.h @@ -34,27 +34,31 @@ namespace JSC { class LiteralParser { public: - LiteralParser(ExecState* exec, const UString& s) + typedef enum { StrictJSON, NonStrictJSON } ParserMode; + LiteralParser(ExecState* exec, const UString& s, ParserMode mode) : m_exec(exec) - , m_lexer(s) - , m_depth(0) - , m_aborted(false) + , m_lexer(s, mode) + , m_mode(mode) { } JSValue tryLiteralParse() { m_lexer.next(); - JSValue result = parseStatement(); - if (m_aborted || m_lexer.currentToken().type != TokEnd) + JSValue result = parse(m_mode == StrictJSON ? StartParseExpression : StartParseStatement); + if (m_lexer.currentToken().type != TokEnd) return JSValue(); return result; } private: - + enum ParserState { StartParseObject, StartParseArray, StartParseExpression, + StartParseStatement, StartParseStatementEndStatement, + DoParseObjectStartExpression, DoParseObjectEndExpression, + DoParseArrayStartExpression, DoParseArrayEndExpression }; enum TokenType { TokLBracket, TokRBracket, TokLBrace, TokRBrace, TokString, TokIdentifier, TokNumber, TokColon, - TokLParen, TokRParen, TokComma, TokEnd, TokError }; + TokLParen, TokRParen, TokComma, TokTrue, TokFalse, + TokNull, TokEnd, TokError }; class Lexer { public: @@ -62,9 +66,12 @@ namespace JSC { TokenType type; const UChar* start; const UChar* end; + UString stringToken; + double numberToken; }; - Lexer(const UString& s) + Lexer(const UString& s, ParserMode mode) : m_string(s) + , m_mode(mode) , m_ptr(s.data()) , m_end(s.data() + s.size()) { @@ -82,30 +89,21 @@ namespace JSC { private: TokenType lex(LiteralParserToken&); - TokenType lexString(LiteralParserToken&); + template <ParserMode parserMode> TokenType lexString(LiteralParserToken&); TokenType lexNumber(LiteralParserToken&); LiteralParserToken m_currentToken; UString m_string; + ParserMode m_mode; const UChar* m_ptr; const UChar* m_end; }; class StackGuard; - JSValue parseStatement(); - JSValue parseExpression(); - JSValue parseArray(); - JSValue parseObject(); - - JSValue abortParse() - { - m_aborted = true; - return JSValue(); - } + JSValue parse(ParserState); ExecState* m_exec; LiteralParser::Lexer m_lexer; - int m_depth; - bool m_aborted; + ParserMode m_mode; }; } diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/PropertySlot.h b/src/3rdparty/webkit/JavaScriptCore/runtime/PropertySlot.h index 7af60ce..da0d152 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/PropertySlot.h +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/PropertySlot.h @@ -79,16 +79,6 @@ namespace JSC { return m_offset; } - void putValue(JSValue value) - { - if (m_getValue == JSC_VALUE_SLOT_MARKER) { - *m_data.valueSlot = value; - return; - } - ASSERT(m_getValue == JSC_REGISTER_SLOT_MARKER); - *m_data.registerSlot = JSValue(value); - } - void setValueSlot(JSValue* valueSlot) { ASSERT(valueSlot); diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/Structure.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/Structure.cpp index 3597a5c..5dfd919 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/Structure.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/Structure.cpp @@ -306,8 +306,11 @@ void Structure::getEnumerablePropertyNames(ExecState* exec, PropertyNameArray& p } if (shouldCache) { + StructureChain* protoChain = prototypeChain(exec); m_cachedPropertyNameArrayData = propertyNames.data(); - m_cachedPropertyNameArrayData->setCachedPrototypeChain(prototypeChain(exec)); + if (!protoChain->isCacheable()) + return; + m_cachedPropertyNameArrayData->setCachedPrototypeChain(protoChain); m_cachedPropertyNameArrayData->setCachedStructure(this); } } @@ -407,6 +410,7 @@ PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, con if (structure->transitionCount() > s_maxTransitionLength) { RefPtr<Structure> transition = toDictionaryTransition(structure); + ASSERT(structure != transition); offset = transition->put(propertyName, attributes, specificValue); if (transition->propertyStorageSize() > transition->propertyStorageCapacity()) transition->growPropertyStorageCapacity(); diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/StructureChain.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/StructureChain.cpp index 085876c..85049b1 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/StructureChain.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/StructureChain.cpp @@ -46,4 +46,15 @@ StructureChain::StructureChain(Structure* head) m_vector[i] = 0; } +bool StructureChain::isCacheable() const +{ + uint32_t i = 0; + + while (m_vector[i]) { + if (m_vector[i++]->isDictionary()) + return false; + } + return true; +} + } // namespace JSC diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/StructureChain.h b/src/3rdparty/webkit/JavaScriptCore/runtime/StructureChain.h index 795e649..c48749d 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/StructureChain.h +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/StructureChain.h @@ -39,6 +39,7 @@ namespace JSC { public: static PassRefPtr<StructureChain> create(Structure* head) { return adoptRef(new StructureChain(head)); } RefPtr<Structure>* head() { return m_vector.get(); } + bool isCacheable() const; private: StructureChain(Structure* head); diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/UString.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/UString.cpp index 0eb46da..118751e 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/UString.cpp +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/UString.cpp @@ -63,7 +63,7 @@ extern const double NaN; extern const double Inf; // This number must be at least 2 to avoid sharing empty, null as well as 1 character strings from SmallStrings. -static const int minLengthToShare = 30; +static const int minLengthToShare = 10; static inline size_t overflowIndicator() { return std::numeric_limits<size_t>::max(); } static inline size_t maxUChars() { return std::numeric_limits<size_t>::max() / sizeof(UChar); } @@ -243,6 +243,15 @@ PassRefPtr<UString::Rep> UString::Rep::create(UChar* string, int length, PassRef return rep; } +UString::SharedUChar* UString::Rep::sharedBuffer() +{ + UString::BaseString* base = baseString(); + if (len < minLengthToShare) + return 0; + + return base->sharedBuffer(); +} + void UString::Rep::destroy() { checkConsistency(); @@ -385,10 +394,6 @@ void UString::Rep::checkConsistency() const UString::SharedUChar* UString::BaseString::sharedBuffer() { - - if (len < minLengthToShare) - return 0; - if (!m_sharedBuffer) setSharedBuffer(SharedUChar::create(new OwnFastMallocPtr<UChar>(buf))); return m_sharedBuffer; diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/UString.h b/src/3rdparty/webkit/JavaScriptCore/runtime/UString.h index 6852d91..d01b75d 100644 --- a/src/3rdparty/webkit/JavaScriptCore/runtime/UString.h +++ b/src/3rdparty/webkit/JavaScriptCore/runtime/UString.h @@ -107,6 +107,7 @@ namespace JSC { // Uses SharedUChar to have joint ownership over the UChar*. static PassRefPtr<Rep> create(UChar*, int, PassRefPtr<SharedUChar>); + SharedUChar* sharedBuffer(); void destroy(); bool baseIsSelf() const { return m_identifierTableAndFlags.isFlagSet(BaseStringFlag); } @@ -192,7 +193,6 @@ namespace JSC { struct BaseString : public Rep { bool isShared() { return rc != 1 || isBufferReadOnly(); } void setSharedBuffer(PassRefPtr<SharedUChar>); - SharedUChar* sharedBuffer(); bool isBufferReadOnly() { @@ -224,6 +224,7 @@ namespace JSC { checkConsistency(); } + SharedUChar* sharedBuffer(); bool slowIsBufferReadOnly(); friend struct Rep; |