diff options
author | Qt Continuous Integration System <qt-info@nokia.com> | 2010-03-16 17:30:24 (GMT) |
---|---|---|
committer | Qt Continuous Integration System <qt-info@nokia.com> | 2010-03-16 17:30:24 (GMT) |
commit | 1a8eaa2087fde99366da6faa11ef8c14711a75ff (patch) | |
tree | 8c35e8e93d8b43f8ed4041f3fae7b9ec39aae4d0 /src/3rdparty/javascriptcore/JavaScriptCore/runtime | |
parent | b83172f8cfb4439f17c96886f0c6046a885370f6 (diff) | |
parent | bcc8ecc91c9884d14dd4eda5fc1a4ab4ba7aab62 (diff) | |
download | Qt-1a8eaa2087fde99366da6faa11ef8c14711a75ff.zip Qt-1a8eaa2087fde99366da6faa11ef8c14711a75ff.tar.gz Qt-1a8eaa2087fde99366da6faa11ef8c14711a75ff.tar.bz2 |
Merge branch '4.7' of scm.dev.nokia.troll.no:qt/oslo-staging-1 into 4.7-integration
* '4.7' of scm.dev.nokia.troll.no:qt/oslo-staging-1: (81 commits)
Define JS_NO_EXPORT to avoid JSC C API functions being exported
Don't use QScriptValueIterator to iterate over an array
QtScript: Fix regression when calling newQObject() from native constructor
Added note to OS X installation instructions.
Keypress events ignored in listview on Cocoa (64 Bit) with Japanese IME
Update only appropriate rectangles during update_sys().
Marked QTDS obsolete from Qt 4.7.
QNetworkReply: Fix canReadLine()
Abort waiting replies on session error.
different approach to fixing "the other" aliasing issue
fix aliasing issue in node_construct()
detach in fewer cases, remove redundant calculation
SSL: Fix memleak related to local certificate
Improve keyboard layout detection on X11
Compile on ARM with -Werror -Wold-style-cast
Use the vista-style native dialog for QFileDialog::getExistingDirectory
Apply the stdset attribute for resource properties
doc: Completed sentence about HideNameFilterDetails
Doc fix in QLocale
Doc for for QGestureRecognizer::create.
...
Diffstat (limited to 'src/3rdparty/javascriptcore/JavaScriptCore/runtime')
155 files changed, 4455 insertions, 3402 deletions
diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArgList.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArgList.h index 3227770..8e1fdbe 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArgList.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArgList.h @@ -104,7 +104,11 @@ namespace JSC { void append(JSValue v) { ASSERT(!m_isReadOnly); - + +#if ENABLE(JSC_ZOMBIES) + ASSERT(!v.isZombie()); +#endif + if (m_isUsingInlineBuffer && m_size < inlineCapacity) { m_vector.uncheckedAppend(v); ++m_size; @@ -187,6 +191,10 @@ namespace JSC { : m_args(args) , m_argCount(argCount) { +#if ENABLE(JSC_ZOMBIES) + for (size_t i = 0; i < argCount; i++) + ASSERT(!m_args[i].isZombie()); +#endif } ArgList(Register* args, int argCount) diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Arguments.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Arguments.cpp index d90ea15..bb30e3b 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Arguments.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Arguments.cpp @@ -204,6 +204,19 @@ bool Arguments::getOwnPropertyDescriptor(ExecState* exec, const Identifier& prop return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor); } +void Arguments::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +{ + if (mode == IncludeDontEnumProperties) { + for (unsigned i = 0; i < d->numArguments; ++i) { + if (!d->deletedArguments || !d->deletedArguments[i]) + propertyNames.add(Identifier(exec, UString::from(i))); + } + propertyNames.add(exec->propertyNames().callee); + propertyNames.add(exec->propertyNames().length); + } + JSObject::getOwnPropertyNames(exec, propertyNames, mode); +} + void Arguments::put(ExecState* exec, unsigned i, JSValue value, PutPropertySlot& slot) { if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) { @@ -244,7 +257,7 @@ void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue val JSObject::put(exec, propertyName, value, slot); } -bool Arguments::deleteProperty(ExecState* exec, unsigned i, bool checkDontDelete) +bool Arguments::deleteProperty(ExecState* exec, unsigned i) { if (i < d->numArguments) { if (!d->deletedArguments) { @@ -257,10 +270,10 @@ bool Arguments::deleteProperty(ExecState* exec, unsigned i, bool checkDontDelete } } - return JSObject::deleteProperty(exec, Identifier(exec, UString::from(i)), checkDontDelete); + return JSObject::deleteProperty(exec, Identifier(exec, UString::from(i))); } -bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName, bool checkDontDelete) +bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName) { bool isArrayIndex; unsigned i = propertyName.toArrayIndex(&isArrayIndex); @@ -285,17 +298,7 @@ bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName, return true; } - return JSObject::deleteProperty(exec, propertyName, checkDontDelete); -} - -bool Arguments::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const -{ - if ((propertyName == exec->propertyNames().length) - || (propertyName == exec->propertyNames().callee)) { - attributes = DontEnum; - return true; - } - return JSObject::getPropertyAttributes(exec, propertyName, attributes); + return JSObject::deleteProperty(exec, propertyName); } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Arguments.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Arguments.h index 2aa0921..d4a8c95 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Arguments.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Arguments.h @@ -85,19 +85,22 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags; + private: void getArgumentsData(CallFrame*, JSObject*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc); virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); + virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); virtual void put(ExecState*, unsigned propertyName, JSValue, PutPropertySlot&); - virtual bool deleteProperty(ExecState*, const Identifier& propertyName, bool checkDontDelete = true); - virtual bool deleteProperty(ExecState*, unsigned propertyName, bool checkDontDelete = true); - virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const; + virtual bool deleteProperty(ExecState*, const Identifier& propertyName); + virtual bool deleteProperty(ExecState*, unsigned propertyName); virtual const ClassInfo* classInfo() const { return &info; } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayConstructor.cpp index c60cb0e..fb44494 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayConstructor.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayConstructor.cpp @@ -37,7 +37,7 @@ ASSERT_CLASS_FITS_IN_CELL(ArrayConstructor); static JSValue JSC_HOST_CALL arrayConstructorIsArray(ExecState*, JSObject*, JSValue, const ArgList&); -ArrayConstructor::ArrayConstructor(ExecState* exec, PassRefPtr<Structure> structure, ArrayPrototype* arrayPrototype, Structure* prototypeFunctionStructure) +ArrayConstructor::ArrayConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, ArrayPrototype* arrayPrototype, Structure* prototypeFunctionStructure) : InternalFunction(&exec->globalData(), structure, Identifier(exec, arrayPrototype->classInfo()->className)) { // ECMA 15.4.3.1 Array.prototype @@ -50,7 +50,7 @@ ArrayConstructor::ArrayConstructor(ExecState* exec, PassRefPtr<Structure> struct putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().isArray, arrayConstructorIsArray), DontEnum); } -static JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args) +static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args) { // a single numeric argument denotes the array size (!) if (args.size() == 1 && args.at(0).isNumber()) { diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayConstructor.h index 2b79510..6d25400 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayConstructor.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayConstructor.h @@ -29,7 +29,7 @@ namespace JSC { class ArrayConstructor : public InternalFunction { public: - ArrayConstructor(ExecState*, PassRefPtr<Structure>, ArrayPrototype*, Structure*); + ArrayConstructor(ExecState*, NonNullPassRefPtr<Structure>, ArrayPrototype*, Structure*); virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayPrototype.cpp index c453b22..ce814b2 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -115,7 +115,7 @@ const ClassInfo ArrayPrototype::info = {"Array", &JSArray::info, 0, ExecState::a */ // ECMA 15.4.4 -ArrayPrototype::ArrayPrototype(PassRefPtr<Structure> structure) +ArrayPrototype::ArrayPrototype(NonNullPassRefPtr<Structure> structure) : JSArray(structure) { } @@ -204,8 +204,7 @@ JSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec, JSObject*, JSValue buffer.append(rep->data(), rep->size()); } ASSERT(buffer.size() == totalSize); - unsigned finalSize = buffer.size(); - return jsString(exec, UString(buffer.releaseBuffer(), finalSize, false)); + return jsString(exec, UString::adopt(buffer)); } JSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -745,8 +744,8 @@ JSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec, JSObject*, JSValue th cachedCall.setArgument(0, array->getIndex(k)); cachedCall.setArgument(1, jsNumber(exec, k)); cachedCall.setArgument(2, thisObj); - - if (!cachedCall.call().toBoolean(exec)) + JSValue result = cachedCall.call(); + if (!result.toBoolean(cachedCall.newCallFrame(exec))) return jsBoolean(false); } } @@ -846,8 +845,8 @@ JSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec, JSObject*, JSValue thi cachedCall.setArgument(0, array->getIndex(k)); cachedCall.setArgument(1, jsNumber(exec, k)); cachedCall.setArgument(2, thisObj); - - if (cachedCall.call().toBoolean(exec)) + JSValue result = cachedCall.call(); + if (result.toBoolean(cachedCall.newCallFrame(exec))) return jsBoolean(true); } } @@ -1034,7 +1033,7 @@ JSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec, JSObject*, JSValue JSValue e = getProperty(exec, thisObj, index); if (!e) continue; - if (JSValue::strictEqual(searchElement, e)) + if (JSValue::strictEqual(exec, searchElement, e)) return jsNumber(exec, index); } @@ -1065,7 +1064,7 @@ JSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec, JSObject*, JSVa JSValue e = getProperty(exec, thisObj, index); if (!e) continue; - if (JSValue::strictEqual(searchElement, e)) + if (JSValue::strictEqual(exec, searchElement, e)) return jsNumber(exec, index); } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayPrototype.h index 6f7ed12..e52914c 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayPrototype.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ArrayPrototype.h @@ -28,7 +28,7 @@ namespace JSC { class ArrayPrototype : public JSArray { public: - explicit ArrayPrototype(PassRefPtr<Structure>); + explicit ArrayPrototype(NonNullPassRefPtr<Structure>); bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BatchedTransitionOptimizer.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BatchedTransitionOptimizer.h index 929a5e7..74089a5 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BatchedTransitionOptimizer.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BatchedTransitionOptimizer.h @@ -43,7 +43,7 @@ namespace JSC { ~BatchedTransitionOptimizer() { - m_object->setStructure(Structure::fromDictionaryTransition(m_object->structure())); + m_object->flattenDictionaryObject(); } private: diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanConstructor.cpp index 9fcba37..b0d8df3 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanConstructor.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanConstructor.cpp @@ -28,7 +28,7 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(BooleanConstructor); -BooleanConstructor::BooleanConstructor(ExecState* exec, PassRefPtr<Structure> structure, BooleanPrototype* booleanPrototype) +BooleanConstructor::BooleanConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, BooleanPrototype* booleanPrototype) : InternalFunction(&exec->globalData(), structure, Identifier(exec, booleanPrototype->classInfo()->className)) { putDirectWithoutTransition(exec->propertyNames().prototype, booleanPrototype, DontEnum | DontDelete | ReadOnly); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanConstructor.h index d9f51ab..1d8a26a 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanConstructor.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanConstructor.h @@ -29,7 +29,7 @@ namespace JSC { class BooleanConstructor : public InternalFunction { public: - BooleanConstructor(ExecState*, PassRefPtr<Structure>, BooleanPrototype*); + BooleanConstructor(ExecState*, NonNullPassRefPtr<Structure>, BooleanPrototype*); private: virtual ConstructType getConstructData(ConstructData&); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanObject.cpp index 01f695a..c9b3846 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanObject.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanObject.cpp @@ -27,7 +27,7 @@ ASSERT_CLASS_FITS_IN_CELL(BooleanObject); const ClassInfo BooleanObject::info = { "Boolean", 0, 0, 0 }; -BooleanObject::BooleanObject(PassRefPtr<Structure> structure) +BooleanObject::BooleanObject(NonNullPassRefPtr<Structure> structure) : JSWrapperObject(structure) { } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanObject.h index 5f3e5f0..69c2e51 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanObject.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanObject.h @@ -27,14 +27,14 @@ namespace JSC { class BooleanObject : public JSWrapperObject { public: - explicit BooleanObject(PassRefPtr<Structure>); + explicit BooleanObject(NonNullPassRefPtr<Structure>); virtual const ClassInfo* classInfo() const { return &info; } static const ClassInfo info; static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot | HasDefaultMark | HasDefaultGetPropertyNames)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } }; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanPrototype.cpp index cf4fbd7..8d338f9 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanPrototype.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanPrototype.cpp @@ -37,7 +37,7 @@ static JSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState*, JSObject*, JSVa // ECMA 15.6.4 -BooleanPrototype::BooleanPrototype(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) +BooleanPrototype::BooleanPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) : BooleanObject(structure) { setInternalValue(jsBoolean(false)); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanPrototype.h index 16f80b5..cc69b3f 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanPrototype.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/BooleanPrototype.h @@ -27,7 +27,7 @@ namespace JSC { class BooleanPrototype : public BooleanObject { public: - BooleanPrototype(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure); + BooleanPrototype(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure); }; } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CallData.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CallData.h index ef4988b..32e1e52 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CallData.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CallData.h @@ -60,12 +60,12 @@ namespace JSC { } inline operator NativeFunction() const {return ptr;} inline operator bool() const {return ptr;} - + JSValue operator()(ExecState* exec, JSObject* jsobj, JSValue thisValue, const ArgList& argList) const; }; #endif -#if defined(QT_BUILD_SCRIPT_LIB) && PLATFORM(SOLARIS) +#if defined(QT_BUILD_SCRIPT_LIB) && OS(SOLARIS) struct #else union diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.cpp index abe15c8..29df7a5 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.cpp @@ -32,6 +32,7 @@ #include "JSONObject.h" #include "JSString.h" #include "JSValue.h" +#include "JSZombie.h" #include "MarkStack.h" #include "Nodes.h" #include "Tracing.h" @@ -44,7 +45,7 @@ #include <wtf/UnusedParam.h> #include <wtf/VMTags.h> -#if PLATFORM(DARWIN) +#if OS(DARWIN) #include <mach/mach_init.h> #include <mach/mach_port.h> @@ -52,29 +53,29 @@ #include <mach/thread_act.h> #include <mach/vm_map.h> -#elif PLATFORM(SYMBIAN) +#elif OS(SYMBIAN) #include <e32std.h> #include <e32cmn.h> #include <unistd.h> -#elif PLATFORM(WIN_OS) +#elif OS(WINDOWS) #include <windows.h> #include <malloc.h> -#elif PLATFORM(HAIKU) +#elif OS(HAIKU) #include <OS.h> -#elif PLATFORM(UNIX) +#elif OS(UNIX) #include <stdlib.h> -#if !PLATFORM(HAIKU) +#if !OS(HAIKU) #include <sys/mman.h> #endif #include <unistd.h> -#if PLATFORM(SOLARIS) +#if OS(SOLARIS) #include <thread.h> #else #include <pthread.h> @@ -84,7 +85,7 @@ #include <pthread_np.h> #endif -#if PLATFORM(QNX) +#if OS(QNX) #include <fcntl.h> #include <sys/procfs.h> #include <stdio.h> @@ -103,26 +104,22 @@ namespace JSC { const size_t GROWTH_FACTOR = 2; const size_t LOW_WATER_FACTOR = 4; -const size_t ALLOCATIONS_PER_COLLECTION = 4000; +const size_t ALLOCATIONS_PER_COLLECTION = 3600; // This value has to be a macro to be used in max() without introducing // a PIC branch in Mach-O binaries, see <rdar://problem/5971391>. #define MIN_ARRAY_SIZE (static_cast<size_t>(14)) -#if PLATFORM(SYMBIAN) +#if OS(SYMBIAN) const size_t MAX_NUM_BLOCKS = 256; // Max size of collector heap set to 16 MB static RHeap* userChunk = 0; #endif #if ENABLE(JSC_MULTIPLE_THREADS) -#if PLATFORM(DARWIN) +#if OS(DARWIN) typedef mach_port_t PlatformThread; -#elif PLATFORM(WIN_OS) -struct PlatformThread { - PlatformThread(DWORD _id, HANDLE _handle) : id(_id), handle(_handle) {} - DWORD id; - HANDLE handle; -}; +#elif OS(WINDOWS) +typedef HANDLE PlatformThread; #endif class Heap::Thread { @@ -151,8 +148,8 @@ Heap::Heap(JSGlobalData* globalData) , m_globalData(globalData) { ASSERT(globalData); - -#if PLATFORM(SYMBIAN) + +#if OS(SYMBIAN) // Symbian OpenC supports mmap but currently not the MAP_ANON flag. // Using fastMalloc() does not properly align blocks on 64k boundaries // and previous implementation was flawed/incomplete. @@ -170,10 +167,10 @@ Heap::Heap(JSGlobalData* globalData) if (!userChunk) CRASH(); } -#endif // PLATFORM(SYMBIAN) +#endif // OS(SYMBIAN) - memset(&primaryHeap, 0, sizeof(CollectorHeap)); - memset(&numberHeap, 0, sizeof(CollectorHeap)); + memset(&m_heap, 0, sizeof(CollectorHeap)); + allocateBlock(); } Heap::~Heap() @@ -189,6 +186,9 @@ void Heap::destroy() if (!m_globalData) return; + ASSERT(!m_globalData->dynamicGlobalObject); + ASSERT(!isBusy()); + // The global object is not GC protected at this point, so sweeping may delete it // (and thus the global data) before other objects that may use the global data. RefPtr<JSGlobalData> protect(m_globalData); @@ -196,13 +196,7 @@ void Heap::destroy() delete m_markListSet; m_markListSet = 0; - sweep<PrimaryHeap>(); - // No need to sweep number heap, because the JSNumber destructor doesn't do anything. - - ASSERT(!primaryHeap.numLiveObjects); - - freeBlocks(&primaryHeap); - freeBlocks(&numberHeap); + freeBlocks(); #if ENABLE(JSC_MULTIPLE_THREADS) if (m_currentThreadRegistrar) { @@ -221,27 +215,23 @@ void Heap::destroy() m_globalData = 0; } -template <HeapType heapType> NEVER_INLINE CollectorBlock* Heap::allocateBlock() { // Disable the use of vm_map for the Qt build on Darwin, because when compiled on 10.4 // it crashes on 10.5 -#if PLATFORM(DARWIN) && !PLATFORM(QT) +#if OS(DARWIN) && !PLATFORM(QT) vm_address_t address = 0; - // FIXME: tag the region as a JavaScriptCore heap when we get a registered VM tag: <rdar://problem/6054788>. vm_map(current_task(), &address, BLOCK_SIZE, BLOCK_OFFSET_MASK, VM_FLAGS_ANYWHERE | VM_TAG_FOR_COLLECTOR_MEMORY, MEMORY_OBJECT_NULL, 0, FALSE, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_DEFAULT); -#elif PLATFORM(SYMBIAN) +#elif OS(SYMBIAN) // Allocate a 64 kb aligned CollectorBlock unsigned char* mask = reinterpret_cast<unsigned char*>(userChunk->Alloc(BLOCK_SIZE)); if (!mask) CRASH(); uintptr_t address = reinterpret_cast<uintptr_t>(mask); - - memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE); -#elif PLATFORM(WINCE) +#elif OS(WINCE) void* address = VirtualAlloc(NULL, BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); -#elif PLATFORM(WIN_OS) -#if COMPILER(MINGW) && !PLATFORM(X86_64) +#elif OS(WINDOWS) +#if COMPILER(MINGW) && !CPU(X86_64) void* address = __mingw_aligned_malloc(BLOCK_SIZE, BLOCK_SIZE); #else void* address = _aligned_malloc(BLOCK_SIZE, BLOCK_SIZE); @@ -250,7 +240,6 @@ NEVER_INLINE CollectorBlock* Heap::allocateBlock() #elif HAVE(POSIX_MEMALIGN) void* address; posix_memalign(&address, BLOCK_SIZE, BLOCK_SIZE); - memset(address, 0, BLOCK_SIZE); #else #if ENABLE(JSC_MULTIPLE_THREADS) @@ -276,58 +265,66 @@ NEVER_INLINE CollectorBlock* Heap::allocateBlock() munmap(reinterpret_cast<char*>(address + adjust + BLOCK_SIZE), extra - adjust); address += adjust; - memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE); #endif + // Initialize block. + CollectorBlock* block = reinterpret_cast<CollectorBlock*>(address); - block->freeList = block->cells; block->heap = this; - block->type = heapType; + clearMarkBits(block); - CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap; - size_t numBlocks = heap.numBlocks; - if (heap.usedBlocks == numBlocks) { + Structure* dummyMarkableCellStructure = m_globalData->dummyMarkableCellStructure.get(); + for (size_t i = 0; i < HeapConstants::cellsPerBlock; ++i) + new (block->cells + i) JSCell(dummyMarkableCellStructure); + + // Add block to blocks vector. + + size_t numBlocks = m_heap.numBlocks; + if (m_heap.usedBlocks == numBlocks) { static const size_t maxNumBlocks = ULONG_MAX / sizeof(CollectorBlock*) / GROWTH_FACTOR; if (numBlocks > maxNumBlocks) CRASH(); numBlocks = max(MIN_ARRAY_SIZE, numBlocks * GROWTH_FACTOR); - heap.numBlocks = numBlocks; - heap.blocks = static_cast<CollectorBlock**>(fastRealloc(heap.blocks, numBlocks * sizeof(CollectorBlock*))); + m_heap.numBlocks = numBlocks; + m_heap.blocks = static_cast<CollectorBlock**>(fastRealloc(m_heap.blocks, numBlocks * sizeof(CollectorBlock*))); } - heap.blocks[heap.usedBlocks++] = block; + m_heap.blocks[m_heap.usedBlocks++] = block; return block; } -template <HeapType heapType> NEVER_INLINE void Heap::freeBlock(size_t block) { - CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap; + m_heap.didShrink = true; - freeBlock(heap.blocks[block]); + ObjectIterator it(m_heap, block); + ObjectIterator end(m_heap, block + 1); + for ( ; it != end; ++it) + (*it)->~JSCell(); + freeBlockPtr(m_heap.blocks[block]); // swap with the last block so we compact as we go - heap.blocks[block] = heap.blocks[heap.usedBlocks - 1]; - heap.usedBlocks--; + m_heap.blocks[block] = m_heap.blocks[m_heap.usedBlocks - 1]; + m_heap.usedBlocks--; - if (heap.numBlocks > MIN_ARRAY_SIZE && heap.usedBlocks < heap.numBlocks / LOW_WATER_FACTOR) { - heap.numBlocks = heap.numBlocks / GROWTH_FACTOR; - heap.blocks = static_cast<CollectorBlock**>(fastRealloc(heap.blocks, heap.numBlocks * sizeof(CollectorBlock*))); + if (m_heap.numBlocks > MIN_ARRAY_SIZE && m_heap.usedBlocks < m_heap.numBlocks / LOW_WATER_FACTOR) { + m_heap.numBlocks = m_heap.numBlocks / GROWTH_FACTOR; + m_heap.blocks = static_cast<CollectorBlock**>(fastRealloc(m_heap.blocks, m_heap.numBlocks * sizeof(CollectorBlock*))); } } -NEVER_INLINE void Heap::freeBlock(CollectorBlock* block) +NEVER_INLINE void Heap::freeBlockPtr(CollectorBlock* block) { // Disable the use of vm_deallocate for the Qt build on Darwin, because when compiled on 10.4 // it crashes on 10.5 -#if PLATFORM(DARWIN) && !PLATFORM(QT) +#if OS(DARWIN) && !PLATFORM(QT) vm_deallocate(current_task(), reinterpret_cast<vm_address_t>(block), BLOCK_SIZE); -#elif PLATFORM(SYMBIAN) +#elif OS(SYMBIAN) userChunk->Free(reinterpret_cast<TAny*>(block)); -#elif PLATFORM(WINCE) +#elif OS(WINCE) VirtualFree(block, 0, MEM_RELEASE); -#elif PLATFORM(WIN_OS) -#if COMPILER(MINGW) && !PLATFORM(X86_64) +#elif OS(WINDOWS) +#if COMPILER(MINGW) && !CPU(X86_64) __mingw_aligned_free(block); #else _aligned_free(block); @@ -339,13 +336,34 @@ NEVER_INLINE void Heap::freeBlock(CollectorBlock* block) #endif } -void Heap::freeBlocks(CollectorHeap* heap) +void Heap::freeBlocks() { - for (size_t i = 0; i < heap->usedBlocks; ++i) - if (heap->blocks[i]) - freeBlock(heap->blocks[i]); - fastFree(heap->blocks); - memset(heap, 0, sizeof(CollectorHeap)); + ProtectCountSet protectedValuesCopy = m_protectedValues; + + clearMarkBits(); + ProtectCountSet::iterator protectedValuesEnd = protectedValuesCopy.end(); + for (ProtectCountSet::iterator it = protectedValuesCopy.begin(); it != protectedValuesEnd; ++it) + markCell(it->first); + + m_heap.nextCell = 0; + m_heap.nextBlock = 0; + DeadObjectIterator it(m_heap, m_heap.nextBlock, m_heap.nextCell); + DeadObjectIterator end(m_heap, m_heap.usedBlocks); + for ( ; it != end; ++it) + (*it)->~JSCell(); + + ASSERT(!protectedObjectCount()); + + protectedValuesEnd = protectedValuesCopy.end(); + for (ProtectCountSet::iterator it = protectedValuesCopy.begin(); it != protectedValuesEnd; ++it) + it->first->~JSCell(); + + for (size_t block = 0; block < m_heap.usedBlocks; ++block) + freeBlockPtr(m_heap.blocks[block]); + + fastFree(m_heap.blocks); + + memset(&m_heap, 0, sizeof(CollectorHeap)); } void Heap::recordExtraCost(size_t cost) @@ -360,123 +378,109 @@ void Heap::recordExtraCost(size_t cost) // are either very short lived temporaries, or have extremely long lifetimes. So // if a large value survives one garbage collection, there is not much point to // collecting more frequently as long as it stays alive. - // NOTE: we target the primaryHeap unconditionally as JSNumber doesn't modify cost - primaryHeap.extraCost += cost; + if (m_heap.extraCost > maxExtraCost && m_heap.extraCost > m_heap.usedBlocks * BLOCK_SIZE / 2) { + // If the last iteration through the heap deallocated blocks, we need + // to clean up remaining garbage before marking. Otherwise, the conservative + // marking mechanism might follow a pointer to unmapped memory. + if (m_heap.didShrink) + sweep(); + reset(); + } + m_heap.extraCost += cost; } -template <HeapType heapType> ALWAYS_INLINE void* Heap::heapAllocate(size_t s) +void* Heap::allocate(size_t s) { - typedef typename HeapConstants<heapType>::Block Block; - typedef typename HeapConstants<heapType>::Cell Cell; - - CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap; + typedef HeapConstants::Block Block; + typedef HeapConstants::Cell Cell; + ASSERT(JSLock::lockCount() > 0); ASSERT(JSLock::currentThreadIsHoldingLock()); - ASSERT_UNUSED(s, s <= HeapConstants<heapType>::cellSize); + ASSERT_UNUSED(s, s <= HeapConstants::cellSize); - ASSERT(heap.operationInProgress == NoOperation); - ASSERT(heapType == PrimaryHeap || heap.extraCost == 0); - // FIXME: If another global variable access here doesn't hurt performance - // too much, we could CRASH() in NDEBUG builds, which could help ensure we - // don't spend any time debugging cases where we allocate inside an object's - // deallocation code. + ASSERT(m_heap.operationInProgress == NoOperation); #if COLLECT_ON_EVERY_ALLOCATION - collect(); + collectAllGarbage(); + ASSERT(m_heap.operationInProgress == NoOperation); #endif - size_t numLiveObjects = heap.numLiveObjects; - size_t usedBlocks = heap.usedBlocks; - size_t i = heap.firstBlockWithPossibleSpace; - - // if we have a huge amount of extra cost, we'll try to collect even if we still have - // free cells left. - if (heapType == PrimaryHeap && heap.extraCost > ALLOCATIONS_PER_COLLECTION) { - size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect; - size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect; - const size_t newCost = numNewObjects + heap.extraCost; - if (newCost >= ALLOCATIONS_PER_COLLECTION && newCost >= numLiveObjectsAtLastCollect) - goto collect; - } +allocate: - ASSERT(heap.operationInProgress == NoOperation); -#ifndef NDEBUG - // FIXME: Consider doing this in NDEBUG builds too (see comment above). - heap.operationInProgress = Allocation; -#endif + // Fast case: find the next garbage cell and recycle it. -scan: - Block* targetBlock; - size_t targetBlockUsedCells; - if (i != usedBlocks) { - targetBlock = reinterpret_cast<Block*>(heap.blocks[i]); - targetBlockUsedCells = targetBlock->usedCells; - ASSERT(targetBlockUsedCells <= HeapConstants<heapType>::cellsPerBlock); - while (targetBlockUsedCells == HeapConstants<heapType>::cellsPerBlock) { - if (++i == usedBlocks) - goto collect; - targetBlock = reinterpret_cast<Block*>(heap.blocks[i]); - targetBlockUsedCells = targetBlock->usedCells; - ASSERT(targetBlockUsedCells <= HeapConstants<heapType>::cellsPerBlock); - } - heap.firstBlockWithPossibleSpace = i; - } else { + do { + ASSERT(m_heap.nextBlock < m_heap.usedBlocks); + Block* block = reinterpret_cast<Block*>(m_heap.blocks[m_heap.nextBlock]); + do { + ASSERT(m_heap.nextCell < HeapConstants::cellsPerBlock); + if (!block->marked.get(m_heap.nextCell)) { // Always false for the last cell in the block + Cell* cell = block->cells + m_heap.nextCell; -collect: - size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect; - size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect; - const size_t newCost = numNewObjects + heap.extraCost; + m_heap.operationInProgress = Allocation; + JSCell* imp = reinterpret_cast<JSCell*>(cell); + imp->~JSCell(); + m_heap.operationInProgress = NoOperation; - if (newCost >= ALLOCATIONS_PER_COLLECTION && newCost >= numLiveObjectsAtLastCollect) { -#ifndef NDEBUG - heap.operationInProgress = NoOperation; -#endif - bool foundGarbage = collect(); - numLiveObjects = heap.numLiveObjects; - usedBlocks = heap.usedBlocks; - i = heap.firstBlockWithPossibleSpace; -#ifndef NDEBUG - heap.operationInProgress = Allocation; -#endif - if (foundGarbage) - goto scan; - } + ++m_heap.nextCell; + return cell; + } + } while (++m_heap.nextCell != HeapConstants::cellsPerBlock); + m_heap.nextCell = 0; + } while (++m_heap.nextBlock != m_heap.usedBlocks); - // didn't find a block, and GC didn't reclaim anything, need to allocate a new block - targetBlock = reinterpret_cast<Block*>(allocateBlock<heapType>()); - heap.firstBlockWithPossibleSpace = heap.usedBlocks - 1; - targetBlockUsedCells = 0; - } + // Slow case: reached the end of the heap. Mark live objects and start over. - // find a free spot in the block and detach it from the free list - Cell* newCell = targetBlock->freeList; + reset(); + goto allocate; +} - // "next" field is a cell offset -- 0 means next cell, so a zeroed block is already initialized - targetBlock->freeList = (newCell + 1) + newCell->u.freeCell.next; +void Heap::resizeBlocks() +{ + m_heap.didShrink = false; - targetBlock->usedCells = static_cast<uint32_t>(targetBlockUsedCells + 1); - heap.numLiveObjects = numLiveObjects + 1; + size_t usedCellCount = markedCells(); + size_t minCellCount = usedCellCount + max(ALLOCATIONS_PER_COLLECTION, usedCellCount); + size_t minBlockCount = (minCellCount + HeapConstants::cellsPerBlock - 1) / HeapConstants::cellsPerBlock; -#ifndef NDEBUG - // FIXME: Consider doing this in NDEBUG builds too (see comment above). - heap.operationInProgress = NoOperation; -#endif + size_t maxCellCount = 1.25f * minCellCount; + size_t maxBlockCount = (maxCellCount + HeapConstants::cellsPerBlock - 1) / HeapConstants::cellsPerBlock; - return newCell; + if (m_heap.usedBlocks < minBlockCount) + growBlocks(minBlockCount); + else if (m_heap.usedBlocks > maxBlockCount) + shrinkBlocks(maxBlockCount); } -void* Heap::allocate(size_t s) +void Heap::growBlocks(size_t neededBlocks) { - return heapAllocate<PrimaryHeap>(s); + ASSERT(m_heap.usedBlocks < neededBlocks); + while (m_heap.usedBlocks < neededBlocks) + allocateBlock(); } -void* Heap::allocateNumber(size_t s) +void Heap::shrinkBlocks(size_t neededBlocks) { - return heapAllocate<NumberHeap>(s); + ASSERT(m_heap.usedBlocks > neededBlocks); + + // Clear the always-on last bit, so isEmpty() isn't fooled by it. + for (size_t i = 0; i < m_heap.usedBlocks; ++i) + m_heap.blocks[i]->marked.clear(HeapConstants::cellsPerBlock - 1); + + for (size_t i = 0; i != m_heap.usedBlocks && m_heap.usedBlocks != neededBlocks; ) { + if (m_heap.blocks[i]->marked.isEmpty()) { + freeBlock(i); + } else + ++i; + } + + // Reset the always-on last bit. + for (size_t i = 0; i < m_heap.usedBlocks; ++i) + m_heap.blocks[i]->marked.set(HeapConstants::cellsPerBlock - 1); } -#if PLATFORM(WINCE) +#if OS(WINCE) void* g_stackBase = 0; inline bool isPageWritable(void* page) @@ -532,7 +536,8 @@ static void* getStackBase(void* previousFrame) } } #endif -#if PLATFORM(HPUX) + +#if OS(HPUX) struct hpux_get_stack_base_data { pthread_t thread; @@ -576,7 +581,7 @@ static void *hpux_get_stack_base() } #endif -#if PLATFORM(QNX) +#if OS(QNX) static inline void *currentThreadStackBaseQNX() { static void* stackBase = 0; @@ -605,10 +610,10 @@ static inline void *currentThreadStackBaseQNX() static inline void* currentThreadStackBase() { -#if PLATFORM(DARWIN) +#if OS(DARWIN) pthread_t thread = pthread_self(); return pthread_get_stackaddr_np(thread); -#elif PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(MSVC) +#elif OS(WINDOWS) && CPU(X86) && COMPILER(MSVC) // offset 0x18 from the FS segment register gives a pointer to // the thread information block for the current thread NT_TIB* pTib; @@ -617,10 +622,11 @@ static inline void* currentThreadStackBase() MOV pTib, EAX } return static_cast<void*>(pTib->StackBase); -#elif PLATFORM(WIN_OS) && PLATFORM(X86_64) && (COMPILER(MSVC) ||COMPILER(GCC)) +#elif OS(WINDOWS) && CPU(X86_64) && (COMPILER(MSVC) || COMPILER(GCC)) + // FIXME: why only for MSVC? PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb()); return reinterpret_cast<void*>(pTib->StackBase); -#elif PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(GCC) +#elif OS(WINDOWS) && CPU(X86) && COMPILER(GCC) // offset 0x18 from the FS segment register gives a pointer to // the thread information block for the current thread NT_TIB* pTib; @@ -628,15 +634,15 @@ static inline void* currentThreadStackBase() : "=r" (pTib) ); return static_cast<void*>(pTib->StackBase); -#elif PLATFORM(QNX) - return currentThreadStackBaseQNX(); -#elif PLATFORM(HPUX) +#elif OS(HPUX) return hpux_get_stack_base(); -#elif PLATFORM(SOLARIS) +#elif OS(QNX) + return currentThreadStackBaseQNX(); +#elif OS(SOLARIS) stack_t s; thr_stksegment(&s); return s.ss_sp; -#elif PLATFORM(AIX) +#elif OS(AIX) pthread_t thread = pthread_self(); struct __pthrdsinfo threadinfo; char regbuf[256]; @@ -648,12 +654,12 @@ static inline void* currentThreadStackBase() return threadinfo.__pi_stackaddr; return 0; -#elif PLATFORM(OPENBSD) +#elif OS(OPENBSD) pthread_t thread = pthread_self(); stack_t stack; pthread_stackseg_np(thread, &stack); return stack.ss_sp; -#elif PLATFORM(SYMBIAN) +#elif OS(SYMBIAN) static void* stackBase = 0; if (stackBase == 0) { TThreadStackInfo info; @@ -662,11 +668,11 @@ static inline void* currentThreadStackBase() stackBase = (void*)info.iBase; } return (void*)stackBase; -#elif PLATFORM(HAIKU) +#elif OS(HAIKU) thread_info threadInfo; get_thread_info(find_thread(NULL), &threadInfo); return threadInfo.stack_end; -#elif PLATFORM(UNIX) +#elif OS(UNIX) static void* stackBase = 0; static size_t stackSize = 0; static pthread_t stackThread; @@ -674,7 +680,7 @@ static inline void* currentThreadStackBase() if (stackBase == 0 || thread != stackThread) { pthread_attr_t sattr; pthread_attr_init(&sattr); -#if HAVE(PTHREAD_NP_H) || PLATFORM(NETBSD) +#if HAVE(PTHREAD_NP_H) || OS(NETBSD) // e.g. on FreeBSD 5.4, neundorf@kde.org pthread_attr_get_np(thread, &sattr); #else @@ -688,7 +694,7 @@ static inline void* currentThreadStackBase() stackThread = thread; } return static_cast<char*>(stackBase) + stackSize; -#elif PLATFORM(WINCE) +#elif OS(WINCE) if (g_stackBase) return g_stackBase; else { @@ -704,11 +710,10 @@ static inline void* currentThreadStackBase() static inline PlatformThread getCurrentPlatformThread() { -#if PLATFORM(DARWIN) +#if OS(DARWIN) return pthread_mach_thread_np(pthread_self()); -#elif PLATFORM(WIN_OS) - HANDLE threadHandle = pthread_getw32threadhandle_np(pthread_self()); - return PlatformThread(GetCurrentThreadId(), threadHandle); +#elif OS(WINDOWS) + return pthread_getw32threadhandle_np(pthread_self()); #endif } @@ -777,10 +782,37 @@ void Heap::registerThread() #endif -#define IS_POINTER_ALIGNED(p) (((intptr_t)(p) & (sizeof(char*) - 1)) == 0) +inline bool isPointerAligned(void* p) +{ + return (((intptr_t)(p) & (sizeof(char*) - 1)) == 0); +} -// cell size needs to be a power of two for this to be valid -#define IS_HALF_CELL_ALIGNED(p) (((intptr_t)(p) & (CELL_MASK >> 1)) == 0) +// Cell size needs to be a power of two for isPossibleCell to be valid. +COMPILE_ASSERT(sizeof(CollectorCell) % 2 == 0, Collector_cell_size_is_power_of_two); + +#if USE(JSVALUE32) +static bool isHalfCellAligned(void *p) +{ + return (((intptr_t)(p) & (CELL_MASK >> 1)) == 0); +} + +static inline bool isPossibleCell(void* p) +{ + return isHalfCellAligned(p) && p; +} + +#else + +static inline bool isCellAligned(void *p) +{ + return (((intptr_t)(p) & CELL_MASK) == 0); +} + +static inline bool isPossibleCell(void* p) +{ + return isCellAligned(p) && p; +} +#endif // USE(JSVALUE32) void Heap::markConservatively(MarkStack& markStack, void* start, void* end) { @@ -791,46 +823,33 @@ void Heap::markConservatively(MarkStack& markStack, void* start, void* end) } ASSERT((static_cast<char*>(end) - static_cast<char*>(start)) < 0x1000000); - ASSERT(IS_POINTER_ALIGNED(start)); - ASSERT(IS_POINTER_ALIGNED(end)); + ASSERT(isPointerAligned(start)); + ASSERT(isPointerAligned(end)); char** p = static_cast<char**>(start); char** e = static_cast<char**>(end); - size_t usedPrimaryBlocks = primaryHeap.usedBlocks; - size_t usedNumberBlocks = numberHeap.usedBlocks; - CollectorBlock** primaryBlocks = primaryHeap.blocks; - CollectorBlock** numberBlocks = numberHeap.blocks; - - const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1); - + CollectorBlock** blocks = m_heap.blocks; while (p != e) { char* x = *p++; - if (IS_HALF_CELL_ALIGNED(x) && x) { + if (isPossibleCell(x)) { + size_t usedBlocks; uintptr_t xAsBits = reinterpret_cast<uintptr_t>(x); xAsBits &= CELL_ALIGN_MASK; + uintptr_t offset = xAsBits & BLOCK_OFFSET_MASK; + const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1); + if (offset > lastCellOffset) + continue; + CollectorBlock* blockAddr = reinterpret_cast<CollectorBlock*>(xAsBits - offset); - // Mark the the number heap, we can mark these Cells directly to avoid the virtual call cost - for (size_t block = 0; block < usedNumberBlocks; block++) { - if ((numberBlocks[block] == blockAddr) & (offset <= lastCellOffset)) { - Heap::markCell(reinterpret_cast<JSCell*>(xAsBits)); - goto endMarkLoop; - } + usedBlocks = m_heap.usedBlocks; + for (size_t block = 0; block < usedBlocks; block++) { + if (blocks[block] != blockAddr) + continue; + markStack.append(reinterpret_cast<JSCell*>(xAsBits)); + markStack.drain(); } - - // Mark the primary heap - for (size_t block = 0; block < usedPrimaryBlocks; block++) { - if ((primaryBlocks[block] == blockAddr) & (offset <= lastCellOffset)) { - if (reinterpret_cast<CollectorCell*>(xAsBits)->u.freeCell.zeroIfFree) { - markStack.append(reinterpret_cast<JSCell*>(xAsBits)); - markStack.drain(); - } - break; - } - } - endMarkLoop: - ; } } } @@ -869,10 +888,10 @@ void Heap::markCurrentThreadConservatively(MarkStack& markStack) static inline void suspendThread(const PlatformThread& platformThread) { -#if PLATFORM(DARWIN) +#if OS(DARWIN) thread_suspend(platformThread); -#elif PLATFORM(WIN_OS) - SuspendThread(platformThread.handle); +#elif OS(WINDOWS) + SuspendThread(platformThread); #else #error Need a way to suspend threads on this platform #endif @@ -880,10 +899,10 @@ static inline void suspendThread(const PlatformThread& platformThread) static inline void resumeThread(const PlatformThread& platformThread) { -#if PLATFORM(DARWIN) +#if OS(DARWIN) thread_resume(platformThread); -#elif PLATFORM(WIN_OS) - ResumeThread(platformThread.handle); +#elif OS(WINDOWS) + ResumeThread(platformThread); #else #error Need a way to resume threads on this platform #endif @@ -891,23 +910,23 @@ static inline void resumeThread(const PlatformThread& platformThread) typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit -#if PLATFORM(DARWIN) +#if OS(DARWIN) -#if PLATFORM(X86) +#if CPU(X86) typedef i386_thread_state_t PlatformThreadRegisters; -#elif PLATFORM(X86_64) +#elif CPU(X86_64) typedef x86_thread_state64_t PlatformThreadRegisters; -#elif PLATFORM(PPC) +#elif CPU(PPC) typedef ppc_thread_state_t PlatformThreadRegisters; -#elif PLATFORM(PPC64) +#elif CPU(PPC64) typedef ppc_thread_state64_t PlatformThreadRegisters; -#elif PLATFORM(ARM) +#elif CPU(ARM) typedef arm_thread_state_t PlatformThreadRegisters; #else #error Unknown Architecture #endif -#elif PLATFORM(WIN_OS)&& PLATFORM(X86) +#elif OS(WINDOWS) && CPU(X86) typedef CONTEXT PlatformThreadRegisters; #else #error Need a thread register struct for this platform @@ -915,21 +934,21 @@ typedef CONTEXT PlatformThreadRegisters; static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, PlatformThreadRegisters& regs) { -#if PLATFORM(DARWIN) +#if OS(DARWIN) -#if PLATFORM(X86) +#if CPU(X86) unsigned user_count = sizeof(regs)/sizeof(int); thread_state_flavor_t flavor = i386_THREAD_STATE; -#elif PLATFORM(X86_64) +#elif CPU(X86_64) unsigned user_count = x86_THREAD_STATE64_COUNT; thread_state_flavor_t flavor = x86_THREAD_STATE64; -#elif PLATFORM(PPC) +#elif CPU(PPC) unsigned user_count = PPC_THREAD_STATE_COUNT; thread_state_flavor_t flavor = PPC_THREAD_STATE; -#elif PLATFORM(PPC64) +#elif CPU(PPC64) unsigned user_count = PPC_THREAD_STATE64_COUNT; thread_state_flavor_t flavor = PPC_THREAD_STATE64; -#elif PLATFORM(ARM) +#elif CPU(ARM) unsigned user_count = ARM_THREAD_STATE_COUNT; thread_state_flavor_t flavor = ARM_THREAD_STATE; #else @@ -943,11 +962,11 @@ static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, P CRASH(); } return user_count * sizeof(usword_t); -// end PLATFORM(DARWIN) +// end OS(DARWIN) -#elif PLATFORM(WIN_OS) && PLATFORM(X86) +#elif OS(WINDOWS) && CPU(X86) regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS; - GetThreadContext(platformThread.handle, ®s); + GetThreadContext(platformThread, ®s); return sizeof(CONTEXT); #else #error Need a way to get thread registers on this platform @@ -956,17 +975,17 @@ static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, P static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs) { -#if PLATFORM(DARWIN) +#if OS(DARWIN) #if __DARWIN_UNIX03 -#if PLATFORM(X86) +#if CPU(X86) return reinterpret_cast<void*>(regs.__esp); -#elif PLATFORM(X86_64) +#elif CPU(X86_64) return reinterpret_cast<void*>(regs.__rsp); -#elif PLATFORM(PPC) || PLATFORM(PPC64) +#elif CPU(PPC) || CPU(PPC64) return reinterpret_cast<void*>(regs.__r1); -#elif PLATFORM(ARM) +#elif CPU(ARM) return reinterpret_cast<void*>(regs.__sp); #else #error Unknown Architecture @@ -974,11 +993,11 @@ static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs) #else // !__DARWIN_UNIX03 -#if PLATFORM(X86) +#if CPU(X86) return reinterpret_cast<void*>(regs.esp); -#elif PLATFORM(X86_64) +#elif CPU(X86_64) return reinterpret_cast<void*>(regs.rsp); -#elif (PLATFORM(PPC) || PLATFORM(PPC64)) +#elif CPU(PPC) || CPU(PPC64) return reinterpret_cast<void*>(regs.r1); #else #error Unknown Architecture @@ -986,8 +1005,8 @@ static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs) #endif // __DARWIN_UNIX03 -// end PLATFORM(DARWIN) -#elif PLATFORM(X86) && PLATFORM(WIN_OS) +// end OS(DARWIN) +#elif CPU(X86) && OS(WINDOWS) return reinterpret_cast<void*>((uintptr_t) regs.Esp); #else #error Need a way to get the stack pointer for another thread on this platform @@ -1041,16 +1060,6 @@ void Heap::markStackObjectsConservatively(MarkStack& markStack) #endif } -void Heap::setGCProtectNeedsLocking() -{ - // Most clients do not need to call this, with the notable exception of WebCore. - // Clients that use shared heap have JSLock protection, while others are supposed - // to do explicit locking. WebCore violates this contract in Database code, - // which calls gcUnprotect from a secondary thread. - if (!m_protectedValuesMutex) - m_protectedValuesMutex.set(new Mutex); -} - void Heap::protect(JSValue k) { ASSERT(k); @@ -1059,13 +1068,7 @@ void Heap::protect(JSValue k) if (!k.isCell()) return; - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - m_protectedValues.add(k.asCell()); - - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); } void Heap::unprotect(JSValue k) @@ -1076,133 +1079,80 @@ void Heap::unprotect(JSValue k) if (!k.isCell()) return; - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - m_protectedValues.remove(k.asCell()); - - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); } void Heap::markProtectedObjects(MarkStack& markStack) { - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - ProtectCountSet::iterator end = m_protectedValues.end(); for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) { markStack.append(it->first); markStack.drain(); } +} - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); +void Heap::clearMarkBits() +{ + for (size_t i = 0; i < m_heap.usedBlocks; ++i) + clearMarkBits(m_heap.blocks[i]); } -template <HeapType heapType> size_t Heap::sweep() +void Heap::clearMarkBits(CollectorBlock* block) { - typedef typename HeapConstants<heapType>::Block Block; - typedef typename HeapConstants<heapType>::Cell Cell; + // allocate assumes that the last cell in every block is marked. + block->marked.clearAll(); + block->marked.set(HeapConstants::cellsPerBlock - 1); +} - // SWEEP: delete everything with a zero refcount (garbage) and unmark everything else - CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap; - - size_t emptyBlocks = 0; - size_t numLiveObjects = heap.numLiveObjects; - - for (size_t block = 0; block < heap.usedBlocks; block++) { - Block* curBlock = reinterpret_cast<Block*>(heap.blocks[block]); - - size_t usedCells = curBlock->usedCells; - Cell* freeList = curBlock->freeList; - - if (usedCells == HeapConstants<heapType>::cellsPerBlock) { - // special case with a block where all cells are used -- testing indicates this happens often - for (size_t i = 0; i < HeapConstants<heapType>::cellsPerBlock; i++) { - if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) { - Cell* cell = curBlock->cells + i; - - if (heapType != NumberHeap) { - JSCell* imp = reinterpret_cast<JSCell*>(cell); - // special case for allocated but uninitialized object - // (We don't need this check earlier because nothing prior this point - // assumes the object has a valid vptr.) - if (cell->u.freeCell.zeroIfFree == 0) - continue; - - imp->~JSCell(); - } - - --usedCells; - --numLiveObjects; - - // put cell on the free list - cell->u.freeCell.zeroIfFree = 0; - cell->u.freeCell.next = freeList - (cell + 1); - freeList = cell; - } - } - } else { - size_t minimumCellsToProcess = usedCells; - for (size_t i = 0; (i < minimumCellsToProcess) & (i < HeapConstants<heapType>::cellsPerBlock); i++) { - Cell* cell = curBlock->cells + i; - if (cell->u.freeCell.zeroIfFree == 0) { - ++minimumCellsToProcess; - } else { - if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) { - if (heapType != NumberHeap) { - JSCell* imp = reinterpret_cast<JSCell*>(cell); - imp->~JSCell(); - } - --usedCells; - --numLiveObjects; - - // put cell on the free list - cell->u.freeCell.zeroIfFree = 0; - cell->u.freeCell.next = freeList - (cell + 1); - freeList = cell; - } - } - } - } - - curBlock->usedCells = static_cast<uint32_t>(usedCells); - curBlock->freeList = freeList; - curBlock->marked.clearAll(); - - if (!usedCells) - ++emptyBlocks; - } - - if (heap.numLiveObjects != numLiveObjects) - heap.firstBlockWithPossibleSpace = 0; - - heap.numLiveObjects = numLiveObjects; - heap.numLiveObjectsAtLastCollect = numLiveObjects; - heap.extraCost = 0; - - if (!emptyBlocks) - return numLiveObjects; +size_t Heap::markedCells(size_t startBlock, size_t startCell) const +{ + ASSERT(startBlock <= m_heap.usedBlocks); + ASSERT(startCell < HeapConstants::cellsPerBlock); - size_t neededCells = 1.25f * (numLiveObjects + max(ALLOCATIONS_PER_COLLECTION, numLiveObjects)); - size_t neededBlocks = (neededCells + HeapConstants<heapType>::cellsPerBlock - 1) / HeapConstants<heapType>::cellsPerBlock; - for (size_t block = 0; block < heap.usedBlocks; block++) { - if (heap.usedBlocks <= neededBlocks) - break; + if (startBlock >= m_heap.usedBlocks) + return 0; + + size_t result = 0; + result += m_heap.blocks[startBlock]->marked.count(startCell); + for (size_t i = startBlock + 1; i < m_heap.usedBlocks; ++i) + result += m_heap.blocks[i]->marked.count(); + + return result; +} - Block* curBlock = reinterpret_cast<Block*>(heap.blocks[block]); - if (curBlock->usedCells) - continue; +void Heap::sweep() +{ + ASSERT(m_heap.operationInProgress == NoOperation); + if (m_heap.operationInProgress != NoOperation) + CRASH(); + m_heap.operationInProgress = Collection; + +#if !ENABLE(JSC_ZOMBIES) + Structure* dummyMarkableCellStructure = m_globalData->dummyMarkableCellStructure.get(); +#endif - freeBlock<heapType>(block); - block--; // Don't move forward a step in this case + DeadObjectIterator it(m_heap, m_heap.nextBlock, m_heap.nextCell); + DeadObjectIterator end(m_heap, m_heap.usedBlocks); + for ( ; it != end; ++it) { + JSCell* cell = *it; +#if ENABLE(JSC_ZOMBIES) + if (!cell->isZombie()) { + const ClassInfo* info = cell->classInfo(); + cell->~JSCell(); + new (cell) JSZombie(info, JSZombie::leakedZombieStructure()); + Heap::markCell(cell); + } +#else + cell->~JSCell(); + // Callers of sweep assume it's safe to mark any cell in the heap. + new (cell) JSCell(dummyMarkableCellStructure); +#endif } - return numLiveObjects; + m_heap.operationInProgress = NoOperation; } -bool Heap::collect() +void Heap::markRoots() { #ifndef NDEBUG if (m_globalData->isSharedInstance) { @@ -1211,27 +1161,34 @@ bool Heap::collect() } #endif - ASSERT((primaryHeap.operationInProgress == NoOperation) | (numberHeap.operationInProgress == NoOperation)); - if ((primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation)) + ASSERT(m_heap.operationInProgress == NoOperation); + if (m_heap.operationInProgress != NoOperation) CRASH(); - JAVASCRIPTCORE_GC_BEGIN(); - primaryHeap.operationInProgress = Collection; - numberHeap.operationInProgress = Collection; + m_heap.operationInProgress = Collection; - // MARK: first mark all referenced objects recursively starting out from the set of root objects MarkStack& markStack = m_globalData->markStack; + + // Reset mark bits. + clearMarkBits(); + + // Mark stack roots. markStackObjectsConservatively(markStack); + m_globalData->interpreter->registerFile().markCallFrames(markStack, this); + + // Mark explicitly registered roots. markProtectedObjects(markStack); + #if QT_BUILD_SCRIPT_LIB if (m_globalData->clientData) m_globalData->clientData->mark(markStack); #endif + + // Mark misc. other roots. if (m_markListSet && m_markListSet->size()) MarkedArgumentBuffer::markLists(markStack, *m_markListSet); if (m_globalData->exception) markStack.append(m_globalData->exception); - m_globalData->interpreter->registerFile().markCallFrames(markStack, this); m_globalData->smallStrings.markChildren(markStack); if (m_globalData->functionCodeBlockBeingReparsed) m_globalData->functionCodeBlockBeingReparsed->markAggregate(markStack); @@ -1240,41 +1197,28 @@ bool Heap::collect() markStack.drain(); markStack.compact(); - JAVASCRIPTCORE_GC_MARKED(); - - size_t originalLiveObjects = primaryHeap.numLiveObjects + numberHeap.numLiveObjects; - size_t numLiveObjects = sweep<PrimaryHeap>(); - numLiveObjects += sweep<NumberHeap>(); - - primaryHeap.operationInProgress = NoOperation; - numberHeap.operationInProgress = NoOperation; - JAVASCRIPTCORE_GC_END(originalLiveObjects, numLiveObjects); - return numLiveObjects < originalLiveObjects; + m_heap.operationInProgress = NoOperation; } -size_t Heap::objectCount() +size_t Heap::objectCount() const { - return primaryHeap.numLiveObjects + numberHeap.numLiveObjects - m_globalData->smallStrings.count(); + return m_heap.nextBlock * HeapConstants::cellsPerBlock // allocated full blocks + + m_heap.nextCell // allocated cells in current block + + markedCells(m_heap.nextBlock, m_heap.nextCell) // marked cells in remainder of m_heap + - m_heap.usedBlocks; // 1 cell per block is a dummy sentinel } -template <HeapType heapType> -static void addToStatistics(Heap::Statistics& statistics, const CollectorHeap& heap) +void Heap::addToStatistics(Heap::Statistics& statistics) const { - typedef HeapConstants<heapType> HC; - for (size_t i = 0; i < heap.usedBlocks; ++i) { - if (heap.blocks[i]) { - statistics.size += BLOCK_SIZE; - statistics.free += (HC::cellsPerBlock - heap.blocks[i]->usedCells) * HC::cellSize; - } - } + statistics.size += m_heap.usedBlocks * BLOCK_SIZE; + statistics.free += m_heap.usedBlocks * BLOCK_SIZE - (objectCount() * HeapConstants::cellSize); } Heap::Statistics Heap::statistics() const { Statistics statistics = { 0, 0 }; - JSC::addToStatistics<PrimaryHeap>(statistics, primaryHeap); - JSC::addToStatistics<NumberHeap>(statistics, numberHeap); + addToStatistics(statistics); return statistics; } @@ -1293,9 +1237,6 @@ size_t Heap::globalObjectCount() size_t Heap::protectedGlobalObjectCount() { - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - size_t count = 0; if (JSGlobalObject* head = m_globalData->head) { JSGlobalObject* o = head; @@ -1306,23 +1247,12 @@ size_t Heap::protectedGlobalObjectCount() } while (o != head); } - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); - return count; } size_t Heap::protectedObjectCount() { - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - - size_t result = m_protectedValues.size(); - - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); - - return result; + return m_protectedValues.size(); } static const char* typeName(JSCell* cell) @@ -1335,6 +1265,10 @@ static const char* typeName(JSCell* cell) #endif if (cell->isGetterSetter()) return "gettersetter"; + if (cell->isAPIValueWrapper()) + return "value wrapper"; + if (cell->isPropertyNameIterator()) + return "for-in iterator"; ASSERT(cell->isObject()); const ClassInfo* info = cell->classInfo(); return info ? info->className : "Object"; @@ -1344,32 +1278,70 @@ HashCountedSet<const char*>* Heap::protectedObjectTypeCounts() { HashCountedSet<const char*>* counts = new HashCountedSet<const char*>; - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - ProtectCountSet::iterator end = m_protectedValues.end(); for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) counts->add(typeName(it->first)); - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); - return counts; } bool Heap::isBusy() { - return (primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation); + return m_heap.operationInProgress != NoOperation; +} + +void Heap::reset() +{ + JAVASCRIPTCORE_GC_BEGIN(); + + markRoots(); + + JAVASCRIPTCORE_GC_MARKED(); + + m_heap.nextCell = 0; + m_heap.nextBlock = 0; + m_heap.nextNumber = 0; + m_heap.extraCost = 0; +#if ENABLE(JSC_ZOMBIES) + sweep(); +#endif + resizeBlocks(); + + JAVASCRIPTCORE_GC_END(); +} + +void Heap::collectAllGarbage() +{ + JAVASCRIPTCORE_GC_BEGIN(); + + // If the last iteration through the heap deallocated blocks, we need + // to clean up remaining garbage before marking. Otherwise, the conservative + // marking mechanism might follow a pointer to unmapped memory. + if (m_heap.didShrink) + sweep(); + + markRoots(); + + JAVASCRIPTCORE_GC_MARKED(); + + m_heap.nextCell = 0; + m_heap.nextBlock = 0; + m_heap.nextNumber = 0; + m_heap.extraCost = 0; + sweep(); + resizeBlocks(); + + JAVASCRIPTCORE_GC_END(); } -Heap::iterator Heap::primaryHeapBegin() +LiveObjectIterator Heap::primaryHeapBegin() { - return iterator(primaryHeap.blocks, primaryHeap.blocks + primaryHeap.usedBlocks); + return LiveObjectIterator(m_heap, 0); } -Heap::iterator Heap::primaryHeapEnd() +LiveObjectIterator Heap::primaryHeapEnd() { - return iterator(primaryHeap.blocks + primaryHeap.usedBlocks, primaryHeap.blocks + primaryHeap.usedBlocks); + return LiveObjectIterator(m_heap, m_heap.usedBlocks); } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.h index 0ecff19..7f7a679 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.h @@ -28,9 +28,9 @@ #include <wtf/HashSet.h> #include <wtf/Noncopyable.h> #include <wtf/OwnPtr.h> +#include <wtf/StdLibExtras.h> #include <wtf/Threading.h> -// This is supremely lame that we require pthreads to build on windows. #if ENABLE(JSC_MULTIPLE_THREADS) #include <pthread.h> #endif @@ -47,19 +47,21 @@ namespace JSC { class MarkStack; enum OperationInProgress { NoOperation, Allocation, Collection }; - enum HeapType { PrimaryHeap, NumberHeap }; - template <HeapType> class CollectorHeapIterator; + class LiveObjectIterator; struct CollectorHeap { + size_t nextBlock; + size_t nextCell; CollectorBlock** blocks; + + void* nextNumber; + size_t numBlocks; size_t usedBlocks; - size_t firstBlockWithPossibleSpace; - size_t numLiveObjects; - size_t numLiveObjectsAtLastCollect; size_t extraCost; + bool didShrink; OperationInProgress operationInProgress; }; @@ -67,36 +69,27 @@ namespace JSC { class Heap : public Noncopyable { public: class Thread; - typedef CollectorHeapIterator<PrimaryHeap> iterator; void destroy(); -#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE - // We can inline these functions because everything is compiled as - // one file, so the heapAllocate template definitions are available. - // However, allocateNumber is used via jsNumberCell outside JavaScriptCore. - // Thus allocateNumber needs to provide a non-inline version too. - void* inlineAllocateNumber(size_t s) { return heapAllocate<NumberHeap>(s); } - void* inlineAllocate(size_t s) { return heapAllocate<PrimaryHeap>(s); } -#endif void* allocateNumber(size_t); void* allocate(size_t); - bool collect(); bool isBusy(); // true if an allocation or collection is in progress + void collectAllGarbage(); - static const size_t minExtraCostSize = 256; + static const size_t minExtraCost = 256; + static const size_t maxExtraCost = 1024 * 1024; void reportExtraMemoryCost(size_t cost); - size_t objectCount(); + size_t objectCount() const; struct Statistics { size_t size; size_t free; }; Statistics statistics() const; - void setGCProtectNeedsLocking(); void protect(JSValue); void unprotect(JSValue); @@ -120,13 +113,12 @@ namespace JSC { JSGlobalData* globalData() const { return m_globalData; } static bool isNumber(JSCell*); - // Iterators for the object heap. - iterator primaryHeapBegin(); - iterator primaryHeapEnd(); + LiveObjectIterator primaryHeapBegin(); + LiveObjectIterator primaryHeapEnd(); private: - template <HeapType heapType> void* heapAllocate(size_t); - template <HeapType heapType> size_t sweep(); + void reset(); + void sweep(); static CollectorBlock* cellBlock(const JSCell*); static size_t cellOffset(const JSCell*); @@ -134,12 +126,22 @@ namespace JSC { Heap(JSGlobalData*); ~Heap(); - template <HeapType heapType> NEVER_INLINE CollectorBlock* allocateBlock(); - template <HeapType heapType> NEVER_INLINE void freeBlock(size_t); - NEVER_INLINE void freeBlock(CollectorBlock*); - void freeBlocks(CollectorHeap*); + NEVER_INLINE CollectorBlock* allocateBlock(); + NEVER_INLINE void freeBlock(size_t); + NEVER_INLINE void freeBlockPtr(CollectorBlock*); + void freeBlocks(); + void resizeBlocks(); + void growBlocks(size_t neededBlocks); + void shrinkBlocks(size_t neededBlocks); + void clearMarkBits(); + void clearMarkBits(CollectorBlock*); + size_t markedCells(size_t startBlock = 0, size_t startCell = 0) const; void recordExtraCost(size_t); + + void addToStatistics(Statistics&) const; + + void markRoots(); void markProtectedObjects(MarkStack&); void markCurrentThreadConservatively(MarkStack&); void markCurrentThreadConservativelyInternal(MarkStack&); @@ -148,10 +150,8 @@ namespace JSC { typedef HashCountedSet<JSCell*> ProtectCountSet; - CollectorHeap primaryHeap; - CollectorHeap numberHeap; + CollectorHeap m_heap; - OwnPtr<Mutex> m_protectedValuesMutex; // Only non-null if the client explicitly requested it via setGCPrtotectNeedsLocking(). ProtectCountSet m_protectedValues; HashSet<MarkedArgumentBuffer*>* m_markListSet; @@ -181,7 +181,7 @@ namespace JSC { #endif template<> struct CellSize<sizeof(uint64_t)> { static const size_t m_value = 64; }; -#if PLATFORM(WINCE) || PLATFORM(SYMBIAN) +#if OS(WINCE) || OS(SYMBIAN) const size_t BLOCK_SIZE = 64 * 1024; // 64k #else const size_t BLOCK_SIZE = 64 * 4096; // 256k @@ -196,87 +196,60 @@ namespace JSC { const size_t SMALL_CELL_SIZE = CELL_SIZE / 2; const size_t CELL_MASK = CELL_SIZE - 1; const size_t CELL_ALIGN_MASK = ~CELL_MASK; - const size_t CELLS_PER_BLOCK = (BLOCK_SIZE * 8 - sizeof(uint32_t) * 8 - sizeof(void *) * 8 - 2 * (7 + 3 * 8)) / (CELL_SIZE * 8 + 2); - const size_t SMALL_CELLS_PER_BLOCK = 2 * CELLS_PER_BLOCK; + const size_t CELLS_PER_BLOCK = (BLOCK_SIZE - sizeof(Heap*)) * 8 * CELL_SIZE / (8 * CELL_SIZE + 1) / CELL_SIZE; // one bitmap byte can represent 8 cells. + const size_t BITMAP_SIZE = (CELLS_PER_BLOCK + 7) / 8; const size_t BITMAP_WORDS = (BITMAP_SIZE + 3) / sizeof(uint32_t); - + struct CollectorBitmap { uint32_t bits[BITMAP_WORDS]; bool get(size_t n) const { return !!(bits[n >> 5] & (1 << (n & 0x1F))); } void set(size_t n) { bits[n >> 5] |= (1 << (n & 0x1F)); } void clear(size_t n) { bits[n >> 5] &= ~(1 << (n & 0x1F)); } void clearAll() { memset(bits, 0, sizeof(bits)); } + size_t count(size_t startCell = 0) + { + size_t result = 0; + for ( ; (startCell & 0x1F) != 0; ++startCell) { + if (get(startCell)) + ++result; + } + for (size_t i = startCell >> 5; i < BITMAP_WORDS; ++i) + result += WTF::bitCount(bits[i]); + return result; + } + size_t isEmpty() // Much more efficient than testing count() == 0. + { + for (size_t i = 0; i < BITMAP_WORDS; ++i) + if (bits[i] != 0) + return false; + return true; + } }; struct CollectorCell { - union { - double memory[CELL_ARRAY_LENGTH]; - struct { - void* zeroIfFree; - ptrdiff_t next; - } freeCell; - } u; - }; - - struct SmallCollectorCell { - union { - double memory[CELL_ARRAY_LENGTH / 2]; - struct { - void* zeroIfFree; - ptrdiff_t next; - } freeCell; - } u; + double memory[CELL_ARRAY_LENGTH]; }; class CollectorBlock { public: CollectorCell cells[CELLS_PER_BLOCK]; - uint32_t usedCells; - CollectorCell* freeList; - CollectorBitmap marked; - Heap* heap; - HeapType type; - }; - - class SmallCellCollectorBlock { - public: - SmallCollectorCell cells[SMALL_CELLS_PER_BLOCK]; - uint32_t usedCells; - SmallCollectorCell* freeList; CollectorBitmap marked; Heap* heap; - HeapType type; }; - - template <HeapType heapType> struct HeapConstants; - template <> struct HeapConstants<PrimaryHeap> { + struct HeapConstants { static const size_t cellSize = CELL_SIZE; static const size_t cellsPerBlock = CELLS_PER_BLOCK; - static const size_t bitmapShift = 0; typedef CollectorCell Cell; typedef CollectorBlock Block; }; - template <> struct HeapConstants<NumberHeap> { - static const size_t cellSize = SMALL_CELL_SIZE; - static const size_t cellsPerBlock = SMALL_CELLS_PER_BLOCK; - static const size_t bitmapShift = 1; - typedef SmallCollectorCell Cell; - typedef SmallCellCollectorBlock Block; - }; - inline CollectorBlock* Heap::cellBlock(const JSCell* cell) { return reinterpret_cast<CollectorBlock*>(reinterpret_cast<uintptr_t>(cell) & BLOCK_MASK); } - inline bool Heap::isNumber(JSCell* cell) - { - return Heap::cellBlock(cell)->type == NumberHeap; - } - inline size_t Heap::cellOffset(const JSCell* cell) { return (reinterpret_cast<uintptr_t>(cell) & BLOCK_OFFSET_MASK) / CELL_SIZE; @@ -294,8 +267,20 @@ namespace JSC { inline void Heap::reportExtraMemoryCost(size_t cost) { - if (cost > minExtraCostSize) - recordExtraCost(cost / (CELL_SIZE * 2)); + if (cost > minExtraCost) + recordExtraCost(cost); + } + + inline void* Heap::allocateNumber(size_t s) + { + if (void* result = m_heap.nextNumber) { + m_heap.nextNumber = 0; + return result; + } + + void* result = allocate(s); + m_heap.nextNumber = static_cast<char*>(result) + (CELL_SIZE / 2); + return result; } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CollectorHeapIterator.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CollectorHeapIterator.h index e38a852..e4f2f91 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CollectorHeapIterator.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CollectorHeapIterator.h @@ -31,58 +31,108 @@ namespace JSC { - template <HeapType heapType> class CollectorHeapIterator { + class CollectorHeapIterator { public: - CollectorHeapIterator(CollectorBlock** block, CollectorBlock** endBlock); - - bool operator!=(const CollectorHeapIterator<heapType>& other) { return m_block != other.m_block || m_cell != other.m_cell; } - CollectorHeapIterator<heapType>& operator++(); + bool operator!=(const CollectorHeapIterator& other); JSCell* operator*() const; - private: - typedef typename HeapConstants<heapType>::Block Block; - typedef typename HeapConstants<heapType>::Cell Cell; - - Block** m_block; - Block** m_endBlock; - Cell* m_cell; - Cell* m_endCell; + protected: + CollectorHeapIterator(CollectorHeap&, size_t startBlock, size_t startCell); + void advance(size_t cellsPerBlock); + + CollectorHeap& m_heap; + size_t m_block; + size_t m_cell; + }; + + class LiveObjectIterator : public CollectorHeapIterator { + public: + LiveObjectIterator(CollectorHeap&, size_t startBlock, size_t startCell = 0); + LiveObjectIterator& operator++(); + }; + + class DeadObjectIterator : public CollectorHeapIterator { + public: + DeadObjectIterator(CollectorHeap&, size_t startBlock, size_t startCell = 0); + DeadObjectIterator& operator++(); + }; + + class ObjectIterator : public CollectorHeapIterator { + public: + ObjectIterator(CollectorHeap&, size_t startBlock, size_t startCell = 0); + ObjectIterator& operator++(); }; - template <HeapType heapType> - CollectorHeapIterator<heapType>::CollectorHeapIterator(CollectorBlock** block, CollectorBlock** endBlock) - : m_block(reinterpret_cast<Block**>(block)) - , m_endBlock(reinterpret_cast<Block**>(endBlock)) - , m_cell(m_block == m_endBlock ? 0 : (*m_block)->cells) - , m_endCell(m_block == m_endBlock ? 0 : (*m_block)->cells + HeapConstants<heapType>::cellsPerBlock) + inline CollectorHeapIterator::CollectorHeapIterator(CollectorHeap& heap, size_t startBlock, size_t startCell) + : m_heap(heap) + , m_block(startBlock) + , m_cell(startCell) + { + } + + inline bool CollectorHeapIterator::operator!=(const CollectorHeapIterator& other) + { + return m_block != other.m_block || m_cell != other.m_cell; + } + + inline JSCell* CollectorHeapIterator::operator*() const + { + return reinterpret_cast<JSCell*>(m_heap.blocks[m_block]->cells + m_cell); + } + + inline void CollectorHeapIterator::advance(size_t cellsPerBlock) + { + ++m_cell; + if (m_cell == cellsPerBlock) { + m_cell = 0; + ++m_block; + } + } + + inline LiveObjectIterator::LiveObjectIterator(CollectorHeap& heap, size_t startBlock, size_t startCell) + : CollectorHeapIterator(heap, startBlock, startCell - 1) + { + ++(*this); + } + + inline LiveObjectIterator& LiveObjectIterator::operator++() + { + if (m_block < m_heap.nextBlock || m_cell < m_heap.nextCell) { + advance(HeapConstants::cellsPerBlock); + return *this; + } + + do { + advance(HeapConstants::cellsPerBlock); + } while (m_block < m_heap.usedBlocks && !m_heap.blocks[m_block]->marked.get(m_cell)); + return *this; + } + + inline DeadObjectIterator::DeadObjectIterator(CollectorHeap& heap, size_t startBlock, size_t startCell) + : CollectorHeapIterator(heap, startBlock, startCell - 1) { - if (m_cell && m_cell->u.freeCell.zeroIfFree == 0) - ++*this; + ++(*this); } - template <HeapType heapType> - CollectorHeapIterator<heapType>& CollectorHeapIterator<heapType>::operator++() + inline DeadObjectIterator& DeadObjectIterator::operator++() { do { - for (++m_cell; m_cell != m_endCell; ++m_cell) - if (m_cell->u.freeCell.zeroIfFree != 0) { - return *this; - } - - if (++m_block != m_endBlock) { - m_cell = (*m_block)->cells; - m_endCell = (*m_block)->cells + HeapConstants<heapType>::cellsPerBlock; - } - } while(m_block != m_endBlock); - - m_cell = 0; + advance(HeapConstants::cellsPerBlock); + ASSERT(m_block > m_heap.nextBlock || (m_block == m_heap.nextBlock && m_cell >= m_heap.nextCell)); + } while (m_block < m_heap.usedBlocks && m_heap.blocks[m_block]->marked.get(m_cell)); return *this; } - template <HeapType heapType> - JSCell* CollectorHeapIterator<heapType>::operator*() const + inline ObjectIterator::ObjectIterator(CollectorHeap& heap, size_t startBlock, size_t startCell) + : CollectorHeapIterator(heap, startBlock, startCell - 1) { - return reinterpret_cast<JSCell*>(m_cell); + ++(*this); + } + + inline ObjectIterator& ObjectIterator::operator++() + { + advance(HeapConstants::cellsPerBlock); + return *this; } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CommonIdentifiers.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CommonIdentifiers.h index abe5038..de24f4a 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CommonIdentifiers.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/CommonIdentifiers.h @@ -50,6 +50,7 @@ macro(get) \ macro(getPrototypeOf) \ macro(getOwnPropertyDescriptor) \ + macro(getOwnPropertyNames) \ macro(hasOwnProperty) \ macro(ignoreCase) \ macro(index) \ diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Completion.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Completion.cpp index 3ad467d..2f88df9 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Completion.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Completion.cpp @@ -31,18 +31,15 @@ #include "Debugger.h" #include <stdio.h> -#ifdef QT_BUILD_SCRIPT_LIB -#include "DebuggerCallFrame.h" -#endif - namespace JSC { Completion checkSyntax(ExecState* exec, const SourceCode& source) { JSLock lock(exec); + ASSERT(exec->globalData().identifierTable == currentIdentifierTable()); - ProgramExecutable program(exec, source); - JSObject* error = program.checkSyntax(exec); + RefPtr<ProgramExecutable> program = ProgramExecutable::create(exec, source); + JSObject* error = program->checkSyntax(exec); if (error) return Completion(Throw, error); @@ -52,23 +49,23 @@ Completion checkSyntax(ExecState* exec, const SourceCode& source) Completion evaluate(ExecState* exec, ScopeChain& scopeChain, const SourceCode& source, JSValue thisValue) { JSLock lock(exec); + ASSERT(exec->globalData().identifierTable == currentIdentifierTable()); - ProgramExecutable program(exec, source); - JSObject* error = program.compile(exec, scopeChain.node()); + RefPtr<ProgramExecutable> program = ProgramExecutable::create(exec, source); + JSObject* error = program->compile(exec, scopeChain.node()); if (error) return Completion(Throw, error); JSObject* thisObj = (!thisValue || thisValue.isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue.toObject(exec); JSValue exception; - JSValue result = exec->interpreter()->execute(&program, exec, scopeChain.node(), thisObj, &exception); + JSValue result = exec->interpreter()->execute(program.get(), exec, scopeChain.node(), thisObj, &exception); if (exception) { if (exception.isObject() && asObject(exception)->isWatchdogException()) return Completion(Interrupted, exception); return Completion(Throw, exception); } - return Completion(Normal, result); } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ConstructData.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ConstructData.cpp index 3dfc918..06f9459 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ConstructData.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ConstructData.cpp @@ -28,7 +28,6 @@ #include "JSFunction.h" - #ifdef QT_BUILD_SCRIPT_LIB #include "Debugger.h" #include "DebuggerCallFrame.h" @@ -53,13 +52,13 @@ JSObject* JSC::NativeConstrWrapper::operator() (ExecState* exec, JSObject* jsobj } #endif -JSObject* construct(ExecState* exec, JSValue callee, ConstructType constructType, const ConstructData& constructData, const ArgList& args) +JSObject* construct(ExecState* exec, JSValue object, ConstructType constructType, const ConstructData& constructData, const ArgList& args) { if (constructType == ConstructTypeHost) - return constructData.native.function(exec, asObject(callee), args); + return constructData.native.function(exec, asObject(object), args); ASSERT(constructType == ConstructTypeJS); // FIXME: Can this be done more efficiently using the constructData? - return asFunction(callee)->construct(exec, args); + return asFunction(object)->construct(exec, args); } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ConstructData.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ConstructData.h index 1dcfb00..9298f51 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ConstructData.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ConstructData.h @@ -70,7 +70,7 @@ namespace JSC { }; #endif -#if defined(QT_BUILD_SCRIPT_LIB) && PLATFORM(SOLARIS) +#if defined(QT_BUILD_SCRIPT_LIB) && OS(SOLARIS) struct #else union diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.cpp index 1879c3f..2e476b3 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.cpp @@ -35,7 +35,7 @@ #include <wtf/DateMath.h> #include <wtf/MathExtras.h> -#if PLATFORM(WINCE) && !PLATFORM(QT) +#if OS(WINCE) && !PLATFORM(QT) extern "C" time_t time(time_t* timer); // Provided by libce. #endif @@ -57,7 +57,7 @@ static JSValue JSC_HOST_CALL dateParse(ExecState*, JSObject*, JSValue, const Arg static JSValue JSC_HOST_CALL dateNow(ExecState*, JSObject*, JSValue, const ArgList&); static JSValue JSC_HOST_CALL dateUTC(ExecState*, JSObject*, JSValue, const ArgList&); -DateConstructor::DateConstructor(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure, DatePrototype* datePrototype) +DateConstructor::DateConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure, DatePrototype* datePrototype) : InternalFunction(&exec->globalData(), structure, Identifier(exec, datePrototype->classInfo()->className)) { putDirectWithoutTransition(exec->propertyNames().prototype, datePrototype, DontEnum|DontDelete|ReadOnly); @@ -77,14 +77,14 @@ JSObject* constructDate(ExecState* exec, const ArgList& args) double value; if (numArgs == 0) // new Date() ECMA 15.9.3.3 - value = getCurrentUTCTime(); + value = jsCurrentTime(); else if (numArgs == 1) { if (args.at(0).inherits(&DateInstance::info)) value = asDateInstance(args.at(0))->internalNumber(); else { JSValue primitive = args.at(0).toPrimitive(exec); if (primitive.isString()) - value = parseDate(primitive.getString()); + value = parseDate(exec, primitive.getString(exec)); else value = primitive.toNumber(exec); } @@ -108,13 +108,11 @@ JSObject* constructDate(ExecState* exec, const ArgList& args) t.second = args.at(5).toInt32(exec); t.isDST = -1; double ms = (numArgs >= 7) ? args.at(6).toNumber(exec) : 0; - value = gregorianDateTimeToMS(t, ms, false); + value = gregorianDateTimeToMS(exec, t, ms, false); } } - DateInstance* result = new (exec) DateInstance(exec->lexicalGlobalObject()->dateStructure()); - result->setInternalValue(jsNumber(exec, timeClip(value))); - return result; + return new (exec) DateInstance(exec, value); } static JSObject* constructWithDateConstructor(ExecState* exec, JSObject*, const ArgList& args) @@ -134,8 +132,12 @@ static JSValue JSC_HOST_CALL callDate(ExecState* exec, JSObject*, JSValue, const time_t localTime = time(0); tm localTM; getLocalTime(&localTime, &localTM); - GregorianDateTime ts(localTM); - return jsNontrivialString(exec, formatDate(ts) + " " + formatTime(ts, false)); + GregorianDateTime ts(exec, localTM); + DateConversionBuffer date; + DateConversionBuffer time; + formatDate(ts, date); + formatTime(ts, time); + return jsNontrivialString(exec, makeString(date, " ", time)); } CallType DateConstructor::getCallData(CallData& callData) @@ -146,12 +148,12 @@ CallType DateConstructor::getCallData(CallData& callData) static JSValue JSC_HOST_CALL dateParse(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, parseDate(args.at(0).toString(exec))); + return jsNumber(exec, parseDate(exec, args.at(0).toString(exec))); } static JSValue JSC_HOST_CALL dateNow(ExecState* exec, JSObject*, JSValue, const ArgList&) { - return jsNumber(exec, getCurrentUTCTime()); + return jsNumber(exec, jsCurrentTime()); } static JSValue JSC_HOST_CALL dateUTC(ExecState* exec, JSObject*, JSValue, const ArgList& args) @@ -175,7 +177,7 @@ static JSValue JSC_HOST_CALL dateUTC(ExecState* exec, JSObject*, JSValue, const t.minute = args.at(4).toInt32(exec); t.second = args.at(5).toInt32(exec); double ms = (n >= 7) ? args.at(6).toNumber(exec) : 0; - return jsNumber(exec, gregorianDateTimeToMS(t, ms, true)); + return jsNumber(exec, gregorianDateTimeToMS(exec, t, ms, true)); } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.h index dcef3cc..10e450e 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.h @@ -29,7 +29,7 @@ namespace JSC { class DateConstructor : public InternalFunction { public: - DateConstructor(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure, DatePrototype*); + DateConstructor(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure, DatePrototype*); private: virtual ConstructType getConstructData(ConstructData&); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConversion.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConversion.cpp index a725478..f129407 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConversion.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConversion.cpp @@ -43,6 +43,7 @@ #include "config.h" #include "DateConversion.h" +#include "CallFrame.h" #include "UString.h" #include <wtf/DateMath.h> #include <wtf/StringExtras.h> @@ -51,51 +52,51 @@ using namespace WTF; namespace JSC { -double parseDate(const UString &date) +double parseDate(ExecState* exec, const UString &date) { - return parseDateFromNullTerminatedCharacters(date.UTF8String().c_str()); + if (date == exec->globalData().cachedDateString) + return exec->globalData().cachedDateStringValue; + double value = parseDateFromNullTerminatedCharacters(exec, date.UTF8String().c_str()); + exec->globalData().cachedDateString = date; + exec->globalData().cachedDateStringValue = value; + return value; } -UString formatDate(const GregorianDateTime &t) +void formatDate(const GregorianDateTime &t, DateConversionBuffer& buffer) { - char buffer[100]; - snprintf(buffer, sizeof(buffer), "%s %s %02d %04d", + snprintf(buffer, DateConversionBufferSize, "%s %s %02d %04d", weekdayName[(t.weekDay + 6) % 7], monthName[t.month], t.monthDay, t.year + 1900); - return buffer; } -UString formatDateUTCVariant(const GregorianDateTime &t) +void formatDateUTCVariant(const GregorianDateTime &t, DateConversionBuffer& buffer) { - char buffer[100]; - snprintf(buffer, sizeof(buffer), "%s, %02d %s %04d", + snprintf(buffer, DateConversionBufferSize, "%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) +void formatTime(const GregorianDateTime &t, DateConversionBuffer& buffer) { - 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); + 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); - } + if (timeZoneName[0]) { + snprintf(buffer, DateConversionBufferSize, "%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, DateConversionBufferSize, "%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); +} + +void formatTimeUTC(const GregorianDateTime &t, DateConversionBuffer& buffer) +{ + snprintf(buffer, DateConversionBufferSize, "%02d:%02d:%02d GMT", t.hour, t.minute, t.second); } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConversion.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConversion.h index 0d12815..ff32b50 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConversion.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConversion.h @@ -42,18 +42,21 @@ #ifndef DateConversion_h #define DateConversion_h -namespace WTF { - struct GregorianDateTime; -} +#include "UString.h" namespace JSC { -class UString; +class ExecState; +struct GregorianDateTime; -double parseDate(const UString&); -UString formatDate(const WTF::GregorianDateTime&); -UString formatDateUTCVariant(const WTF::GregorianDateTime&); -UString formatTime(const WTF::GregorianDateTime&, bool inputIsUTC); +static const unsigned DateConversionBufferSize = 100; +typedef char DateConversionBuffer[DateConversionBufferSize]; + +double parseDate(ExecState* exec, const UString&); +void formatDate(const GregorianDateTime&, DateConversionBuffer&); +void formatDateUTCVariant(const GregorianDateTime&, DateConversionBuffer&); +void formatTime(const GregorianDateTime&, DateConversionBuffer&); +void formatTimeUTC(const GregorianDateTime&, DateConversionBuffer&); } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstance.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstance.cpp index 62791ae..77a92be 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstance.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstance.cpp @@ -22,6 +22,8 @@ #include "config.h" #include "DateInstance.h" +#include "JSGlobalObject.h" + #include <math.h> #include <wtf/DateMath.h> #include <wtf/MathExtras.h> @@ -30,89 +32,50 @@ using namespace WTF; namespace JSC { -struct DateInstance::Cache { - double m_gregorianDateTimeCachedForMS; - GregorianDateTime m_cachedGregorianDateTime; - double m_gregorianDateTimeUTCCachedForMS; - GregorianDateTime m_cachedGregorianDateTimeUTC; -}; - const ClassInfo DateInstance::info = {"Date", 0, 0, 0}; -DateInstance::DateInstance(PassRefPtr<Structure> structure) +DateInstance::DateInstance(ExecState* exec, NonNullPassRefPtr<Structure> structure) : JSWrapperObject(structure) - , m_cache(0) { + setInternalValue(jsNaN(exec)); } -DateInstance::~DateInstance() +DateInstance::DateInstance(ExecState* exec, double time) + : JSWrapperObject(exec->lexicalGlobalObject()->dateStructure()) { - delete m_cache; + setInternalValue(jsNumber(exec, timeClip(time))); } -void DateInstance::msToGregorianDateTime(double milli, bool outputIsUTC, GregorianDateTime& t) const -{ - if (!m_cache) { - m_cache = new Cache; - m_cache->m_gregorianDateTimeCachedForMS = NaN; - m_cache->m_gregorianDateTimeUTCCachedForMS = NaN; - } - - if (outputIsUTC) { - if (m_cache->m_gregorianDateTimeUTCCachedForMS != milli) { - 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) { - WTF::msToGregorianDateTime(milli, false, m_cache->m_cachedGregorianDateTime); - m_cache->m_gregorianDateTimeCachedForMS = milli; - } - t.copyFrom(m_cache->m_cachedGregorianDateTime); - } -} - -bool DateInstance::getTime(GregorianDateTime& t, int& offset) const +const GregorianDateTime* DateInstance::calculateGregorianDateTime(ExecState* exec) const { double milli = internalNumber(); if (isnan(milli)) - return false; - - msToGregorianDateTime(milli, false, t); - offset = gmtoffset(t); - return true; + return 0; + + if (!m_data) + m_data = exec->globalData().dateInstanceCache.add(milli); + + if (m_data->m_gregorianDateTimeCachedForMS != milli) { + msToGregorianDateTime(exec, milli, false, m_data->m_cachedGregorianDateTime); + m_data->m_gregorianDateTimeCachedForMS = milli; + } + return &m_data->m_cachedGregorianDateTime; } -bool DateInstance::getUTCTime(GregorianDateTime& t) const +const GregorianDateTime* DateInstance::calculateGregorianDateTimeUTC(ExecState* exec) const { double milli = internalNumber(); if (isnan(milli)) - return false; - - msToGregorianDateTime(milli, true, t); - return true; -} + return 0; -bool DateInstance::getTime(double& milli, int& offset) const -{ - milli = internalNumber(); - if (isnan(milli)) - return false; - - GregorianDateTime t; - msToGregorianDateTime(milli, false, t); - offset = gmtoffset(t); - return true; -} + if (!m_data) + m_data = exec->globalData().dateInstanceCache.add(milli); -bool DateInstance::getUTCTime(double& milli) const -{ - milli = internalNumber(); - if (isnan(milli)) - return false; - - return true; + if (m_data->m_gregorianDateTimeUTCCachedForMS != milli) { + msToGregorianDateTime(exec, milli, true, m_data->m_cachedGregorianDateTimeUTC); + m_data->m_gregorianDateTimeUTCCachedForMS = milli; + } + return &m_data->m_cachedGregorianDateTimeUTC; } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstance.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstance.h index 3b73521..44b7521 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstance.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstance.h @@ -31,27 +31,41 @@ namespace JSC { class DateInstance : public JSWrapperObject { public: - explicit DateInstance(PassRefPtr<Structure>); - virtual ~DateInstance(); + DateInstance(ExecState*, double); + explicit DateInstance(ExecState*, NonNullPassRefPtr<Structure>); double internalNumber() const { return internalValue().uncheckedGetNumber(); } - 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, WTF::GregorianDateTime&) const; + static JS_EXPORTDATA const ClassInfo info; + + const GregorianDateTime* gregorianDateTime(ExecState* exec) const + { + if (m_data && m_data->m_gregorianDateTimeCachedForMS == internalNumber()) + return &m_data->m_cachedGregorianDateTime; + return calculateGregorianDateTime(exec); + } + + const GregorianDateTime* gregorianDateTimeUTC(ExecState* exec) const + { + if (m_data && m_data->m_gregorianDateTimeUTCCachedForMS == internalNumber()) + return &m_data->m_cachedGregorianDateTimeUTC; + return calculateGregorianDateTimeUTC(exec); + } + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); + } + + protected: + static const unsigned StructureFlags = OverridesMarkChildren | JSWrapperObject::StructureFlags; private: + const GregorianDateTime* calculateGregorianDateTime(ExecState*) const; + const GregorianDateTime* calculateGregorianDateTimeUTC(ExecState*) const; virtual const ClassInfo* classInfo() const { return &info; } - using JSWrapperObject::internalValue; - - struct Cache; - mutable Cache* m_cache; + mutable RefPtr<DateInstanceData> m_data; }; DateInstance* asDateInstance(JSValue); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstanceCache.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstanceCache.h new file mode 100644 index 0000000..d208580 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateInstanceCache.h @@ -0,0 +1,94 @@ +/* + * 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 DateInstanceCache_h +#define DateInstanceCache_h + +#include <wtf/DateMath.h> +#include <wtf/HashFunctions.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace JSC { + + extern const double NaN; + + class DateInstanceData : public RefCounted<DateInstanceData> { + public: + static PassRefPtr<DateInstanceData> create() { return adoptRef(new DateInstanceData); } + + double m_gregorianDateTimeCachedForMS; + GregorianDateTime m_cachedGregorianDateTime; + double m_gregorianDateTimeUTCCachedForMS; + GregorianDateTime m_cachedGregorianDateTimeUTC; + + private: + DateInstanceData() + : m_gregorianDateTimeCachedForMS(NaN) + , m_gregorianDateTimeUTCCachedForMS(NaN) + { + } + }; + + class DateInstanceCache { + public: + DateInstanceCache() + { + reset(); + } + + void reset() + { + for (size_t i = 0; i < cacheSize; ++i) + m_cache[i].key = NaN; + } + + DateInstanceData* add(double d) + { + CacheEntry& entry = lookup(d); + if (d == entry.key) + return entry.value.get(); + + entry.key = d; + entry.value = DateInstanceData::create(); + return entry.value.get(); + } + + private: + static const size_t cacheSize = 16; + + struct CacheEntry { + double key; + RefPtr<DateInstanceData> value; + }; + + CacheEntry& lookup(double d) { return m_cache[WTF::FloatHash<double>::hash(d) & (cacheSize - 1)]; } + + CacheEntry m_cache[cacheSize]; + }; + +} // namespace JSC + +#endif // DateInstanceCache_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DatePrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DatePrototype.cpp index c6f7dec..ca9d4ea 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DatePrototype.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DatePrototype.cpp @@ -28,7 +28,6 @@ #include "JSString.h" #include "ObjectPrototype.h" #include "DateInstance.h" -#include <float.h> #if !PLATFORM(MAC) && HAVE(LANGINFO_H) #include <langinfo.h> @@ -60,7 +59,7 @@ #include <CoreFoundation/CoreFoundation.h> #endif -#if PLATFORM(WINCE) && !PLATFORM(QT) +#if OS(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 @@ -198,7 +197,7 @@ 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)) || PLATFORM(SYMBIAN) +#elif (OS(WINCE) && !PLATFORM(QT)) || OS(SYMBIAN) // strftime() does not support '#' on WinCE or Symbian static const char* const formatStrings[] = { "%c", "%x", "%X" }; #else @@ -251,12 +250,12 @@ static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, L return jsNontrivialString(exec, timebuffer); } -static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double timeInMilliseconds, LocaleDateTimeFormat format, const ArgList&) +static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double, LocaleDateTimeFormat format, const ArgList&) { - GregorianDateTime gregorianDateTime; - const bool notUTC = false; - dateObject->msToGregorianDateTime(timeInMilliseconds, notUTC, gregorianDateTime); - return formatLocaleDate(exec, gregorianDateTime, format); + const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNontrivialString(exec, "Invalid Date"); + return formatLocaleDate(exec, *gregorianDateTime, format); } #endif // !PLATFORM(MAC) @@ -395,10 +394,9 @@ const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, 0, ExecState // ECMA 15.9.4 -DatePrototype::DatePrototype(ExecState* exec, PassRefPtr<Structure> structure) - : DateInstance(structure) +DatePrototype::DatePrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure) + : DateInstance(exec, structure) { - setInternalValue(jsNaN(exec)); // The constructor will be added later, after DateConstructor has been built. } @@ -420,16 +418,16 @@ JSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec, JSObject*, JSValue if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNontrivialString(exec, "Invalid Date"); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNontrivialString(exec, formatDate(t) + " " + formatTime(t, utc)); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNontrivialString(exec, "Invalid Date"); + DateConversionBuffer date; + DateConversionBuffer time; + formatDate(*gregorianDateTime, date); + formatTime(*gregorianDateTime, time); + return jsNontrivialString(exec, makeString(date, " ", time)); } JSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -437,16 +435,16 @@ JSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec, JSObject*, JSVal if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNontrivialString(exec, "Invalid Date"); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNontrivialString(exec, formatDateUTCVariant(t) + " " + formatTime(t, utc)); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNontrivialString(exec, "Invalid Date"); + DateConversionBuffer date; + DateConversionBuffer time; + formatDateUTCVariant(*gregorianDateTime, date); + formatTimeUTC(*gregorianDateTime, time); + return jsNontrivialString(exec, makeString(date, " ", time)); } JSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -454,19 +452,15 @@ JSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec, JSObject*, JSVal if (!thisValue.inherits(&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); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNontrivialString(exec, "Invalid Date"); // Maximum amount of space we need in buffer: 6 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + 4 (. + 3 digits for milliseconds) // 6 for formatting and one for null termination = 27. We add one extra character to allow us to force null termination. char buffer[28]; - snprintf(buffer, sizeof(buffer) - 1, "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + t.year, t.month + 1, t.monthDay, t.hour, t.minute, t.second, static_cast<int>(fmod(milli, 1000))); + snprintf(buffer, sizeof(buffer) - 1, "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + gregorianDateTime->year, gregorianDateTime->month + 1, gregorianDateTime->monthDay, gregorianDateTime->hour, gregorianDateTime->minute, gregorianDateTime->second, static_cast<int>(fmod(thisDateObj->internalNumber(), 1000))); buffer[sizeof(buffer) - 1] = 0; return jsNontrivialString(exec, buffer); } @@ -476,16 +470,14 @@ JSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec, JSObject*, JSVa if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNontrivialString(exec, "Invalid Date"); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNontrivialString(exec, formatDate(t)); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNontrivialString(exec, "Invalid Date"); + DateConversionBuffer date; + formatDate(*gregorianDateTime, date); + return jsNontrivialString(exec, date); } JSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -493,16 +485,14 @@ JSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec, JSObject*, JSVa if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNontrivialString(exec, "Invalid Date"); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNontrivialString(exec, formatTime(t, utc)); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNontrivialString(exec, "Invalid Date"); + DateConversionBuffer time; + formatTime(*gregorianDateTime, time); + return jsNontrivialString(exec, time); } JSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) @@ -511,11 +501,7 @@ JSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec, JSObject*, JS return throwError(exec, TypeError); DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNontrivialString(exec, "Invalid Date"); - - return formatLocaleDate(exec, thisDateObj, milli, LocaleDateAndTime, args); + return formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime, args); } JSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) @@ -524,11 +510,7 @@ JSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec, JSObject* return throwError(exec, TypeError); DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNontrivialString(exec, "Invalid Date"); - - return formatLocaleDate(exec, thisDateObj, milli, LocaleDate, args); + return formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate, args); } JSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) @@ -537,11 +519,7 @@ JSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec, JSObject* return throwError(exec, TypeError); DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNontrivialString(exec, "Invalid Date"); - - return formatLocaleDate(exec, thisDateObj, milli, LocaleTime, args); + return formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime, args); } JSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -549,12 +527,7 @@ JSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec, JSObject*, JSValue t if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - - return jsNumber(exec, milli); + return asDateInstance(thisValue)->internalValue(); } JSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -562,16 +535,12 @@ JSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec, JSObject*, JSVal if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, 1900 + t.year); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, 1900 + gregorianDateTime->year); } JSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -579,16 +548,12 @@ JSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec, JSObject*, JS if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, 1900 + t.year); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, 1900 + gregorianDateTime->year); } JSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -596,16 +561,16 @@ JSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec, JSObject*, JSVal if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNontrivialString(exec, "Invalid Date"); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNontrivialString(exec, formatDateUTCVariant(t) + " " + formatTime(t, utc)); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNontrivialString(exec, "Invalid Date"); + DateConversionBuffer date; + DateConversionBuffer time; + formatDateUTCVariant(*gregorianDateTime, date); + formatTimeUTC(*gregorianDateTime, time); + return jsNontrivialString(exec, makeString(date, " ", time)); } JSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -613,16 +578,12 @@ JSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec, JSObject*, JSValue if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.month); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->month); } JSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -630,16 +591,12 @@ JSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec, JSObject*, JSVal if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.month); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->month); } JSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -647,16 +604,12 @@ JSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec, JSObject*, JSValue t if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.monthDay); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->monthDay); } JSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -664,16 +617,12 @@ JSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec, JSObject*, JSValu if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.monthDay); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->monthDay); } JSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -681,16 +630,12 @@ JSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec, JSObject*, JSValue th if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.weekDay); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->weekDay); } JSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -698,16 +643,12 @@ JSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec, JSObject*, JSValue if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.weekDay); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->weekDay); } JSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -715,16 +656,12 @@ JSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec, JSObject*, JSValue if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.hour); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->hour); } JSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -732,16 +669,12 @@ JSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec, JSObject*, JSVal if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.hour); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->hour); } JSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -749,16 +682,12 @@ JSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec, JSObject*, JSValu if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.minute); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->minute); } JSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -766,16 +695,12 @@ JSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec, JSObject*, JSV if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.minute); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->minute); } JSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -783,16 +708,12 @@ JSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec, JSObject*, JSValu if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.second); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->second); } JSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -800,16 +721,12 @@ JSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec, JSObject*, JSV if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.second); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->second); } JSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -847,16 +764,12 @@ JSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec, JSObject*, if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, -gmtoffset(t) / minutesPerHour); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, -gregorianDateTime->utcOffset / minutesPerHour); } JSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) @@ -889,16 +802,21 @@ static JSValue setNewValueFromTimeArgs(ExecState* exec, JSValue thisValue, const double secs = floor(milli / msPerSecond); double ms = milli - secs * msPerSecond; - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, inputIsUTC, t); + const GregorianDateTime* other = inputIsUTC + ? thisDateObj->gregorianDateTimeUTC(exec) + : thisDateObj->gregorianDateTime(exec); + if (!other) + return jsNaN(exec); - if (!fillStructuresUsingTimeArgs(exec, args, numArgsToUse, &ms, &t)) { + GregorianDateTime gregorianDateTime; + gregorianDateTime.copyFrom(*other); + if (!fillStructuresUsingTimeArgs(exec, args, numArgsToUse, &ms, &gregorianDateTime)) { JSValue result = jsNaN(exec); thisDateObj->setInternalValue(result); return result; } - JSValue result = jsNumber(exec, gregorianDateTimeToMS(t, ms, inputIsUTC)); + JSValue result = jsNumber(exec, gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC)); thisDateObj->setInternalValue(result); return result; } @@ -916,26 +834,28 @@ static JSValue setNewValueFromDateArgs(ExecState* exec, JSValue thisValue, const } double milli = thisDateObj->internalNumber(); - double ms = 0; - - GregorianDateTime t; - if (numArgsToUse == 3 && isnan(milli)) - // Based on ECMA 262 15.9.5.40 - .41 (set[UTC]FullYear) - // the time must be reset to +0 if it is NaN. - thisDateObj->msToGregorianDateTime(0, true, t); - else { - double secs = floor(milli / msPerSecond); - ms = milli - secs * msPerSecond; - thisDateObj->msToGregorianDateTime(milli, inputIsUTC, t); + double ms = 0; + + GregorianDateTime gregorianDateTime; + if (numArgsToUse == 3 && isnan(milli)) + msToGregorianDateTime(exec, 0, true, gregorianDateTime); + else { + ms = milli - floor(milli / msPerSecond) * msPerSecond; + const GregorianDateTime* other = inputIsUTC + ? thisDateObj->gregorianDateTimeUTC(exec) + : thisDateObj->gregorianDateTime(exec); + if (!other) + return jsNaN(exec); + gregorianDateTime.copyFrom(*other); } - if (!fillStructuresUsingDateArgs(exec, args, numArgsToUse, &ms, &t)) { + if (!fillStructuresUsingDateArgs(exec, args, numArgsToUse, &ms, &gregorianDateTime)) { JSValue result = jsNaN(exec); thisDateObj->setInternalValue(result); return result; } - JSValue result = jsNumber(exec, gregorianDateTimeToMS(t, ms, inputIsUTC)); + JSValue result = jsNumber(exec, gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC)); thisDateObj->setInternalValue(result); return result; } @@ -1029,8 +949,6 @@ JSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec, JSObject*, JSValue t if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); if (args.isEmpty()) { JSValue result = jsNaN(exec); @@ -1041,15 +959,16 @@ JSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec, JSObject*, JSValue t double milli = thisDateObj->internalNumber(); double ms = 0; - GregorianDateTime t; + GregorianDateTime gregorianDateTime; if (isnan(milli)) // Based on ECMA 262 B.2.5 (setYear) // the time must be reset to +0 if it is NaN. - thisDateObj->msToGregorianDateTime(0, true, t); + msToGregorianDateTime(exec, 0, true, gregorianDateTime); else { double secs = floor(milli / msPerSecond); ms = milli - secs * msPerSecond; - thisDateObj->msToGregorianDateTime(milli, utc, t); + if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec)) + gregorianDateTime.copyFrom(*other); } bool ok = true; @@ -1060,8 +979,8 @@ JSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec, JSObject*, JSValue t return result; } - t.year = (year > 99 || year < 0) ? year - 1900 : year; - JSValue result = jsNumber(exec, gregorianDateTimeToMS(t, ms, utc)); + gregorianDateTime.year = (year > 99 || year < 0) ? year - 1900 : year; + JSValue result = jsNumber(exec, gregorianDateTimeToMS(exec, gregorianDateTime, ms, false)); thisDateObj->setInternalValue(result); return result; } @@ -1071,18 +990,14 @@ JSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec, JSObject*, JSValue t if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); // NOTE: IE returns the full year even in getYear. - return jsNumber(exec, t.year); + return jsNumber(exec, gregorianDateTime->year); } JSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DatePrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DatePrototype.h index 12fabda..f565775 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DatePrototype.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DatePrototype.h @@ -29,7 +29,7 @@ namespace JSC { class DatePrototype : public DateInstance { public: - DatePrototype(ExecState*, PassRefPtr<Structure>); + DatePrototype(ExecState*, NonNullPassRefPtr<Structure>); virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); @@ -39,8 +39,12 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, HasDefaultGetPropertyNames)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } + + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | DateInstance::StructureFlags; + }; } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorConstructor.cpp index 07b7e23..b9c3f58 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorConstructor.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorConstructor.cpp @@ -29,7 +29,7 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(ErrorConstructor); -ErrorConstructor::ErrorConstructor(ExecState* exec, PassRefPtr<Structure> structure, ErrorPrototype* errorPrototype) +ErrorConstructor::ErrorConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, ErrorPrototype* errorPrototype) : InternalFunction(&exec->globalData(), structure, Identifier(exec, errorPrototype->classInfo()->className)) { // ECMA 15.11.3.1 Error.prototype diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorConstructor.h index 2dd4124..e3d789b 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorConstructor.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorConstructor.h @@ -30,7 +30,7 @@ namespace JSC { class ErrorConstructor : public InternalFunction { public: - ErrorConstructor(ExecState*, PassRefPtr<Structure>, ErrorPrototype*); + ErrorConstructor(ExecState*, NonNullPassRefPtr<Structure>, ErrorPrototype*); private: virtual ConstructType getConstructData(ConstructData&); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorInstance.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorInstance.cpp index 2e2cdce..1cdb87a 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorInstance.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorInstance.cpp @@ -25,7 +25,7 @@ namespace JSC { const ClassInfo ErrorInstance::info = { "Error", 0, 0, 0 }; -ErrorInstance::ErrorInstance(PassRefPtr<Structure> structure) +ErrorInstance::ErrorInstance(NonNullPassRefPtr<Structure> structure) : JSObject(structure) { } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorInstance.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorInstance.h index 6f9d262..9f53b51 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorInstance.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorInstance.h @@ -27,7 +27,7 @@ namespace JSC { class ErrorInstance : public JSObject { public: - explicit ErrorInstance(PassRefPtr<Structure>); + explicit ErrorInstance(NonNullPassRefPtr<Structure>); virtual const ClassInfo* classInfo() const { return &info; } static const ClassInfo info; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorPrototype.cpp index 599390e..be9e4b8 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorPrototype.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorPrototype.cpp @@ -34,7 +34,7 @@ ASSERT_CLASS_FITS_IN_CELL(ErrorPrototype); static JSValue JSC_HOST_CALL errorProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&); // ECMA 15.9.4 -ErrorPrototype::ErrorPrototype(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) +ErrorPrototype::ErrorPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) : ErrorInstance(structure) { // The constructor will be added later in ErrorConstructor's constructor @@ -48,21 +48,19 @@ ErrorPrototype::ErrorPrototype(ExecState* exec, PassRefPtr<Structure> structure, JSValue JSC_HOST_CALL errorProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { JSObject* thisObj = thisValue.toThisObject(exec); + JSValue name = thisObj->get(exec, exec->propertyNames().name); + JSValue message = thisObj->get(exec, exec->propertyNames().message); - UString s = "Error"; + // Mozilla-compatible format. - JSValue v = thisObj->get(exec, exec->propertyNames().name); - if (!v.isUndefined()) - s = v.toString(exec); - - v = thisObj->get(exec, exec->propertyNames().message); - if (!v.isUndefined()) { - // Mozilla-compatible format. - s += ": "; - s += v.toString(exec); + if (!name.isUndefined()) { + if (!message.isUndefined()) + return jsNontrivialString(exec, makeString(name.toString(exec), ": ", message.toString(exec))); + return jsNontrivialString(exec, name.toString(exec)); } - - return jsNontrivialString(exec, s); + if (!message.isUndefined()) + return jsNontrivialString(exec, makeString("Error: ", message.toString(exec))); + return jsNontrivialString(exec, "Error"); } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorPrototype.h index 53d12d9..a561590 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorPrototype.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ErrorPrototype.h @@ -29,7 +29,7 @@ namespace JSC { class ErrorPrototype : public ErrorInstance { public: - ErrorPrototype(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure); + ErrorPrototype(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure); }; } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ExceptionHelpers.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ExceptionHelpers.cpp index cc18b95..9bb740e 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ExceptionHelpers.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ExceptionHelpers.cpp @@ -66,15 +66,18 @@ JSValue createStackOverflowError(ExecState* exec) return createError(exec, RangeError, "Maximum call stack size exceeded."); } +JSValue createTypeError(ExecState* exec, const char* message) +{ + return createError(exec, TypeError, message); +} + JSValue createUndefinedVariableError(ExecState* exec, const Identifier& ident, unsigned bytecodeOffset, CodeBlock* codeBlock) { int startOffset = 0; int endOffset = 0; int divotPoint = 0; int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); - UString message = "Can't find variable: "; - message.append(ident.ustring()); - JSObject* exception = Error::create(exec, ReferenceError, message, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL()); + JSObject* exception = Error::create(exec, ReferenceError, makeString("Can't find variable: ", ident.ustring()), line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL()); exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete); @@ -83,59 +86,36 @@ JSValue createUndefinedVariableError(ExecState* exec, const Identifier& ident, u static UString createErrorMessage(ExecState* exec, CodeBlock* codeBlock, int, int expressionStart, int expressionStop, JSValue value, UString error) { - if (!expressionStop || expressionStart > codeBlock->source()->length()) { - UString errorText = value.toString(exec); - errorText.append(" is "); - errorText.append(error); - return errorText; - } + if (!expressionStop || expressionStart > codeBlock->source()->length()) + return makeString(value.toString(exec), " is ", error); + if (expressionStart < expressionStop) + return makeString("Result of expression '", codeBlock->source()->getRange(expressionStart, expressionStop), "' [", value.toString(exec), "] is ", error, "."); - UString errorText = "Result of expression "; - - if (expressionStart < expressionStop) { - errorText.append('\''); - errorText.append(codeBlock->source()->getRange(expressionStart, expressionStop)); - errorText.append("' ["); - errorText.append(value.toString(exec)); - errorText.append("] is "); - } else { - // No range information, so give a few characters of context - const UChar* data = codeBlock->source()->data(); - int dataLength = codeBlock->source()->length(); - int start = expressionStart; - int stop = expressionStart; - // Get up to 20 characters of context to the left and right of the divot, clamping to the line. - // then strip whitespace. - while (start > 0 && (expressionStart - start < 20) && data[start - 1] != '\n') - start--; - while (start < (expressionStart - 1) && isStrWhiteSpace(data[start])) - start++; - while (stop < dataLength && (stop - expressionStart < 20) && data[stop] != '\n') - stop++; - while (stop > expressionStart && isStrWhiteSpace(data[stop])) - stop--; - errorText.append("near '..."); - errorText.append(codeBlock->source()->getRange(start, stop)); - errorText.append("...' ["); - errorText.append(value.toString(exec)); - errorText.append("] is "); - } - errorText.append(error); - errorText.append("."); - return errorText; + // No range information, so give a few characters of context + const UChar* data = codeBlock->source()->data(); + int dataLength = codeBlock->source()->length(); + int start = expressionStart; + int stop = expressionStart; + // Get up to 20 characters of context to the left and right of the divot, clamping to the line. + // then strip whitespace. + while (start > 0 && (expressionStart - start < 20) && data[start - 1] != '\n') + start--; + while (start < (expressionStart - 1) && isStrWhiteSpace(data[start])) + start++; + while (stop < dataLength && (stop - expressionStart < 20) && data[stop] != '\n') + stop++; + while (stop > expressionStart && isStrWhiteSpace(data[stop])) + stop--; + return makeString("Result of expression near '...", codeBlock->source()->getRange(start, stop), "...' [", value.toString(exec), "] is ", error, "."); } JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock) { - UString message = "not a valid argument for '"; - message.append(op); - message.append("'"); - int startOffset = 0; int endOffset = 0; int divotPoint = 0; int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); - UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint, divotPoint + endOffset, value, message); + UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint, divotPoint + endOffset, value, makeString("not a valid argument for '", op, "'")); JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL()); exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ExceptionHelpers.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ExceptionHelpers.h index 4c5bec1..e739d09 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ExceptionHelpers.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ExceptionHelpers.h @@ -44,6 +44,7 @@ namespace JSC { JSValue createInterruptedExecutionException(JSGlobalData*); JSValue createStackOverflowError(ExecState*); + JSValue createTypeError(ExecState*, const char* message); JSValue createUndefinedVariableError(ExecState*, const Identifier&, unsigned bytecodeOffset, CodeBlock*); JSNotAnObjectErrorStub* createNotAnObjectErrorStub(ExecState*, bool isNull); JSObject* createInvalidParamError(ExecState*, const char* op, JSValue, unsigned bytecodeOffset, CodeBlock*); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Executable.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Executable.cpp index 7586746..bc18cc9 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Executable.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Executable.cpp @@ -30,6 +30,7 @@ #include "CodeBlock.h" #include "JIT.h" #include "Parser.h" +#include "StringBuilder.h" #include "Vector.h" namespace JSC { @@ -265,14 +266,13 @@ PassRefPtr<FunctionExecutable> FunctionExecutable::fromGlobalCode(const Identifi UString FunctionExecutable::paramString() const { FunctionParameters& parameters = *m_parameters; - UString s(""); + StringBuilder builder; for (size_t pos = 0; pos < parameters.size(); ++pos) { - if (!s.isEmpty()) - s += ", "; - s += parameters[pos].ustring(); + if (!builder.isEmpty()) + builder.append(", "); + builder.append(parameters[pos].ustring()); } - - return s; + return builder.release(); } }; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Executable.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Executable.h index 76764f9..d1d38de 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Executable.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Executable.h @@ -158,11 +158,6 @@ namespace JSC { class EvalExecutable : public ScriptExecutable { public: - EvalExecutable(ExecState* exec, const SourceCode& source) - : ScriptExecutable(exec, source) - , m_evalCodeBlock(0) - { - } ~EvalExecutable(); @@ -181,6 +176,11 @@ namespace JSC { static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source) { return adoptRef(new EvalExecutable(exec, source)); } private: + EvalExecutable(ExecState* exec, const SourceCode& source) + : ScriptExecutable(exec, source) + , m_evalCodeBlock(0) + { + } EvalCodeBlock* m_evalCodeBlock; #if ENABLE(JIT) @@ -199,12 +199,11 @@ namespace JSC { class ProgramExecutable : public ScriptExecutable { public: - ProgramExecutable(ExecState* exec, const SourceCode& source) - : ScriptExecutable(exec, source) - , m_programCodeBlock(0) + static PassRefPtr<ProgramExecutable> create(ExecState* exec, const SourceCode& source) { + return adoptRef(new ProgramExecutable(exec, source)); } - + ~ProgramExecutable(); ProgramCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) @@ -223,6 +222,11 @@ namespace JSC { ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) { ASSERT_NOT_REACHED(); return 0; } private: + ProgramExecutable(ExecState* exec, const SourceCode& source) + : ScriptExecutable(exec, source) + , m_programCodeBlock(0) + { + } ProgramCodeBlock* m_programCodeBlock; #if ENABLE(JIT) @@ -282,7 +286,9 @@ namespace JSC { size_t parameterCount() const { return m_parameters->size(); } size_t variableCount() const { return m_numVariables; } UString paramString() const; +#ifdef QT_BUILD_SCRIPT_LIB UString parameterName(int i) const { return (*m_parameters)[i].ustring(); } +#endif void recompile(ExecState*); ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionConstructor.cpp index d5eb20f..9d55dd1 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionConstructor.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionConstructor.cpp @@ -21,20 +21,21 @@ #include "config.h" #include "FunctionConstructor.h" +#include "Debugger.h" #include "FunctionPrototype.h" #include "JSFunction.h" #include "JSGlobalObject.h" #include "JSString.h" -#include "Parser.h" -#include "Debugger.h" #include "Lexer.h" #include "Nodes.h" +#include "Parser.h" +#include "StringBuilder.h" namespace JSC { ASSERT_CLASS_FITS_IN_CELL(FunctionConstructor); -FunctionConstructor::FunctionConstructor(ExecState* exec, PassRefPtr<Structure> structure, FunctionPrototype* functionPrototype) +FunctionConstructor::FunctionConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, FunctionPrototype* functionPrototype) : InternalFunction(&exec->globalData(), structure, Identifier(exec, functionPrototype->classInfo()->className)) { putDirectWithoutTransition(exec->propertyNames().prototype, functionPrototype, DontEnum | DontDelete | ReadOnly); @@ -76,12 +77,19 @@ JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifi if (args.isEmpty()) program = "(function() { \n})"; else if (args.size() == 1) - program = "(function() { " + args.at(0).toString(exec) + "\n})"; + program = makeString("(function() { ", args.at(0).toString(exec), "\n})"); else { - program = "(function(" + args.at(0).toString(exec); - for (size_t i = 1; i < args.size() - 1; i++) - program += "," + args.at(i).toString(exec); - program += ") { " + args.at(args.size() - 1).toString(exec) + "\n})"; + StringBuilder builder; + builder.append("(function("); + builder.append(args.at(0).toString(exec)); + for (size_t i = 1; i < args.size() - 1; i++) { + builder.append(","); + builder.append(args.at(i).toString(exec)); + } + builder.append(") { "); + builder.append(args.at(args.size() - 1).toString(exec)); + builder.append("\n})"); + program = builder.release(); } int errLine; @@ -92,7 +100,7 @@ JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifi return throwError(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), source.provider()->url()); JSGlobalObject* globalObject = exec->lexicalGlobalObject(); - ScopeChain scopeChain(globalObject, globalObject->globalData(), exec->globalThisValue()); + ScopeChain scopeChain(globalObject, globalObject->globalData(), globalObject, exec->globalThisValue()); return new (exec) JSFunction(exec, function, scopeChain.node()); } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionConstructor.h index e8486dc..197f320 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionConstructor.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionConstructor.h @@ -29,7 +29,7 @@ namespace JSC { class FunctionConstructor : public InternalFunction { public: - FunctionConstructor(ExecState*, PassRefPtr<Structure>, FunctionPrototype*); + FunctionConstructor(ExecState*, NonNullPassRefPtr<Structure>, FunctionPrototype*); private: virtual ConstructType getConstructData(ConstructData&); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionPrototype.cpp index 1df998d..00f307e 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionPrototype.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionPrototype.cpp @@ -37,7 +37,7 @@ static JSValue JSC_HOST_CALL functionProtoFuncToString(ExecState*, JSObject*, JS static JSValue JSC_HOST_CALL functionProtoFuncApply(ExecState*, JSObject*, JSValue, const ArgList&); static JSValue JSC_HOST_CALL functionProtoFuncCall(ExecState*, JSObject*, JSValue, const ArgList&); -FunctionPrototype::FunctionPrototype(ExecState* exec, PassRefPtr<Structure> structure) +FunctionPrototype::FunctionPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure) : InternalFunction(&exec->globalData(), structure, exec->propertyNames().nullIdentifier) { putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 0), DontDelete | ReadOnly | DontEnum); @@ -76,7 +76,7 @@ static inline void insertSemicolonIfNeeded(UString& functionBody) UChar ch = functionBody[i]; if (!Lexer::isWhiteSpace(ch) && !Lexer::isLineTerminator(ch)) { if (ch != ';' && ch != '}') - functionBody = functionBody.substr(0, i + 1) + ";" + functionBody.substr(i + 1, functionBody.size() - (i + 1)); + functionBody = makeString(functionBody.substr(0, i + 1), ";", functionBody.substr(i + 1, functionBody.size() - (i + 1))); return; } } @@ -90,13 +90,13 @@ JSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec, JSObject*, JSVa FunctionExecutable* executable = function->jsExecutable(); UString sourceString = executable->source().toString(); insertSemicolonIfNeeded(sourceString); - return jsString(exec, "function " + function->name(&exec->globalData()) + "(" + executable->paramString() + ") " + sourceString); + return jsString(exec, makeString("function ", function->name(exec), "(", executable->paramString(), ") ", sourceString)); } } if (thisValue.inherits(&InternalFunction::info)) { InternalFunction* function = asInternalFunction(thisValue); - return jsString(exec, "function " + function->name(&exec->globalData()) + "() {\n [native code]\n}"); + return jsString(exec, makeString("function ", function->name(exec), "() {\n [native code]\n}")); } #ifdef QT_BUILD_SCRIPT_LIB //same error message as in the old engine, and in mozilla diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionPrototype.h index 469191e..d1d6a1d 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionPrototype.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/FunctionPrototype.h @@ -29,12 +29,12 @@ namespace JSC { class FunctionPrototype : public InternalFunction { public: - FunctionPrototype(ExecState*, PassRefPtr<Structure>); + FunctionPrototype(ExecState*, NonNullPassRefPtr<Structure>); void addFunctionProperties(ExecState*, Structure* prototypeFunctionStructure, NativeFunctionWrapper** callFunction, NativeFunctionWrapper** applyFunction); static PassRefPtr<Structure> createStructure(JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot | HasDefaultMark | HasDefaultGetPropertyNames)); + return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); } private: diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GetterSetter.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GetterSetter.h index 73dd854..68e9ea3 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GetterSetter.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GetterSetter.h @@ -50,7 +50,7 @@ namespace JSC { void setSetter(JSObject* setter) { m_setter = setter; } static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(GetterSetterType)); + return Structure::create(prototype, TypeInfo(GetterSetterType, OverridesMarkChildren)); } private: virtual bool isGetterSetter() const; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GlobalEvalFunction.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GlobalEvalFunction.cpp index 3074f95..c26002b 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GlobalEvalFunction.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GlobalEvalFunction.cpp @@ -32,7 +32,7 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(GlobalEvalFunction); -GlobalEvalFunction::GlobalEvalFunction(ExecState* exec, PassRefPtr<Structure> structure, int len, const Identifier& name, NativeFunction function, JSGlobalObject* cachedGlobalObject) +GlobalEvalFunction::GlobalEvalFunction(ExecState* exec, NonNullPassRefPtr<Structure> structure, int len, const Identifier& name, NativeFunction function, JSGlobalObject* cachedGlobalObject) : PrototypeFunction(exec, structure, len, name, function) , m_cachedGlobalObject(cachedGlobalObject) { diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GlobalEvalFunction.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GlobalEvalFunction.h index c56b0dc..389b1c3 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GlobalEvalFunction.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/GlobalEvalFunction.h @@ -32,14 +32,17 @@ namespace JSC { class GlobalEvalFunction : public PrototypeFunction { public: - GlobalEvalFunction(ExecState*, PassRefPtr<Structure>, int len, const Identifier&, NativeFunction, JSGlobalObject* expectedThisObject); + GlobalEvalFunction(ExecState*, NonNullPassRefPtr<Structure>, int len, const Identifier&, NativeFunction, JSGlobalObject* expectedThisObject); JSGlobalObject* cachedGlobalObject() const { return m_cachedGlobalObject; } static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, ImplementsHasInstance | HasStandardGetOwnPropertySlot)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } + protected: + static const unsigned StructureFlags = ImplementsHasInstance | OverridesMarkChildren | OverridesGetPropertyNames | PrototypeFunction::StructureFlags; + private: virtual void markChildren(MarkStack&); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Identifier.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Identifier.cpp index 7db723b..747c4ac 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Identifier.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Identifier.cpp @@ -28,6 +28,8 @@ #include <wtf/FastMalloc.h> #include <wtf/HashSet.h> +using WTF::ThreadSpecific; + namespace JSC { typedef HashMap<const char*, RefPtr<UString::Rep>, PtrHash<const char*> > LiteralIdentifierTable; @@ -38,13 +40,13 @@ public: { HashSet<UString::Rep*>::iterator end = m_table.end(); for (HashSet<UString::Rep*>::iterator iter = m_table.begin(); iter != end; ++iter) - (*iter)->setIdentifierTable(0); + (*iter)->setIsIdentifier(false); } std::pair<HashSet<UString::Rep*>::iterator, bool> add(UString::Rep* value) { std::pair<HashSet<UString::Rep*>::iterator, bool> result = m_table.add(value); - (*result.first)->setIdentifierTable(this); + (*result.first)->setIsIdentifier(true); return result; } @@ -52,7 +54,7 @@ public: std::pair<HashSet<UString::Rep*>::iterator, bool> add(U value) { std::pair<HashSet<UString::Rep*>::iterator, bool> result = m_table.add<U, V>(value); - (*result.first)->setIdentifierTable(this); + (*result.first)->setIsIdentifier(true); return result; } @@ -77,7 +79,7 @@ void deleteIdentifierTable(IdentifierTable* table) bool Identifier::equal(const UString::Rep* r, const char* s) { - int length = r->len; + int length = r->size(); const UChar* d = r->data(); for (int i = 0; i != length; ++i) if (d[i] != (unsigned char)s[i]) @@ -87,7 +89,7 @@ bool Identifier::equal(const UString::Rep* r, const char* s) bool Identifier::equal(const UString::Rep* r, const UChar* s, int length) { - if (r->len != length) + if (r->size() != length) return false; const UChar* d = r->data(); for (int i = 0; i != length; ++i) @@ -110,13 +112,11 @@ struct CStringTranslator { static void translate(UString::Rep*& location, const char* c, unsigned hash) { size_t length = strlen(c); - UChar* d = static_cast<UChar*>(fastMalloc(sizeof(UChar) * length)); + UChar* d; + UString::Rep* r = UString::Rep::createUninitialized(length, d).releaseRef(); for (size_t i = 0; i != length; i++) d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend - - UString::Rep* r = UString::Rep::create(d, static_cast<int>(length)).releaseRef(); - r->_hash = hash; - + r->setHash(hash); location = r; } }; @@ -175,13 +175,11 @@ struct UCharBufferTranslator { static void translate(UString::Rep*& location, const UCharBuffer& buf, unsigned hash) { - UChar* d = static_cast<UChar*>(fastMalloc(sizeof(UChar) * buf.length)); + UChar* d; + UString::Rep* r = UString::Rep::createUninitialized(buf.length, d).releaseRef(); for (unsigned i = 0; i != buf.length; i++) d[i] = buf.s[i]; - - UString::Rep* r = UString::Rep::create(d, buf.length).releaseRef(); - r->_hash = hash; - + r->setHash(hash); location = r; } }; @@ -212,19 +210,19 @@ PassRefPtr<UString::Rep> Identifier::add(ExecState* exec, const UChar* s, int le PassRefPtr<UString::Rep> Identifier::addSlowCase(JSGlobalData* globalData, UString::Rep* r) { - ASSERT(!r->identifierTable()); - if (r->len == 1) { + ASSERT(!r->isIdentifier()); + if (r->size() == 1) { UChar c = r->data()[0]; if (c <= 0xFF) r = globalData->smallStrings.singleCharacterStringRep(c); - if (r->identifierTable()) { + if (r->isIdentifier()) { #ifndef NDEBUG checkSameIdentifierTable(globalData, r); #endif return r; } } - if (!r->len) { + if (!r->size()) { UString::Rep::empty().hash(); return &UString::Rep::empty(); } @@ -238,19 +236,19 @@ PassRefPtr<UString::Rep> Identifier::addSlowCase(ExecState* exec, UString::Rep* void Identifier::remove(UString::Rep* r) { - r->identifierTable()->remove(r); + currentIdentifierTable()->remove(r); } #ifndef NDEBUG -void Identifier::checkSameIdentifierTable(ExecState* exec, UString::Rep* rep) +void Identifier::checkSameIdentifierTable(ExecState* exec, UString::Rep*) { - ASSERT(rep->identifierTable() == exec->globalData().identifierTable); + ASSERT_UNUSED(exec, exec->globalData().identifierTable == currentIdentifierTable()); } -void Identifier::checkSameIdentifierTable(JSGlobalData* globalData, UString::Rep* rep) +void Identifier::checkSameIdentifierTable(JSGlobalData* globalData, UString::Rep*) { - ASSERT(rep->identifierTable() == globalData->identifierTable); + ASSERT_UNUSED(globalData, globalData->identifierTable == currentIdentifierTable()); } #else @@ -265,4 +263,30 @@ void Identifier::checkSameIdentifierTable(JSGlobalData*, UString::Rep*) #endif +ThreadSpecific<ThreadIdentifierTableData>* g_identifierTableSpecific = 0; + +#if ENABLE(JSC_MULTIPLE_THREADS) + +pthread_once_t createIdentifierTableSpecificOnce = PTHREAD_ONCE_INIT; +static void createIdentifierTableSpecificCallback() +{ + ASSERT(!g_identifierTableSpecific); + g_identifierTableSpecific = new ThreadSpecific<ThreadIdentifierTableData>(); +} +void createIdentifierTableSpecific() +{ + pthread_once(&createIdentifierTableSpecificOnce, createIdentifierTableSpecificCallback); + ASSERT(g_identifierTableSpecific); +} + +#else + +void createIdentifierTableSpecific() +{ + ASSERT(!g_identifierTableSpecific); + g_identifierTableSpecific = new ThreadSpecific<ThreadIdentifierTableData>(); +} + +#endif + } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Identifier.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Identifier.h index 2249179..1d1bd18 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Identifier.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Identifier.h @@ -22,6 +22,7 @@ #define Identifier_h #include "JSGlobalData.h" +#include "ThreadSpecific.h" #include "UString.h" namespace JSC { @@ -92,7 +93,7 @@ namespace JSC { static PassRefPtr<UString::Rep> add(ExecState* exec, UString::Rep* r) { - if (r->identifierTable()) { + if (r->isIdentifier()) { #ifndef NDEBUG checkSameIdentifierTable(exec, r); #endif @@ -102,7 +103,7 @@ namespace JSC { } static PassRefPtr<UString::Rep> add(JSGlobalData* globalData, UString::Rep* r) { - if (r->identifierTable()) { + if (r->isIdentifier()) { #ifndef NDEBUG checkSameIdentifierTable(globalData, r); #endif @@ -141,6 +142,67 @@ namespace JSC { IdentifierTable* createIdentifierTable(); void deleteIdentifierTable(IdentifierTable*); + struct ThreadIdentifierTableData { + ThreadIdentifierTableData() + : defaultIdentifierTable(0) + , currentIdentifierTable(0) + { + } + + IdentifierTable* defaultIdentifierTable; + IdentifierTable* currentIdentifierTable; + }; + + extern WTF::ThreadSpecific<ThreadIdentifierTableData>* g_identifierTableSpecific; + void createIdentifierTableSpecific(); + + inline IdentifierTable* defaultIdentifierTable() + { + if (!g_identifierTableSpecific) + createIdentifierTableSpecific(); + ThreadIdentifierTableData& data = **g_identifierTableSpecific; + + return data.defaultIdentifierTable; + } + + inline void setDefaultIdentifierTable(IdentifierTable* identifierTable) + { + if (!g_identifierTableSpecific) + createIdentifierTableSpecific(); + ThreadIdentifierTableData& data = **g_identifierTableSpecific; + + data.defaultIdentifierTable = identifierTable; + } + + inline IdentifierTable* currentIdentifierTable() + { + if (!g_identifierTableSpecific) + createIdentifierTableSpecific(); + ThreadIdentifierTableData& data = **g_identifierTableSpecific; + + return data.currentIdentifierTable; + } + + inline IdentifierTable* setCurrentIdentifierTable(IdentifierTable* identifierTable) + { + if (!g_identifierTableSpecific) + createIdentifierTableSpecific(); + ThreadIdentifierTableData& data = **g_identifierTableSpecific; + + IdentifierTable* oldIdentifierTable = data.currentIdentifierTable; + data.currentIdentifierTable = identifierTable; + return oldIdentifierTable; + } + + inline void resetCurrentIdentifierTable() + { + if (!g_identifierTableSpecific) + createIdentifierTableSpecific(); + ThreadIdentifierTableData& data = **g_identifierTableSpecific; + + data.currentIdentifierTable = data.defaultIdentifierTable; + } + } // namespace JSC #endif // Identifier_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InitializeThreading.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InitializeThreading.cpp index fea89f8..2605a9a 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InitializeThreading.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InitializeThreading.cpp @@ -41,7 +41,7 @@ using namespace WTF; namespace JSC { -#if PLATFORM(DARWIN) && ENABLE(JSC_MULTIPLE_THREADS) +#if OS(DARWIN) && ENABLE(JSC_MULTIPLE_THREADS) static pthread_once_t initializeThreadingKeyOnce = PTHREAD_ONCE_INIT; #endif @@ -49,15 +49,16 @@ static void initializeThreadingOnce() { WTF::initializeThreading(); initializeUString(); + JSGlobalData::storeVPtrs(); #if ENABLE(JSC_MULTIPLE_THREADS) s_dtoaP5Mutex = new Mutex; - WTF::initializeDates(); + initializeDates(); #endif } void initializeThreading() { -#if PLATFORM(DARWIN) && ENABLE(JSC_MULTIPLE_THREADS) +#if OS(DARWIN) && ENABLE(JSC_MULTIPLE_THREADS) pthread_once(&initializeThreadingKeyOnce, initializeThreadingOnce); #else static bool initializedThreading = false; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InternalFunction.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InternalFunction.cpp index b5c9571..c48d628 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InternalFunction.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InternalFunction.cpp @@ -37,35 +37,35 @@ const ClassInfo* InternalFunction::classInfo() const return &info; } -InternalFunction::InternalFunction(JSGlobalData* globalData, PassRefPtr<Structure> structure, const Identifier& name) +InternalFunction::InternalFunction(JSGlobalData* globalData, NonNullPassRefPtr<Structure> structure, const Identifier& name) : JSObject(structure) { putDirect(globalData->propertyNames->name, jsString(globalData, name.ustring()), DontDelete | ReadOnly | DontEnum); } -const UString& InternalFunction::name(JSGlobalData* globalData) +const UString& InternalFunction::name(ExecState* exec) { - return asString(getDirect(globalData->propertyNames->name))->value(); + return asString(getDirect(exec->globalData().propertyNames->name))->value(exec); } -const UString InternalFunction::displayName(JSGlobalData* globalData) +const UString InternalFunction::displayName(ExecState* exec) { - JSValue displayName = getDirect(globalData->propertyNames->displayName); + JSValue displayName = getDirect(exec->globalData().propertyNames->displayName); - if (displayName && isJSString(globalData, displayName)) - return asString(displayName)->value(); + if (displayName && isJSString(&exec->globalData(), displayName)) + return asString(displayName)->value(exec); return UString::null(); } -const UString InternalFunction::calculatedDisplayName(JSGlobalData* globalData) +const UString InternalFunction::calculatedDisplayName(ExecState* exec) { - const UString explicitName = displayName(globalData); + const UString explicitName = displayName(exec); if (!explicitName.isEmpty()) return explicitName; - return name(globalData); + return name(exec); } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InternalFunction.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InternalFunction.h index 37077f6..fa1e5aa 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InternalFunction.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/InternalFunction.h @@ -36,18 +36,20 @@ namespace JSC { virtual const ClassInfo* classInfo() const; static JS_EXPORTDATA const ClassInfo info; - const UString& name(JSGlobalData*); - const UString displayName(JSGlobalData*); - const UString calculatedDisplayName(JSGlobalData*); + const UString& name(ExecState*); + const UString displayName(ExecState*); + const UString calculatedDisplayName(ExecState*); static PassRefPtr<Structure> createStructure(JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, ImplementsHasInstance | HasStandardGetOwnPropertySlot | HasDefaultMark)); + return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); } protected: - InternalFunction(PassRefPtr<Structure> structure) : JSObject(structure) { } - InternalFunction(JSGlobalData*, PassRefPtr<Structure>, const Identifier&); + static const unsigned StructureFlags = ImplementsHasInstance | JSObject::StructureFlags; + + InternalFunction(NonNullPassRefPtr<Structure> structure) : JSObject(structure) { } + InternalFunction(JSGlobalData*, NonNullPassRefPtr<Structure>, const Identifier&); private: virtual CallType getCallData(CallData&) = 0; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSAPIValueWrapper.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSAPIValueWrapper.h index 88a8493..aca550e 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSAPIValueWrapper.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSAPIValueWrapper.h @@ -39,7 +39,7 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(CompoundType)); + return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren | OverridesGetPropertyNames)); } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSActivation.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSActivation.cpp index d989a89..22fdaaf 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSActivation.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSActivation.cpp @@ -39,7 +39,7 @@ ASSERT_CLASS_FITS_IN_CELL(JSActivation); const ClassInfo JSActivation::info = { "JSActivation", 0, 0, 0 }; -JSActivation::JSActivation(CallFrame* callFrame, PassRefPtr<FunctionExecutable> functionExecutable) +JSActivation::JSActivation(CallFrame* callFrame, NonNullPassRefPtr<FunctionExecutable> functionExecutable) : Base(callFrame->globalData().activationStructure, new JSActivationData(functionExecutable, callFrame->registers())) { } @@ -121,12 +121,12 @@ void JSActivation::putWithAttributes(ExecState* exec, const Identifier& property JSObject::putWithAttributes(exec, propertyName, value, attributes, true, slot); } -bool JSActivation::deleteProperty(ExecState* exec, const Identifier& propertyName, bool checkDontDelete) +bool JSActivation::deleteProperty(ExecState* exec, const Identifier& propertyName) { if (propertyName == exec->propertyNames().arguments) return false; - return Base::deleteProperty(exec, propertyName, checkDontDelete); + return Base::deleteProperty(exec, propertyName); } JSObject* JSActivation::toThisObject(ExecState* exec) const diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSActivation.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSActivation.h index 90815a1..ee98191 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSActivation.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSActivation.h @@ -43,7 +43,7 @@ namespace JSC { class JSActivation : public JSVariableObject { typedef JSVariableObject Base; public: - JSActivation(CallFrame*, PassRefPtr<FunctionExecutable>); + JSActivation(CallFrame*, NonNullPassRefPtr<FunctionExecutable>); virtual ~JSActivation(); virtual void markChildren(MarkStack&); @@ -57,7 +57,7 @@ namespace JSC { virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); virtual void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes); - virtual bool deleteProperty(ExecState*, const Identifier& propertyName, bool checkDontDelete = true); + virtual bool deleteProperty(ExecState*, const Identifier& propertyName); virtual JSObject* toThisObject(ExecState*) const; @@ -66,11 +66,14 @@ namespace JSC { virtual const ClassInfo* classInfo() const { return &info; } static const ClassInfo info; - static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, NeedsThisConversion)); } + static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); } + + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NeedsThisConversion | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags; private: struct JSActivationData : public JSVariableObjectData { - JSActivationData(PassRefPtr<FunctionExecutable> _functionExecutable, Register* registers) + JSActivationData(NonNullPassRefPtr<FunctionExecutable> _functionExecutable, Register* registers) : JSVariableObjectData(_functionExecutable->generatedBytecode().symbolTable(), registers) , functionExecutable(_functionExecutable) { diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSArray.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSArray.cpp index 9e0ab59..2be7371 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSArray.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSArray.cpp @@ -130,7 +130,7 @@ inline void JSArray::checkConsistency(ConsistencyCheckType) #endif -JSArray::JSArray(PassRefPtr<Structure> structure) +JSArray::JSArray(NonNullPassRefPtr<Structure> structure) : JSObject(structure) { unsigned initialCapacity = 0; @@ -141,7 +141,7 @@ JSArray::JSArray(PassRefPtr<Structure> structure) checkConsistency(); } -JSArray::JSArray(PassRefPtr<Structure> structure, unsigned initialLength) +JSArray::JSArray(NonNullPassRefPtr<Structure> structure, unsigned initialLength) : JSObject(structure) { unsigned initialCapacity = min(initialLength, MIN_SPARSE_ARRAY_INDEX); @@ -152,6 +152,7 @@ JSArray::JSArray(PassRefPtr<Structure> structure, unsigned initialLength) m_storage->m_numValuesInVector = 0; m_storage->m_sparseValueMap = 0; m_storage->lazyCreationData = 0; + m_storage->reportedMapCapacity = 0; JSValue* vector = m_storage->m_vector; for (size_t i = 0; i < initialCapacity; ++i) @@ -162,7 +163,7 @@ JSArray::JSArray(PassRefPtr<Structure> structure, unsigned initialLength) Heap::heap(this)->reportExtraMemoryCost(initialCapacity * sizeof(JSValue)); } -JSArray::JSArray(PassRefPtr<Structure> structure, const ArgList& list) +JSArray::JSArray(NonNullPassRefPtr<Structure> structure, const ArgList& list) : JSObject(structure) { unsigned initialCapacity = list.size(); @@ -172,6 +173,8 @@ JSArray::JSArray(PassRefPtr<Structure> structure, const ArgList& list) m_vectorLength = initialCapacity; m_storage->m_numValuesInVector = initialCapacity; m_storage->m_sparseValueMap = 0; + m_storage->lazyCreationData = 0; + m_storage->reportedMapCapacity = 0; size_t i = 0; ArgList::const_iterator end = list.end(); @@ -185,6 +188,7 @@ JSArray::JSArray(PassRefPtr<Structure> structure, const ArgList& list) JSArray::~JSArray() { + ASSERT(vptr() == JSGlobalData::jsArrayVPtr); checkConsistency(DestructorConsistencyCheck); delete m_storage->m_sparseValueMap; @@ -328,13 +332,24 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue valu } // We miss some cases where we could compact the storage, such as a large array that is being filled from the end - // (which will only be compacted as we reach indices that are less than cutoff) - but this makes the check much faster. + // (which will only be compacted as we reach indices that are less than MIN_SPARSE_ARRAY_INDEX) - but this makes the check much faster. if ((i > MAX_STORAGE_VECTOR_INDEX) || !isDenseEnoughForVector(i + 1, storage->m_numValuesInVector + 1)) { if (!map) { map = new SparseArrayValueMap; storage->m_sparseValueMap = map; } - map->set(i, value); + + pair<SparseArrayValueMap::iterator, bool> result = map->add(i, value); + if (!result.second) { // pre-existing entry + result.first->second = value; + return; + } + + size_t capacity = map->capacity(); + if (capacity != storage->reportedMapCapacity) { + Heap::heap(this)->reportExtraMemoryCost((capacity - storage->reportedMapCapacity) * (sizeof(unsigned) + sizeof(JSValue))); + storage->reportedMapCapacity = capacity; + } return; } } @@ -380,8 +395,6 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue valu unsigned vectorLength = m_vectorLength; - Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); - if (newNumValuesInVector == storage->m_numValuesInVector + 1) { for (unsigned j = vectorLength; j < newVectorLength; ++j) storage->m_vector[j] = JSValue(); @@ -402,22 +415,24 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue valu m_storage = storage; checkConsistency(); + + Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); } -bool JSArray::deleteProperty(ExecState* exec, const Identifier& propertyName, bool checkDontDelete) +bool JSArray::deleteProperty(ExecState* exec, const Identifier& propertyName) { bool isArrayIndex; unsigned i = propertyName.toArrayIndex(&isArrayIndex); if (isArrayIndex) - return deleteProperty(exec, i, checkDontDelete); + return deleteProperty(exec, i); if (propertyName == exec->propertyNames().length) return false; - return JSObject::deleteProperty(exec, propertyName, checkDontDelete); + return JSObject::deleteProperty(exec, propertyName); } -bool JSArray::deleteProperty(ExecState* exec, unsigned i, bool checkDontDelete) +bool JSArray::deleteProperty(ExecState* exec, unsigned i) { checkConsistency(); @@ -449,12 +464,12 @@ bool JSArray::deleteProperty(ExecState* exec, unsigned i, bool checkDontDelete) checkConsistency(); if (i > MAX_ARRAY_INDEX) - return deleteProperty(exec, Identifier::from(exec, i), checkDontDelete); + return deleteProperty(exec, Identifier::from(exec, i)); return false; } -void JSArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, bool includeNonEnumerable) +void JSArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { // FIXME: Filling PropertyNameArray with an identifier for every integer // is incredibly inefficient for large arrays. We need a different approach, @@ -474,7 +489,10 @@ void JSArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNa propertyNames.add(Identifier::from(exec, it->first)); } - JSObject::getOwnPropertyNames(exec, propertyNames, includeNonEnumerable); + if (mode == IncludeDontEnumProperties) + propertyNames.add(exec->propertyNames().length); + + JSObject::getOwnPropertyNames(exec, propertyNames, mode); } bool JSArray::increaseVectorLength(unsigned newLength) @@ -492,13 +510,15 @@ bool JSArray::increaseVectorLength(unsigned newLength) if (!tryFastRealloc(storage, storageSize(newVectorLength)).getValue(storage)) return false; - Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); m_vectorLength = newVectorLength; for (unsigned i = vectorLength; i < newVectorLength; ++i) storage->m_vector[i] = JSValue(); m_storage = storage; + + Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); + return true; } @@ -785,7 +805,7 @@ struct AVLTreeAbstractorForArrayCompare { m_cachedCall->setThis(m_globalThisValue); m_cachedCall->setArgument(0, va); m_cachedCall->setArgument(1, vb); - compareResult = m_cachedCall->call().toNumber(m_cachedCall->newCallFrame()); + compareResult = m_cachedCall->call().toNumber(m_cachedCall->newCallFrame(m_exec)); } else { MarkedArgumentBuffer arguments; arguments.append(va); @@ -1051,26 +1071,4 @@ void JSArray::checkConsistency(ConsistencyCheckType type) #endif -JSArray* constructEmptyArray(ExecState* exec) -{ - return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure()); -} - -JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength) -{ - return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength); -} - -JSArray* constructArray(ExecState* exec, JSValue singleItemValue) -{ - MarkedArgumentBuffer values; - values.append(singleItemValue); - return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values); -} - -JSArray* constructArray(ExecState* exec, const ArgList& values) -{ - return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values); -} - } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSArray.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSArray.h index 2613991..64b2ff1 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSArray.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSArray.h @@ -32,6 +32,7 @@ namespace JSC { unsigned m_numValuesInVector; SparseArrayValueMap* m_sparseValueMap; void* lazyCreationData; // A JSArray subclass can use this to fill the vector lazily. + size_t reportedMapCapacity; JSValue m_vector[1]; }; @@ -40,9 +41,9 @@ namespace JSC { friend class Walker; public: - explicit JSArray(PassRefPtr<Structure>); - JSArray(PassRefPtr<Structure>, unsigned initialLength); - JSArray(PassRefPtr<Structure>, const ArgList& initialValues); + explicit JSArray(NonNullPassRefPtr<Structure>); + JSArray(NonNullPassRefPtr<Structure>, unsigned initialLength); + JSArray(NonNullPassRefPtr<Structure>, const ArgList& initialValues); virtual ~JSArray(); virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); @@ -87,16 +88,17 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } inline void markChildrenDirect(MarkStack& markStack); protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags; virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); - virtual bool deleteProperty(ExecState*, const Identifier& propertyName, bool checkDontDelete = true); - virtual bool deleteProperty(ExecState*, unsigned propertyName, bool checkDontDelete = true); - virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, bool includeNonEnumerable = false); + virtual bool deleteProperty(ExecState*, const Identifier& propertyName); + virtual bool deleteProperty(ExecState*, unsigned propertyName); + virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); virtual void markChildren(MarkStack&); void* lazyCreationData(); @@ -121,11 +123,6 @@ namespace JSC { JSArray* asArray(JSValue); - JSArray* constructEmptyArray(ExecState*); - JSArray* constructEmptyArray(ExecState*, unsigned initialLength); - JSArray* constructArray(ExecState*, JSValue singleItemValue); - JSArray* constructArray(ExecState*, const ArgList& values); - inline JSArray* asArray(JSCell* cell) { ASSERT(cell->inherits(&JSArray::info)); @@ -162,7 +159,7 @@ namespace JSC { inline void MarkStack::markChildren(JSCell* cell) { ASSERT(Heap::isCellMarked(cell)); - if (cell->structure()->typeInfo().hasDefaultMark()) { + if (!cell->structure()->typeInfo().overridesMarkChildren()) { #ifdef NDEBUG asObject(cell)->markChildrenDirect(*this); #else diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSByteArray.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSByteArray.cpp index 0907099..f8ab1e8 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSByteArray.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSByteArray.cpp @@ -35,17 +35,25 @@ namespace JSC { const ClassInfo JSByteArray::s_defaultInfo = { "ByteArray", 0, 0, 0 }; -JSByteArray::JSByteArray(ExecState* exec, PassRefPtr<Structure> structure, ByteArray* storage, const JSC::ClassInfo* classInfo) +JSByteArray::JSByteArray(ExecState* exec, NonNullPassRefPtr<Structure> structure, ByteArray* storage, const JSC::ClassInfo* classInfo) : JSObject(structure) , m_storage(storage) , m_classInfo(classInfo) { putDirect(exec->globalData().propertyNames->length, jsNumber(exec, m_storage->length()), ReadOnly | DontDelete); } - + +#if !ASSERT_DISABLED +JSByteArray::~JSByteArray() +{ + ASSERT(vptr() == JSGlobalData::jsByteArrayVPtr); +} +#endif + + PassRefPtr<Structure> JSByteArray::createStructure(JSValue prototype) { - PassRefPtr<Structure> result = Structure::create(prototype, TypeInfo(ObjectType, HasDefaultMark)); + PassRefPtr<Structure> result = Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); return result; } @@ -96,12 +104,12 @@ void JSByteArray::put(ExecState* exec, unsigned propertyName, JSValue value) setIndex(exec, propertyName, value); } -void JSByteArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, bool includeNonEnumerable) +void JSByteArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { unsigned length = m_storage->length(); for (unsigned i = 0; i < length; ++i) propertyNames.add(Identifier::from(exec, i)); - JSObject::getOwnPropertyNames(exec, propertyNames, includeNonEnumerable); + JSObject::getOwnPropertyNames(exec, propertyNames, mode); } } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSByteArray.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSByteArray.h index 5ea0505..5b7adcf 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSByteArray.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSByteArray.h @@ -33,7 +33,7 @@ namespace JSC { class JSByteArray : public JSObject { - friend struct VPtrSet; + friend class JSGlobalData; public: bool canAccessIndex(unsigned i) { return i < m_storage->length(); } JSValue getIndex(ExecState* exec, unsigned i) @@ -73,7 +73,7 @@ namespace JSC { setIndex(i, byteValue); } - JSByteArray(ExecState* exec, PassRefPtr<Structure>, WTF::ByteArray* storage, const JSC::ClassInfo* = &s_defaultInfo); + JSByteArray(ExecState* exec, NonNullPassRefPtr<Structure>, WTF::ByteArray* storage, const JSC::ClassInfo* = &s_defaultInfo); static PassRefPtr<Structure> createStructure(JSValue prototype); virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&); @@ -82,7 +82,7 @@ namespace JSC { virtual void put(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&); virtual void put(JSC::ExecState*, unsigned propertyName, JSC::JSValue); - virtual void getOwnPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&, bool includeNonEnumerable = false); + virtual void getOwnPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); virtual const ClassInfo* classInfo() const { return m_classInfo; } static const ClassInfo s_defaultInfo; @@ -91,6 +91,13 @@ namespace JSC { WTF::ByteArray* storage() const { return m_storage.get(); } +#if !ASSERT_DISABLED + virtual ~JSByteArray(); +#endif + + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags; + private: enum VPtrStealingHackType { VPtrStealingHack }; JSByteArray(VPtrStealingHackType) diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSCell.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSCell.cpp index 1cfe72d..869fbfc 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSCell.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSCell.cpp @@ -59,10 +59,10 @@ static const union { } doubles; } NaNInf = { { -#if PLATFORM(BIG_ENDIAN) +#if CPU(BIG_ENDIAN) { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 }, { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 } -#elif PLATFORM(MIDDLE_ENDIAN) +#elif CPU(MIDDLE_ENDIAN) { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 }, { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 } #else @@ -76,31 +76,22 @@ extern const double Inf = NaNInf.doubles.Inf_Double; #endif // !(defined NAN && defined INFINITY) -void* JSCell::operator new(size_t size, ExecState* exec) -{ -#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE - return exec->heap()->inlineAllocate(size); -#else - return exec->heap()->allocate(size); -#endif -} - bool JSCell::getUInt32(uint32_t&) const { return false; } -bool JSCell::getString(UString&stringValue) const +bool JSCell::getString(ExecState* exec, UString&stringValue) const { if (!isString()) return false; - stringValue = static_cast<const JSString*>(this)->value(); + stringValue = static_cast<const JSString*>(this)->value(exec); return true; } -UString JSCell::getString() const +UString JSCell::getString(ExecState* exec) const { - return isString() ? static_cast<const JSString*>(this)->value() : UString(); + return isString() ? static_cast<const JSString*>(this)->value(exec) : UString(); } JSObject* JSCell::getObject() @@ -157,14 +148,14 @@ void JSCell::put(ExecState* exec, unsigned identifier, JSValue value) toObject(exec)->put(exec, identifier, value); } -bool JSCell::deleteProperty(ExecState* exec, const Identifier& identifier, bool checkDontDelete) +bool JSCell::deleteProperty(ExecState* exec, const Identifier& identifier) { - return toObject(exec)->deleteProperty(exec, identifier, checkDontDelete); + return toObject(exec)->deleteProperty(exec, identifier); } -bool JSCell::deleteProperty(ExecState* exec, unsigned identifier, bool checkDontDelete) +bool JSCell::deleteProperty(ExecState* exec, unsigned identifier) { - return toObject(exec)->deleteProperty(exec, identifier, checkDontDelete); + return toObject(exec)->deleteProperty(exec, identifier); } JSObject* JSCell::toThisObject(ExecState* exec) const diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSCell.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSCell.h index d015b9c..36bfd66 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSCell.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSCell.h @@ -42,14 +42,19 @@ namespace JSC { friend class JSString; friend class JSValue; friend class JSAPIValueWrapper; - friend struct VPtrSet; + friend class JSZombie; + friend class JSGlobalData; private: explicit JSCell(Structure*); - JSCell(); // Only used for initializing Collector blocks. virtual ~JSCell(); public: + static PassRefPtr<Structure> createDummyStructure() + { + return Structure::create(jsNull(), TypeInfo(UnspecifiedType)); + } + // Querying the type. #if USE(JSVALUE32) bool isNumber() const; @@ -59,12 +64,13 @@ namespace JSC { virtual bool isGetterSetter() const; bool inherits(const ClassInfo*) const; virtual bool isAPIValueWrapper() const { return false; } + virtual bool isPropertyNameIterator() const { return false; } Structure* structure() const; // Extracting the value. - bool getString(UString&) const; - UString getString() const; // null string if not a string + bool getString(ExecState* exec, UString&) const; + UString getString(ExecState* exec) const; // null string if not a string JSObject* getObject(); // NULL if not an object const JSObject* getObject() const; // NULL if not an object @@ -89,19 +95,23 @@ namespace JSC { void* operator new(size_t, void* placementNewDestination) { return placementNewDestination; } virtual void markChildren(MarkStack&); +#if ENABLE(JSC_ZOMBIES) + virtual bool isZombie() const { return false; } +#endif // Object operations, with the toObject operation included. virtual const ClassInfo* classInfo() const; virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); virtual void put(ExecState*, unsigned propertyName, JSValue); - virtual bool deleteProperty(ExecState*, const Identifier& propertyName, bool checkDontDelete = true); - virtual bool deleteProperty(ExecState*, unsigned propertyName, bool checkDontDelete = true); + virtual bool deleteProperty(ExecState*, const Identifier& propertyName); + virtual bool deleteProperty(ExecState*, unsigned propertyName); virtual JSObject* toThisObject(ExecState*) const; virtual UString toThisString(ExecState*) const; virtual JSString* toThisJSString(ExecState*); virtual JSValue getJSNumber(); void* vptr() { return *reinterpret_cast<void**>(this); } + void setVPtr(void* vptr) { *reinterpret_cast<void**>(this) = vptr; } private: // Base implementation; for non-object classes implements getPropertySlot. @@ -112,24 +122,11 @@ namespace JSC { Structure* m_structure; }; - // FIXME: We should deprecate this and just use JSValue::asCell() instead. - JSCell* asCell(JSValue); - - inline JSCell* asCell(JSValue value) - { - return value.asCell(); - } - inline JSCell::JSCell(Structure* structure) : m_structure(structure) { } - // Only used for initializing Collector blocks. - inline JSCell::JSCell() - { - } - inline JSCell::~JSCell() { } @@ -137,7 +134,7 @@ namespace JSC { #if USE(JSVALUE32) inline bool JSCell::isNumber() const { - return Heap::isNumber(const_cast<JSCell*>(this)); + return m_structure->typeInfo().type() == NumberType; } #endif @@ -162,11 +159,12 @@ namespace JSC { inline void* JSCell::operator new(size_t size, JSGlobalData* globalData) { -#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE - return globalData->heap.inlineAllocate(size); -#else return globalData->heap.allocate(size); -#endif + } + + inline void* JSCell::operator new(size_t size, ExecState* exec) + { + return exec->heap()->allocate(size); } // --- JSValue inlines ---------------------------- @@ -186,14 +184,14 @@ namespace JSC { return isCell() && asCell()->isObject(); } - inline bool JSValue::getString(UString& s) const + inline bool JSValue::getString(ExecState* exec, UString& s) const { - return isCell() && asCell()->getString(s); + return isCell() && asCell()->getString(exec, s); } - inline UString JSValue::getString() const + inline UString JSValue::getString(ExecState* exec) const { - return isCell() ? asCell()->getString() : UString(); + return isCell() ? asCell()->getString(exec) : UString(); } inline JSObject* JSValue::getObject() const @@ -342,11 +340,6 @@ namespace JSC { append(value.asCell()); } - inline void Structure::markAggregate(MarkStack& markStack) - { - markStack.append(m_prototype); - } - inline Heap* Heap::heap(JSValue v) { if (!v.isCell()) @@ -358,7 +351,13 @@ namespace JSC { { return cellBlock(c)->heap; } - + +#if ENABLE(JSC_ZOMBIES) + inline bool JSValue::isZombie() const + { + return isCell() && asCell() && asCell()->isZombie(); + } +#endif } // namespace JSC #endif // JSCell_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSFunction.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSFunction.cpp index bf4e34d..d213b4a 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSFunction.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSFunction.cpp @@ -50,13 +50,13 @@ bool JSFunction::isHostFunctionNonInline() const return isHostFunction(); } -JSFunction::JSFunction(PassRefPtr<Structure> structure) +JSFunction::JSFunction(NonNullPassRefPtr<Structure> structure) : Base(structure) , m_executable(adoptRef(new VPtrHackExecutable())) { } -JSFunction::JSFunction(ExecState* exec, PassRefPtr<Structure> structure, int length, const Identifier& name, NativeFunction func) +JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<Structure> structure, int length, const Identifier& name, NativeFunction func) : Base(&exec->globalData(), structure, name) #if ENABLE(JIT) , m_executable(adoptRef(new NativeExecutable(exec))) @@ -72,7 +72,7 @@ JSFunction::JSFunction(ExecState* exec, PassRefPtr<Structure> structure, int len #endif } -JSFunction::JSFunction(ExecState* exec, PassRefPtr<FunctionExecutable> executable, ScopeChainNode* scopeChainNode) +JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<FunctionExecutable> executable, ScopeChainNode* scopeChainNode) : Base(&exec->globalData(), exec->lexicalGlobalObject()->functionStructure(), executable->name()) , m_executable(executable) { @@ -81,6 +81,8 @@ JSFunction::JSFunction(ExecState* exec, PassRefPtr<FunctionExecutable> executabl JSFunction::~JSFunction() { + ASSERT(vptr() == JSGlobalData::jsFunctionVPtr); + // 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). @@ -206,6 +208,17 @@ bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyN return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor); } +void JSFunction::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +{ + if (!isHostFunction() && (mode == IncludeDontEnumProperties)) { + propertyNames.add(exec->propertyNames().arguments); + propertyNames.add(exec->propertyNames().callee); + propertyNames.add(exec->propertyNames().caller); + propertyNames.add(exec->propertyNames().length); + } + Base::getOwnPropertyNames(exec, propertyNames, mode); +} + void JSFunction::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { if (isHostFunction()) { @@ -217,13 +230,13 @@ void JSFunction::put(ExecState* exec, const Identifier& propertyName, JSValue va Base::put(exec, propertyName, value, slot); } -bool JSFunction::deleteProperty(ExecState* exec, const Identifier& propertyName, bool checkDontDelete) +bool JSFunction::deleteProperty(ExecState* exec, const Identifier& propertyName) { if (isHostFunction()) - return Base::deleteProperty(exec, propertyName, checkDontDelete); + return Base::deleteProperty(exec, propertyName); if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length) return false; - return Base::deleteProperty(exec, propertyName, checkDontDelete); + return Base::deleteProperty(exec, propertyName); } // ECMA 13.2.2 [[Construct]] diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSFunction.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSFunction.h index 416a58a..bdb79b8 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSFunction.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSFunction.h @@ -36,13 +36,13 @@ namespace JSC { class JSFunction : public InternalFunction { friend class JIT; - friend struct VPtrSet; + friend class JSGlobalData; typedef InternalFunction Base; public: - JSFunction(ExecState*, PassRefPtr<Structure>, int length, const Identifier&, NativeFunction); - JSFunction(ExecState*, PassRefPtr<FunctionExecutable>, ScopeChainNode*); + JSFunction(ExecState*, NonNullPassRefPtr<Structure>, int length, const Identifier&, NativeFunction); + JSFunction(ExecState*, NonNullPassRefPtr<FunctionExecutable>, ScopeChainNode*); virtual ~JSFunction(); JSObject* construct(ExecState*, const ArgList&); @@ -61,26 +61,30 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, ImplementsHasInstance)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } NativeFunction nativeFunction() { - return *reinterpret_cast<NativeFunction*>(m_data); + return *WTF::bitwise_cast<NativeFunction*>(m_data); } virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); + protected: + const static unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesMarkChildren | OverridesGetPropertyNames | InternalFunction::StructureFlags; + private: - JSFunction(PassRefPtr<Structure>); + JSFunction(NonNullPassRefPtr<Structure>); bool isHostFunctionNonInline() const; virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); + virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); - virtual bool deleteProperty(ExecState*, const Identifier& propertyName, bool checkDontDelete = true); + virtual bool deleteProperty(ExecState*, const Identifier& propertyName); virtual void markChildren(MarkStack&); @@ -94,7 +98,7 @@ namespace JSC { ScopeChain& scopeChain() { ASSERT(!isHostFunctionNonInline()); - return *reinterpret_cast<ScopeChain*>(m_data); + return *WTF::bitwise_cast<ScopeChain*>(m_data); } void clearScopeChain() { @@ -109,11 +113,11 @@ namespace JSC { void setScopeChain(const ScopeChain& sc) { ASSERT(!isHostFunctionNonInline()); - *reinterpret_cast<ScopeChain*>(m_data) = sc; + *WTF::bitwise_cast<ScopeChain*>(m_data) = sc; } void setNativeFunction(NativeFunction func) { - *reinterpret_cast<NativeFunction*>(m_data) = func; + *WTF::bitwise_cast<NativeFunction*>(m_data) = func; } unsigned char m_data[sizeof(void*)]; }; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.cpp index 4496d6c..34b5f82 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.cpp @@ -45,10 +45,10 @@ #include "JSNotAnObject.h" #include "JSPropertyNameIterator.h" #include "JSStaticScopeObject.h" -#include "Parser.h" #include "Lexer.h" #include "Lookup.h" #include "Nodes.h" +#include "Parser.h" #if ENABLE(JSC_MULTIPLE_THREADS) #include <wtf/Threading.h> @@ -71,40 +71,38 @@ extern JSC_CONST_HASHTABLE HashTable regExpTable; extern JSC_CONST_HASHTABLE HashTable regExpConstructorTable; extern JSC_CONST_HASHTABLE HashTable stringTable; -struct VPtrSet { - VPtrSet(); - - void* jsArrayVPtr; - void* jsByteArrayVPtr; - void* jsStringVPtr; - void* jsFunctionVPtr; -}; +void* JSGlobalData::jsArrayVPtr; +void* JSGlobalData::jsByteArrayVPtr; +void* JSGlobalData::jsStringVPtr; +void* JSGlobalData::jsFunctionVPtr; -VPtrSet::VPtrSet() +void JSGlobalData::storeVPtrs() { - // Bizarrely, calling fastMalloc here is faster than allocating space on the stack. - void* storage = fastMalloc(sizeof(CollectorBlock)); + CollectorCell cell; + void* storage = &cell; + COMPILE_ASSERT(sizeof(JSArray) <= sizeof(CollectorCell), sizeof_JSArray_must_be_less_than_CollectorCell); JSCell* jsArray = new (storage) JSArray(JSArray::createStructure(jsNull())); - jsArrayVPtr = jsArray->vptr(); + JSGlobalData::jsArrayVPtr = jsArray->vptr(); jsArray->~JSCell(); + COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(CollectorCell), sizeof_JSByteArray_must_be_less_than_CollectorCell); JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack); - jsByteArrayVPtr = jsByteArray->vptr(); + JSGlobalData::jsByteArrayVPtr = jsByteArray->vptr(); jsByteArray->~JSCell(); + COMPILE_ASSERT(sizeof(JSString) <= sizeof(CollectorCell), sizeof_JSString_must_be_less_than_CollectorCell); JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack); - jsStringVPtr = jsString->vptr(); + JSGlobalData::jsStringVPtr = jsString->vptr(); jsString->~JSCell(); + COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(CollectorCell), sizeof_JSFunction_must_be_less_than_CollectorCell); JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull())); - jsFunctionVPtr = jsFunction->vptr(); + JSGlobalData::jsFunctionVPtr = jsFunction->vptr(); jsFunction->~JSCell(); - - fastFree(storage); } -JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet) +JSGlobalData::JSGlobalData(bool isShared) : isSharedInstance(isShared) , clientData(0) , arrayTable(fastNew<HashTable>(JSC::arrayTable)) @@ -124,13 +122,10 @@ JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet) , propertyNameIteratorStructure(JSPropertyNameIterator::createStructure(jsNull())) , getterSetterStructure(GetterSetter::createStructure(jsNull())) , apiWrapperStructure(JSAPIValueWrapper::createStructure(jsNull())) + , dummyMarkableCellStructure(JSCell::createDummyStructure()) #if USE(JSVALUE32) , numberStructure(JSNumberCell::createStructure(jsNull())) #endif - , jsArrayVPtr(vptrSet.jsArrayVPtr) - , jsByteArrayVPtr(vptrSet.jsByteArrayVPtr) - , jsStringVPtr(vptrSet.jsStringVPtr) - , jsFunctionVPtr(vptrSet.jsFunctionVPtr) , identifierTable(createIdentifierTable()) , propertyNames(new CommonIdentifiers(this)) , emptyList(new MarkedArgumentBuffer) @@ -147,7 +142,9 @@ JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet) , dynamicGlobalObject(0) , functionCodeBlockBeingReparsed(0) , firstStringifierToMark(0) - , markStack(vptrSet.jsArrayVPtr) + , markStack(jsArrayVPtr) + , cachedUTCOffset(NaN) + , weakRandom(static_cast<int>(currentTime())) #ifndef NDEBUG , mainThreadOnly(false) #endif @@ -199,9 +196,17 @@ JSGlobalData::~JSGlobalData() delete clientData; } -PassRefPtr<JSGlobalData> JSGlobalData::create(bool isShared) +PassRefPtr<JSGlobalData> JSGlobalData::createNonDefault() +{ + return adoptRef(new JSGlobalData(false)); +} + +PassRefPtr<JSGlobalData> JSGlobalData::create() { - return adoptRef(new JSGlobalData(isShared, VPtrSet())); + JSGlobalData* globalData = new JSGlobalData(false); + setDefaultIdentifierTable(globalData->identifierTable); + setCurrentIdentifierTable(globalData->identifierTable); + return adoptRef(globalData); } PassRefPtr<JSGlobalData> JSGlobalData::createLeaked() @@ -221,7 +226,7 @@ JSGlobalData& JSGlobalData::sharedInstance() { JSGlobalData*& instance = sharedInstanceInternal(); if (!instance) { - instance = create(true).releaseRef(); + instance = new JSGlobalData(true); #if ENABLE(JSC_MULTIPLE_THREADS) instance->makeUsableFromMultipleThreads(); #endif @@ -253,4 +258,27 @@ JSGlobalData::ClientData::~ClientData() { } +void JSGlobalData::resetDateCache() +{ + cachedUTCOffset = NaN; + dstOffsetCache.reset(); + cachedDateString = UString(); + dateInstanceCache.reset(); +} + +void JSGlobalData::startSampling() +{ + interpreter->startSampling(); +} + +void JSGlobalData::stopSampling() +{ + interpreter->stopSampling(); +} + +void JSGlobalData::dumpSampleData(ExecState* exec) +{ + interpreter->dumpSampleData(exec); +} + } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.h index c9887e8..49a6c4c 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.h @@ -30,6 +30,7 @@ #define JSGlobalData_h #include "Collector.h" +#include "DateInstanceCache.h" #include "ExecutableAllocator.h" #include "JITStubs.h" #include "JSValue.h" @@ -37,6 +38,7 @@ #include "NumericStrings.h" #include "SmallStrings.h" #include "TimeoutChecker.h" +#include "WeakRandom.h" #include <wtf/Forward.h> #include <wtf/HashMap.h> #include <wtf/RefCounted.h> @@ -60,7 +62,26 @@ namespace JSC { struct HashTable; struct Instruction; - struct VPtrSet; + + struct DSTOffsetCache { + DSTOffsetCache() + { + reset(); + } + + void reset() + { + offset = 0.0; + start = 0.0; + end = -1.0; + increment = 0.0; + } + + double offset; + double start; + double end; + double increment; + }; class JSGlobalData : public RefCounted<JSGlobalData> { public: @@ -74,8 +95,9 @@ namespace JSC { static bool sharedInstanceExists(); static JSGlobalData& sharedInstance(); - static PassRefPtr<JSGlobalData> create(bool isShared = false); + static PassRefPtr<JSGlobalData> create(); static PassRefPtr<JSGlobalData> createLeaked(); + static PassRefPtr<JSGlobalData> createNonDefault(); ~JSGlobalData(); #if ENABLE(JSC_MULTIPLE_THREADS) @@ -104,22 +126,25 @@ namespace JSC { RefPtr<Structure> propertyNameIteratorStructure; RefPtr<Structure> getterSetterStructure; RefPtr<Structure> apiWrapperStructure; + RefPtr<Structure> dummyMarkableCellStructure; #if USE(JSVALUE32) RefPtr<Structure> numberStructure; #endif - void* jsArrayVPtr; - void* jsByteArrayVPtr; - void* jsStringVPtr; - void* jsFunctionVPtr; + static void storeVPtrs(); + static JS_EXPORTDATA void* jsArrayVPtr; + static JS_EXPORTDATA void* jsByteArrayVPtr; + static JS_EXPORTDATA void* jsStringVPtr; + static JS_EXPORTDATA void* jsFunctionVPtr; IdentifierTable* identifierTable; CommonIdentifiers* propertyNames; const MarkedArgumentBuffer* emptyList; // Lists are supposed to be allocated on the stack to have their elements properly marked, which is not the case here - but this list has nothing to mark. SmallStrings smallStrings; NumericStrings numericStrings; - + DateInstanceCache dateInstanceCache; + #if ENABLE(ASSEMBLER) ExecutableAllocator executableAllocator; #endif @@ -154,16 +179,29 @@ namespace JSC { MarkStack markStack; + double cachedUTCOffset; + DSTOffsetCache dstOffsetCache; + + UString cachedDateString; + double cachedDateStringValue; + + WeakRandom weakRandom; + #ifndef NDEBUG bool mainThreadOnly; #endif + void resetDateCache(); + + void startSampling(); + void stopSampling(); + void dumpSampleData(ExecState* exec); private: - JSGlobalData(bool isShared, const VPtrSet&); + JSGlobalData(bool isShared); static JSGlobalData*& sharedInstanceInternal(); void createNativeThunk(); }; - + } // namespace JSC #endif // JSGlobalData_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObject.cpp index 60eb1b4..a2e9928 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -89,7 +89,7 @@ static inline void markIfNeeded(MarkStack& markStack, JSValue v) static inline void markIfNeeded(MarkStack& markStack, const RefPtr<Structure>& s) { if (s) - s->markAggregate(markStack); + markIfNeeded(markStack, s->storedPrototype()); } JSGlobalObject::~JSGlobalObject() @@ -121,15 +121,17 @@ JSGlobalObject::~JSGlobalObject() registerFile.setGlobalObject(0); registerFile.setNumGlobals(0); } - delete d(); + d()->destructor(d()); } void JSGlobalObject::init(JSObject* thisValue) { ASSERT(JSLock::currentThreadIsHoldingLock()); + structure()->disableSpecificFunctionTracking(); + d()->globalData = Heap::heap(this)->globalData(); - d()->globalScopeChain = ScopeChain(this, d()->globalData.get(), thisValue); + d()->globalScopeChain = ScopeChain(this, d()->globalData.get(), this, thisValue); JSGlobalObject::globalExec()->init(0, 0, d()->globalScopeChain.node(), CallFrame::noCaller(), 0, 0, 0); @@ -396,6 +398,21 @@ void JSGlobalObject::markChildren(MarkStack& markStack) markIfNeeded(markStack, d()->methodCallDummy); markIfNeeded(markStack, d()->errorStructure); + markIfNeeded(markStack, d()->argumentsStructure); + markIfNeeded(markStack, d()->arrayStructure); + markIfNeeded(markStack, d()->booleanObjectStructure); + markIfNeeded(markStack, d()->callbackConstructorStructure); + markIfNeeded(markStack, d()->callbackFunctionStructure); + markIfNeeded(markStack, d()->callbackObjectStructure); + markIfNeeded(markStack, d()->dateStructure); + markIfNeeded(markStack, d()->emptyObjectStructure); + markIfNeeded(markStack, d()->errorStructure); + markIfNeeded(markStack, d()->functionStructure); + markIfNeeded(markStack, d()->numberObjectStructure); + markIfNeeded(markStack, d()->prototypeFunctionStructure); + markIfNeeded(markStack, d()->regExpMatchesArrayStructure); + markIfNeeded(markStack, d()->regExpStructure); + markIfNeeded(markStack, d()->stringObjectStructure); // No need to mark the other structures, because their prototypes are all // guaranteed to be referenced elsewhere. @@ -450,11 +467,12 @@ void JSGlobalObject::copyGlobalsTo(RegisterFile& registerFile) void* JSGlobalObject::operator new(size_t size, JSGlobalData* globalData) { -#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE - return globalData->heap.inlineAllocate(size); -#else return globalData->heap.allocate(size); -#endif +} + +void JSGlobalObject::destroyJSGlobalObjectData(void* jsGlobalObjectData) +{ + delete static_cast<JSGlobalObjectData*>(jsGlobalObjectData); } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObject.h index 7459c2e..340e04d 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObject.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObject.h @@ -22,6 +22,7 @@ #ifndef JSGlobalObject_h #define JSGlobalObject_h +#include "JSArray.h" #include "JSGlobalData.h" #include "JSVariableObject.h" #include "NativeFunctionWrapper.h" @@ -52,14 +53,22 @@ namespace JSC { struct HashTable; typedef Vector<ExecState*, 16> ExecStateStack; - + class JSGlobalObject : public JSVariableObject { protected: using JSVariableObject::JSVariableObjectData; struct JSGlobalObjectData : public JSVariableObjectData { - JSGlobalObjectData() + // We use an explicit destructor function pointer instead of a + // virtual destructor because we want to avoid adding a vtable + // pointer to this struct. Adding a vtable pointer would force the + // compiler to emit costly pointer fixup code when casting from + // JSVariableObjectData* to JSGlobalObjectData*. + typedef void (*Destructor)(void*); + + JSGlobalObjectData(Destructor destructor) : JSVariableObjectData(&symbolTable, 0) + , destructor(destructor) , registerArraySize(0) , globalScopeChain(NoScopeChain()) , regExpConstructor(0) @@ -85,10 +94,8 @@ namespace JSC { { } - virtual ~JSGlobalObjectData() - { - } - + Destructor destructor; + size_t registerArraySize; JSGlobalObject* next; @@ -153,13 +160,13 @@ namespace JSC { void* operator new(size_t, JSGlobalData*); explicit JSGlobalObject() - : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData) + : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData(destroyJSGlobalObjectData)) { init(this); } protected: - JSGlobalObject(PassRefPtr<Structure> structure, JSGlobalObjectData* data, JSObject* thisValue) + JSGlobalObject(NonNullPassRefPtr<Structure> structure, JSGlobalObjectData* data, JSObject* thisValue) : JSVariableObject(structure, data) { init(thisValue); @@ -229,10 +236,7 @@ namespace JSC { unsigned profileGroup() const { return d()->profileGroup; } Debugger* debugger() const { return d()->debugger; } - void setDebugger(Debugger* debugger) - { - d()->debugger = debugger; - } + void setDebugger(Debugger* debugger) { d()->debugger = debugger; } virtual bool supportsProfiling() const { return false; } @@ -264,10 +268,13 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } protected: + + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags; + struct GlobalPropertyInfo { GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a) : identifier(i) @@ -283,6 +290,8 @@ namespace JSC { void addStaticGlobals(GlobalPropertyInfo*, int count); private: + static void destroyJSGlobalObjectData(void*); + // FIXME: Fold reset into init. void init(JSObject* thisValue); void reset(JSValue prototype); @@ -347,14 +356,6 @@ namespace JSC { return symbolTableGet(propertyName, slot, slotIsWriteable); } - inline JSGlobalObject* ScopeChainNode::globalObject() const - { - const ScopeChainNode* n = this; - while (n->next) - n = n->next; - return asGlobalObject(n->object); - } - inline JSValue Structure::prototypeForLookup(ExecState* exec) const { if (typeInfo().type() == ObjectType) @@ -409,13 +410,46 @@ namespace JSC { return globalData().dynamicGlobalObject; } + inline JSObject* constructEmptyObject(ExecState* exec) + { + return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure()); + } + + inline JSArray* constructEmptyArray(ExecState* exec) + { + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure()); + } + + inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength) + { + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength); + } + + inline JSArray* constructArray(ExecState* exec, JSValue singleItemValue) + { + MarkedArgumentBuffer values; + values.append(singleItemValue); + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values); + } + + inline JSArray* constructArray(ExecState* exec, const ArgList& values) + { + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values); + } + class DynamicGlobalObjectScope : public Noncopyable { public: DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject) : m_dynamicGlobalObjectSlot(callFrame->globalData().dynamicGlobalObject) , m_savedDynamicGlobalObject(m_dynamicGlobalObjectSlot) { - m_dynamicGlobalObjectSlot = dynamicGlobalObject; + if (!m_dynamicGlobalObjectSlot) { + m_dynamicGlobalObjectSlot = dynamicGlobalObject; + + // Reset the date cache between JS invocations to force the VM + // to observe time zone changes. + callFrame->globalData().resetDateCache(); + } } ~DynamicGlobalObjectScope() diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp index 5ded370..0bc1274 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp @@ -27,14 +27,16 @@ #include "CallFrame.h" #include "GlobalEvalFunction.h" +#include "Interpreter.h" #include "JSGlobalObject.h" -#include "LiteralParser.h" #include "JSString.h" -#include "Interpreter.h" -#include "Parser.h" -#include "dtoa.h" #include "Lexer.h" +#include "LiteralParser.h" #include "Nodes.h" +#include "Parser.h" +#include "StringBuilder.h" +#include "StringExtras.h" +#include "dtoa.h" #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -55,24 +57,24 @@ static JSValue encode(ExecState* exec, const ArgList& args, const char* doNotEsc if (!cstr.c_str()) return throwError(exec, URIError, "String contained an illegal UTF-16 sequence."); - UString result = ""; + StringBuilder builder; const char* p = cstr.c_str(); for (size_t k = 0; k < cstr.size(); k++, p++) { char c = *p; if (c && strchr(doNotEscape, c)) - result.append(c); + builder.append(c); else { char tmp[4]; - sprintf(tmp, "%%%02X", static_cast<unsigned char>(c)); - result += tmp; + snprintf(tmp, 4, "%%%02X", static_cast<unsigned char>(c)); + builder.append((const char*)tmp); } } - return jsString(exec, result); + return jsString(exec, builder.release()); } static JSValue decode(ExecState* exec, const ArgList& args, const char* doNotUnescape, bool strict) { - UString result = ""; + StringBuilder builder; UString str = args.at(0).toString(exec); int k = 0; int len = str.size(); @@ -106,7 +108,7 @@ static JSValue decode(ExecState* exec, const ArgList& args, const char* doNotUne charLen = 0; else if (character >= 0x10000) { // Convert to surrogate pair. - result.append(static_cast<UChar>(0xD800 | ((character - 0x10000) >> 10))); + builder.append(static_cast<UChar>(0xD800 | ((character - 0x10000) >> 10))); u = static_cast<UChar>(0xDC00 | ((character - 0x10000) & 0x3FF)); } else u = static_cast<UChar>(character); @@ -131,9 +133,9 @@ static JSValue decode(ExecState* exec, const ArgList& args, const char* doNotUne } } k++; - result.append(c); + builder.append(c); } - return jsString(exec, result); + return jsString(exec, builder.release()); } bool isStrWhiteSpace(UChar c) @@ -286,12 +288,12 @@ JSValue JSC_HOST_CALL globalFuncEval(ExecState* exec, JSObject* function, JSValu if (JSValue parsedObject = preparser.tryLiteralParse()) return parsedObject; - EvalExecutable eval(exec, makeSource(s)); - JSObject* error = eval.compile(exec, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain().node()); + RefPtr<EvalExecutable> eval = EvalExecutable::create(exec, makeSource(s)); + JSObject* error = eval->compile(exec, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain().node()); if (error) return throwError(exec, error); - return exec->interpreter()->execute(&eval, exec, thisObject, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain().node(), exec->exceptionSlot()); + return exec->interpreter()->execute(eval.get(), exec, thisObject, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain().node(), exec->exceptionSlot()); } JSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec, JSObject*, JSValue, const ArgList& args) @@ -376,7 +378,7 @@ JSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec, JSObject*, JSValue, cons "0123456789" "*+-./@_"; - UString result = ""; + StringBuilder builder; UString s; UString str = args.at(0).toString(exec); const UChar* c = str.data(); @@ -393,15 +395,15 @@ JSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec, JSObject*, JSValue, cons sprintf(tmp, "%%%02X", u); s = UString(tmp); } - result += s; + builder.append(s); } - return jsString(exec, result); + return jsString(exec, builder.release()); } JSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - UString result = ""; + StringBuilder builder; UString str = args.at(0).toString(exec); int k = 0; int len = str.size(); @@ -420,10 +422,10 @@ JSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec, JSObject*, JSValue, co k += 2; } k++; - result.append(*c); + builder.append(*c); } - return jsString(exec, result); + return jsString(exec, builder.release()); } #ifndef NDEBUG diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNotAnObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNotAnObject.cpp index 321762a..f4764e2 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNotAnObject.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNotAnObject.cpp @@ -121,7 +121,7 @@ bool JSNotAnObject::deleteProperty(ExecState* exec, unsigned) return false; } -void JSNotAnObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray&, bool) +void JSNotAnObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray&, EnumerationMode) { ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNotAnObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNotAnObject.h index 57347af..d5f430c 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNotAnObject.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNotAnObject.h @@ -62,10 +62,13 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } private: + + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags; + // JSValue methods virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue&); @@ -88,7 +91,7 @@ namespace JSC { virtual bool deleteProperty(ExecState*, const Identifier& propertyName); virtual bool deleteProperty(ExecState*, unsigned propertyName); - virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, bool includeNonEnumerable = false); + virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); JSNotAnObjectErrorStub* m_exception; }; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNumberCell.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNumberCell.h index 6a48081..e9e2470 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNumberCell.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSNumberCell.h @@ -68,23 +68,15 @@ namespace JSC { void* operator new(size_t size, ExecState* exec) { - #ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE - return exec->heap()->inlineAllocateNumber(size); - #else return exec->heap()->allocateNumber(size); - #endif } void* operator new(size_t size, JSGlobalData* globalData) { - #ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE - return globalData->heap.inlineAllocateNumber(size); - #else return globalData->heap.allocateNumber(size); - #endif } - static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(NumberType, NeedsThisConversion | HasDefaultMark)); } + static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(NumberType, OverridesGetOwnPropertySlot | NeedsThisConversion)); } private: JSNumberCell(JSGlobalData* globalData, double value) @@ -117,6 +109,11 @@ namespace JSC { return static_cast<JSNumberCell*>(v.asCell()); } + ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, ExecState* exec, double d) + { + *this = jsNumberCell(exec, d); + } + inline JSValue::JSValue(ExecState* exec, double d) { JSValue v = JSImmediate::from(d); @@ -201,6 +198,11 @@ namespace JSC { #endif // USE(JSVALUE32) #if USE(JSVALUE64) + ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, ExecState*, double d) + { + *this = JSImmediate::fromNumberOutsideIntegerRange(d); + } + inline JSValue::JSValue(ExecState*, double d) { JSValue v = JSImmediate::from(d); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSONObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSONObject.cpp index 377c9d1..b089584 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSONObject.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSONObject.cpp @@ -32,6 +32,7 @@ #include "JSArray.h" #include "LiteralParser.h" #include "PropertyNameArray.h" +#include "StringBuilder.h" #include <wtf/MathExtras.h> namespace JSC { @@ -70,8 +71,6 @@ public: void markAggregate(MarkStack&); private: - typedef UString StringBuilder; - class Holder { public: Holder(JSObject*); @@ -156,7 +155,7 @@ static inline UString gap(ExecState* exec, JSValue space) } // If the space value is a string, use it as the gap string, otherwise use no gap string. - UString spaces = space.getString(); + UString spaces = space.getString(exec); if (spaces.size() > maxGapLength) { spaces = spaces.substr(0, maxGapLength); } @@ -213,7 +212,7 @@ Stringifier::Stringifier(ExecState* exec, JSValue replacer, JSValue space) break; UString propertyName; - if (name.getString(propertyName)) { + if (name.getString(exec, propertyName)) { m_arrayReplacerPropertyNames.add(Identifier(exec, propertyName)); continue; } @@ -269,7 +268,7 @@ JSValue Stringifier::stringify(JSValue value) if (m_exec->hadException()) return jsNull(); - return jsString(m_exec, result); + return jsString(m_exec, result.release()); } void Stringifier::appendQuotedString(StringBuilder& builder, const UString& value) @@ -389,7 +388,7 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& } UString stringValue; - if (value.getString(stringValue)) { + if (value.getString(m_exec, stringValue)) { appendQuotedString(builder, stringValue); return StringifySucceeded; } @@ -461,7 +460,7 @@ 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); + m_repeatedGap = makeString(m_repeatedGap, m_gap); ASSERT(newSize <= m_repeatedGap.size()); m_indent = m_repeatedGap.substr(0, newSize); } @@ -504,7 +503,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui m_propertyNames = stringifier.m_arrayReplacerPropertyNames.data(); else { PropertyNameArray objectPropertyNames(exec); - m_object->getPropertyNames(exec, objectPropertyNames); + m_object->getOwnPropertyNames(exec, objectPropertyNames); m_propertyNames = objectPropertyNames.releaseData(); } m_size = m_propertyNames->propertyNameVector().size(); @@ -588,7 +587,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui // 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); + builder.resize(rollBackPoint); break; } @@ -750,7 +749,7 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) objectStack.append(object); indexStack.append(0); propertyStack.append(PropertyNameArray(m_exec)); - object->getPropertyNames(m_exec, propertyStack.last()); + object->getOwnPropertyNames(m_exec, propertyStack.last()); // fallthrough } objectStartVisitMember: diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSONObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSONObject.h index 0705a69..ec3fa40 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSONObject.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSONObject.h @@ -34,18 +34,21 @@ namespace JSC { class JSONObject : public JSObject { public: - JSONObject(PassRefPtr<Structure> structure) + JSONObject(NonNullPassRefPtr<Structure> structure) : JSObject(structure) { } static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, HasDefaultMark | HasDefaultGetPropertyNames)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } static void markStringifiers(MarkStack&, Stringifier*); + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags; + private: virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp index 01f74ac..0e3475f 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp @@ -42,6 +42,25 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(JSObject); +static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode) +{ + // Add properties from the static hashtables of properties + for (; classInfo; classInfo = classInfo->parentClass) { + const HashTable* table = classInfo->propHashTable(exec); + if (!table) + continue; + table->initializeIfNeeded(exec); + ASSERT(table->table); + + int hashSizeMask = table->compactSize - 1; + const HashEntry* entry = table->table; + for (int i = 0; i <= hashSizeMask; ++i, ++entry) { + if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties))) + propertyNames.add(entry->key()); + } + } +} + void JSObject::markChildren(MarkStack& markStack) { #ifndef NDEBUG @@ -187,12 +206,12 @@ bool JSObject::hasProperty(ExecState* exec, unsigned propertyName) const } // ECMA 8.6.2.5 -bool JSObject::deleteProperty(ExecState* exec, const Identifier& propertyName, bool checkDontDelete) +bool JSObject::deleteProperty(ExecState* exec, const Identifier& propertyName) { unsigned attributes; JSCell* specificValue; if (m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) { - if ((attributes & DontDelete) && checkDontDelete) + if ((attributes & DontDelete)) return false; removeDirect(propertyName); return true; @@ -200,7 +219,7 @@ bool JSObject::deleteProperty(ExecState* exec, const Identifier& propertyName, b // Look in the static hashtable of properties const HashEntry* entry = findPropertyHashEntry(exec, propertyName); - if (entry && (entry->attributes() & DontDelete) && checkDontDelete) + if (entry && entry->attributes() & DontDelete) return false; // this builtin property can't be deleted // FIXME: Should the code here actually do some deletion? @@ -213,9 +232,9 @@ bool JSObject::hasOwnProperty(ExecState* exec, const Identifier& propertyName) c return const_cast<JSObject*>(this)->getOwnPropertySlot(exec, propertyName, slot); } -bool JSObject::deleteProperty(ExecState* exec, unsigned propertyName, bool checkDontDelete) +bool JSObject::deleteProperty(ExecState* exec, unsigned propertyName) { - return deleteProperty(exec, Identifier::from(exec, propertyName), checkDontDelete); + return deleteProperty(exec, Identifier::from(exec, propertyName)); } static ALWAYS_INLINE JSValue callDefaultValueFunction(ExecState* exec, const JSObject* object, const Identifier& propertyName) @@ -395,26 +414,10 @@ bool JSObject::hasInstance(ExecState* exec, JSValue value, JSValue proto) bool JSObject::propertyIsEnumerable(ExecState* exec, const Identifier& propertyName) const { - unsigned attributes; - if (!getPropertyAttributes(exec, propertyName, attributes)) + PropertyDescriptor descriptor; + if (!const_cast<JSObject*>(this)->getOwnPropertyDescriptor(exec, propertyName, descriptor)) return false; - return !(attributes & DontEnum); -} - -bool JSObject::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const -{ - JSCell* specificValue; - if (m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) - return true; - - // Look in the static hashtable of properties - const HashEntry* entry = findPropertyHashEntry(exec, propertyName); - if (entry) { - attributes = entry->attributes(); - return true; - } - - return false; + return descriptor.enumerable(); } bool JSObject::getPropertySpecificValue(ExecState*, const Identifier& propertyName, JSCell*& specificValue) const @@ -430,14 +433,31 @@ bool JSObject::getPropertySpecificValue(ExecState*, const Identifier& propertyNa return false; } -void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { - m_structure->getEnumerablePropertyNames(exec, propertyNames, this); + getOwnPropertyNames(exec, propertyNames, mode); + + if (prototype().isNull()) + return; + + JSObject* prototype = asObject(this->prototype()); + while(1) { + if (prototype->structure()->typeInfo().overridesGetPropertyNames()) { + prototype->getPropertyNames(exec, propertyNames, mode); + break; + } + prototype->getOwnPropertyNames(exec, propertyNames, mode); + JSValue nextProto = prototype->prototype(); + if (nextProto.isNull()) + break; + prototype = asObject(nextProto); + } } -void JSObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, bool includeNonEnumerable) +void JSObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { - m_structure->getOwnPropertyNames(exec, propertyNames, this, includeNonEnumerable); + m_structure->getPropertyNames(propertyNames, mode); + getClassPropertyNames(exec, classInfo(), propertyNames, mode); } bool JSObject::toBoolean(ExecState*) const @@ -494,12 +514,12 @@ void JSObject::removeDirect(const Identifier& propertyName) void JSObject::putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr) { - putDirectFunction(Identifier(exec, function->name(&exec->globalData())), function, attr); + putDirectFunction(Identifier(exec, function->name(exec)), function, attr); } void JSObject::putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr) { - putDirectFunctionWithoutTransition(Identifier(exec, function->name(&exec->globalData())), function, attr); + putDirectFunctionWithoutTransition(Identifier(exec, function->name(exec)), function, attr); } NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue* location) @@ -514,7 +534,7 @@ Structure* JSObject::createInheritorID() { #ifdef QT_BUILD_SCRIPT_LIB // ### QtScript needs the hasOwnProperty() calls etc. for QScriptObject - m_inheritorID = Structure::create(this, TypeInfo(ObjectType, ImplementsHasInstance)); + m_inheritorID = Structure::create(this, TypeInfo(ObjectType, ImplementsHasInstance | JSC::OverridesHasInstance | JSC::OverridesGetOwnPropertySlot | JSC::OverridesMarkChildren | JSC::OverridesGetPropertyNames)); #else m_inheritorID = JSObject::createStructure(this); #endif @@ -526,11 +546,6 @@ void JSObject::allocatePropertyStorage(size_t oldSize, size_t newSize) allocatePropertyStorageInline(oldSize, newSize); } -JSObject* constructEmptyObject(ExecState* exec) -{ - return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure()); -} - bool JSObject::getOwnPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor& descriptor) { unsigned attributes = 0; @@ -581,7 +596,7 @@ bool JSObject::defineOwnProperty(ExecState* exec, const Identifier& propertyName if (descriptor.isEmpty()) return true; - if (current.equalTo(descriptor)) + if (current.equalTo(exec, descriptor)) return true; // Filter out invalid changes @@ -627,7 +642,7 @@ bool JSObject::defineOwnProperty(ExecState* exec, const Identifier& propertyName return false; } if (!current.writable()) { - if (descriptor.value() || !JSValue::strictEqual(current.value(), descriptor.value())) { + if (descriptor.value() || !JSValue::strictEqual(exec, current.value(), descriptor.value())) { if (throwException) throwError(exec, TypeError, "Attempting to change value of a readonly property."); return false; @@ -649,12 +664,12 @@ bool JSObject::defineOwnProperty(ExecState* exec, const Identifier& propertyName // Changing the accessor functions of an existing accessor property ASSERT(descriptor.isAccessorDescriptor()); if (!current.configurable()) { - if (descriptor.setterPresent() && !(current.setter() && JSValue::strictEqual(current.setter(), descriptor.setter()))) { + if (descriptor.setterPresent() && !(current.setter() && JSValue::strictEqual(exec, current.setter(), descriptor.setter()))) { if (throwException) throwError(exec, TypeError, "Attempting to change the setter of an unconfigurable property."); return false; } - if (descriptor.getterPresent() && !(current.getter() && JSValue::strictEqual(current.getter(), descriptor.getter()))) { + if (descriptor.getterPresent() && !(current.getter() && JSValue::strictEqual(exec, current.getter(), descriptor.getter()))) { if (throwException) throwError(exec, TypeError, "Attempting to change the getter of an unconfigurable property."); return false; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.h index 9eb4e3e..21dbfe9 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.h @@ -74,7 +74,7 @@ namespace JSC { friend class JSCell; public: - explicit JSObject(PassRefPtr<Structure>); + explicit JSObject(NonNullPassRefPtr<Structure>); virtual void markChildren(MarkStack&); ALWAYS_INLINE void markChildrenDirect(MarkStack& markStack); @@ -86,7 +86,7 @@ namespace JSC { JSValue prototype() const; void setPrototype(JSValue prototype); - void setStructure(PassRefPtr<Structure>); + void setStructure(NonNullPassRefPtr<Structure>); Structure* inheritorID(); virtual UString className() const; @@ -115,15 +115,15 @@ namespace JSC { bool hasProperty(ExecState*, unsigned propertyName) const; bool hasOwnProperty(ExecState*, const Identifier& propertyName) const; - virtual bool deleteProperty(ExecState*, const Identifier& propertyName, bool checkDontDelete = true); - virtual bool deleteProperty(ExecState*, unsigned propertyName, bool checkDontDelete = true); + virtual bool deleteProperty(ExecState*, const Identifier& propertyName); + virtual bool deleteProperty(ExecState*, unsigned propertyName); virtual JSValue defaultValue(ExecState*, PreferredPrimitiveType) const; virtual bool hasInstance(ExecState*, JSValue, JSValue prototypeProperty); - virtual void getPropertyNames(ExecState*, PropertyNameArray&); - virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, bool includeNonEnumerable = false); + virtual void getPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); + virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const; virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value); @@ -135,7 +135,6 @@ namespace JSC { virtual JSObject* toThisObject(ExecState*) const; virtual JSObject* unwrappedObject(); - virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const; bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const; // This get function only looks at the property map. @@ -197,7 +196,6 @@ namespace JSC { virtual bool isActivationObject() const { return false; } virtual bool isWatchdogException() const { return false; } virtual bool isNotAnObjectErrorStub() const { return false; } - #ifdef QT_BUILD_SCRIPT_LIB virtual bool compareToObject(ExecState*, JSObject *other) { return other == this; } #endif @@ -206,15 +204,22 @@ namespace JSC { void allocatePropertyStorageInline(size_t oldSize, size_t newSize); bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); } - static const size_t inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3; - static const size_t nonInlineBaseStorageCapacity = 16; + static const unsigned inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3; + static const unsigned nonInlineBaseStorageCapacity = 16; static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot | HasDefaultMark | HasDefaultGetPropertyNames)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); + } + + void flattenDictionaryObject() + { + m_structure->flattenDictionaryStructure(this); } protected: + static const unsigned StructureFlags = 0; + void addAnonymousSlots(unsigned count); void putAnonymousValue(unsigned index, JSValue value) { @@ -231,7 +236,7 @@ namespace JSC { using JSCell::isGetterSetter; using JSCell::toObject; void getObject(); - void getString(); + void getString(ExecState* exec); void isObject(); void isString(); #if USE(JSVALUE32) @@ -268,8 +273,6 @@ namespace JSC { RefPtr<Structure> m_inheritorID; }; -JSObject* constructEmptyObject(ExecState*); - inline JSObject* asObject(JSCell* cell) { ASSERT(cell->isObject()); @@ -281,10 +284,9 @@ inline JSObject* asObject(JSValue value) return asObject(value.asCell()); } -inline JSObject::JSObject(PassRefPtr<Structure> structure) +inline JSObject::JSObject(NonNullPassRefPtr<Structure> structure) : JSCell(structure.releaseRef()) // ~JSObject balances this ref() { - ASSERT(m_structure); ASSERT(m_structure->propertyStorageCapacity() == inlineStorageCapacity); ASSERT(m_structure->isEmpty()); ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype())); @@ -313,7 +315,7 @@ inline void JSObject::setPrototype(JSValue prototype) setStructure(newStructure.release()); } -inline void JSObject::setStructure(PassRefPtr<Structure> structure) +inline void JSObject::setStructure(NonNullPassRefPtr<Structure> structure) { m_structure->deref(); m_structure = structure.releaseRef(); // ~JSObject balances this ref() @@ -375,14 +377,14 @@ ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifie ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { - if (structure()->typeInfo().hasStandardGetOwnPropertySlot()) + if (!structure()->typeInfo().overridesGetOwnPropertySlot()) return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot); return getOwnPropertySlot(exec, propertyName, slot); } // It may seem crazy to inline a function this large but it makes a big difference // since this is function very hot in variable lookup -inline bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { JSObject* object = this; while (true) { @@ -395,7 +397,7 @@ inline bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propert } } -inline bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) +ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) { JSObject* object = this; while (true) { @@ -689,7 +691,7 @@ ALWAYS_INLINE void JSObject::markChildrenDirect(MarkStack& markStack) { JSCell::markChildren(markStack); - m_structure->markAggregate(markStack); + markStack.append(prototype()); PropertyStorage storage = propertyStorage(); size_t storageSize = m_structure->propertyStorageSize(); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSPropertyNameIterator.cpp index e08a3d9..d3dcb83 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSPropertyNameIterator.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSPropertyNameIterator.cpp @@ -29,26 +29,62 @@ #include "config.h" #include "JSPropertyNameIterator.h" +#include "JSGlobalObject.h" + namespace JSC { ASSERT_CLASS_FITS_IN_CELL(JSPropertyNameIterator); -JSPropertyNameIterator::~JSPropertyNameIterator() +JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject* o) { + ASSERT(!o->structure()->enumerationCache() || + o->structure()->enumerationCache()->cachedStructure() != o->structure() || + o->structure()->enumerationCache()->cachedPrototypeChain() != o->structure()->prototypeChain(exec)); + + PropertyNameArray propertyNames(exec); + o->getPropertyNames(exec, propertyNames); + size_t numCacheableSlots = 0; + if (!o->structure()->hasNonEnumerableProperties() && !o->structure()->hasAnonymousSlots() && + !o->structure()->hasGetterSetterProperties() && !o->structure()->isUncacheableDictionary() && + !o->structure()->typeInfo().overridesGetPropertyNames()) + numCacheableSlots = o->structure()->propertyStorageSize(); + + JSPropertyNameIterator* jsPropertyNameIterator = new (exec) JSPropertyNameIterator(exec, propertyNames.data(), numCacheableSlots); + + if (o->structure()->isDictionary()) + return jsPropertyNameIterator; + + if (o->structure()->typeInfo().overridesGetPropertyNames()) + return jsPropertyNameIterator; + + size_t count = normalizePrototypeChain(exec, o); + StructureChain* structureChain = o->structure()->prototypeChain(exec); + RefPtr<Structure>* structure = structureChain->head(); + for (size_t i = 0; i < count; ++i) { + if (structure[i]->typeInfo().overridesGetPropertyNames()) + return jsPropertyNameIterator; + } + + jsPropertyNameIterator->setCachedPrototypeChain(structureChain); + jsPropertyNameIterator->setCachedStructure(o->structure()); + o->structure()->setEnumerationCache(jsPropertyNameIterator); + return jsPropertyNameIterator; } -void JSPropertyNameIterator::markChildren(MarkStack& markStack) +JSValue JSPropertyNameIterator::get(ExecState* exec, JSObject* base, size_t i) { - JSCell::markChildren(markStack); - if (m_object) - markStack.append(m_object); + JSValue& identifier = m_jsStrings[i]; + if (m_cachedStructure == base->structure() && m_cachedPrototypeChain == base->structure()->prototypeChain(exec)) + return identifier; + + if (!base->hasProperty(exec, Identifier(exec, asString(identifier)->value(exec)))) + return JSValue(); + return identifier; } -void JSPropertyNameIterator::invalidate() +void JSPropertyNameIterator::markChildren(MarkStack& markStack) { - ASSERT(m_position == m_end); - m_object = 0; - m_data.clear(); + markStack.appendValues(m_jsStrings.get(), m_jsStringsSize, MayContainNullValues); } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSPropertyNameIterator.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSPropertyNameIterator.h index d2849a8..f5c64bb 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSPropertyNameIterator.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSPropertyNameIterator.h @@ -31,7 +31,9 @@ #include "JSObject.h" #include "JSString.h" +#include "Operations.h" #include "PropertyNameArray.h" +#include "StructureChain.h" namespace JSC { @@ -39,73 +41,63 @@ namespace JSC { class JSObject; class JSPropertyNameIterator : public JSCell { + friend class JIT; + public: - static JSPropertyNameIterator* create(ExecState*, JSValue); + static JSPropertyNameIterator* create(ExecState*, JSObject*); + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren)); + } - virtual ~JSPropertyNameIterator(); + virtual bool isPropertyNameIterator() const { return true; } virtual void markChildren(MarkStack&); - JSValue next(ExecState*); - void invalidate(); - - static PassRefPtr<Structure> createStructure(JSValue prototype) + bool getOffset(size_t i, int& offset) { - return Structure::create(prototype, TypeInfo(CompoundType)); + if (i >= m_numCacheableSlots) + return false; + offset = i; + return true; } + + JSValue get(ExecState*, JSObject*, size_t i); + size_t size() { return m_jsStringsSize; } + + void setCachedStructure(Structure* structure) { m_cachedStructure = structure; } + Structure* cachedStructure() { return m_cachedStructure; } + + void setCachedPrototypeChain(NonNullPassRefPtr<StructureChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; } + StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); } + private: - JSPropertyNameIterator(ExecState*); - JSPropertyNameIterator(ExecState*, JSObject*, PassRefPtr<PropertyNameArrayData> propertyNameArrayData); + JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlot); - JSObject* m_object; - RefPtr<PropertyNameArrayData> m_data; - PropertyNameArrayData::const_iterator m_position; - PropertyNameArrayData::const_iterator m_end; + Structure* m_cachedStructure; + RefPtr<StructureChain> m_cachedPrototypeChain; + uint32_t m_numCacheableSlots; + uint32_t m_jsStringsSize; + OwnArrayPtr<JSValue> m_jsStrings; }; -inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec) +inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlots) : JSCell(exec->globalData().propertyNameIteratorStructure.get()) - , m_object(0) - , m_position(0) - , m_end(0) + , m_cachedStructure(0) + , m_numCacheableSlots(numCacheableSlots) + , m_jsStringsSize(propertyNameArrayData->propertyNameVector().size()) + , m_jsStrings(new JSValue[m_jsStringsSize]) { + PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector(); + for (size_t i = 0; i < m_jsStringsSize; ++i) + m_jsStrings[i] = jsOwnedString(exec, propertyNameVector[i].ustring()); } -inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, JSObject* object, PassRefPtr<PropertyNameArrayData> propertyNameArrayData) - : JSCell(exec->globalData().propertyNameIteratorStructure.get()) - , m_object(object) - , m_data(propertyNameArrayData) - , m_position(m_data->begin()) - , m_end(m_data->end()) -{ -} - -inline JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSValue v) +inline void Structure::setEnumerationCache(JSPropertyNameIterator* enumerationCache) { - if (v.isUndefinedOrNull()) - return new (exec) JSPropertyNameIterator(exec); - - JSObject* o = v.toObject(exec); - PropertyNameArray propertyNames(exec); - o->getPropertyNames(exec, propertyNames); - return new (exec) JSPropertyNameIterator(exec, o, propertyNames.releaseData()); -} - -inline JSValue JSPropertyNameIterator::next(ExecState* exec) -{ - if (m_position == m_end) - return JSValue(); - - if (m_data->cachedStructure() == m_object->structure() && m_data->cachedPrototypeChain() == m_object->structure()->prototypeChain(exec)) - return jsOwnedString(exec, (*m_position++).ustring()); - - do { - if (m_object->hasProperty(exec, *m_position)) - return jsOwnedString(exec, (*m_position++).ustring()); - m_position++; - } while (m_position != m_end); - - return JSValue(); + ASSERT(!isDictionary()); + m_enumerationCache = enumerationCache; } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSStaticScopeObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSStaticScopeObject.h index 5eb0e4b..2542878 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSStaticScopeObject.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSStaticScopeObject.h @@ -57,7 +57,10 @@ namespace JSC{ virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes); - static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, NeedsThisConversion)); } + static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); } + + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NeedsThisConversion | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags; private: JSStaticScopeObjectData* d() { return static_cast<JSStaticScopeObjectData*>(JSVariableObject::d); } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.cpp index a30f729..1e23a15 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.cpp @@ -25,41 +25,150 @@ #include "JSGlobalObject.h" #include "JSObject.h" +#include "Operations.h" #include "StringObject.h" #include "StringPrototype.h" namespace JSC { +void JSString::Rope::destructNonRecursive() +{ + Vector<Rope*, 32> workQueue; + Rope* rope = this; + + while (true) { + unsigned length = rope->ropeLength(); + for (unsigned i = 0; i < length; ++i) { + Fiber& fiber = rope->fibers(i); + if (fiber.isString()) + fiber.string()->deref(); + else { + Rope* nextRope = fiber.rope(); + if (nextRope->hasOneRef()) + workQueue.append(nextRope); + else + nextRope->deref(); + } + } + if (rope != this) + fastFree(rope); + + if (workQueue.isEmpty()) + return; + + rope = workQueue.last(); + workQueue.removeLast(); + } +} + +JSString::Rope::~Rope() +{ + destructNonRecursive(); +} + +// Overview: this methods converts a JSString from holding a string in rope form +// down to a simple UString representation. It does so by building up the string +// backwards, since we want to avoid recursion, we expect that the tree structure +// representing the rope is likely imbalanced with more nodes down the left side +// (since appending to the string is likely more common) - and as such resolving +// in this fashion should minimize work queue size. (If we built the queue forwards +// we would likely have to place all of the constituent UString::Reps into the +// Vector before performing any concatenation, but by working backwards we likely +// only fill the queue with the number of substrings at any given level in a +// rope-of-ropes.) +void JSString::resolveRope(ExecState* exec) const +{ + ASSERT(isRope()); + + // Allocate the buffer to hold the final string, position initially points to the end. + UChar* buffer; + if (PassRefPtr<UStringImpl> newImpl = UStringImpl::tryCreateUninitialized(m_stringLength, buffer)) + m_value = newImpl; + else { + for (unsigned i = 0; i < m_ropeLength; ++i) { + m_fibers[i].deref(); + m_fibers[i] = static_cast<void*>(0); + } + m_ropeLength = 0; + ASSERT(!isRope()); + ASSERT(m_value == UString()); + throwOutOfMemoryError(exec); + return; + } + UChar* position = buffer + m_stringLength; + + // Start with the current Rope. + Vector<Rope::Fiber, 32> workQueue; + Rope::Fiber currentFiber; + for (unsigned i = 0; i < (m_ropeLength - 1); ++i) + workQueue.append(m_fibers[i]); + currentFiber = m_fibers[m_ropeLength - 1]; + while (true) { + if (currentFiber.isRope()) { + Rope* rope = currentFiber.rope(); + // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber' + // (we will be working backwards over the rope). + unsigned ropeLengthMinusOne = rope->ropeLength() - 1; + for (unsigned i = 0; i < ropeLengthMinusOne; ++i) + workQueue.append(rope->fibers(i)); + currentFiber = rope->fibers(ropeLengthMinusOne); + } else { + UString::Rep* string = currentFiber.string(); + unsigned length = string->size(); + position -= length; + UStringImpl::copyChars(position, string->data(), length); + + // Was this the last item in the work queue? + if (workQueue.isEmpty()) { + // Create a string from the UChar buffer, clear the rope RefPtr. + ASSERT(buffer == position); + for (unsigned i = 0; i < m_ropeLength; ++i) { + m_fibers[i].deref(); + m_fibers[i] = static_cast<void*>(0); + } + m_ropeLength = 0; + + ASSERT(!isRope()); + return; + } + + // No! - set the next item up to process. + currentFiber = workQueue.last(); + workQueue.removeLast(); + } + } +} + JSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const { return const_cast<JSString*>(this); } -bool JSString::getPrimitiveNumber(ExecState*, double& number, JSValue& value) +bool JSString::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) { - value = this; - number = m_value.toDouble(); + result = this; + number = value(exec).toDouble(); return false; } bool JSString::toBoolean(ExecState*) const { - return !m_value.isEmpty(); + return m_stringLength; } -double JSString::toNumber(ExecState*) const +double JSString::toNumber(ExecState* exec) const { - return m_value.toDouble(); + return value(exec).toDouble(); } -UString JSString::toString(ExecState*) const +UString JSString::toString(ExecState* exec) const { - return m_value; + return value(exec); } -UString JSString::toThisString(ExecState*) const +UString JSString::toThisString(ExecState* exec) const { - return m_value; + return value(exec); } JSString* JSString::toThisJSString(ExecState*) @@ -106,14 +215,14 @@ bool JSString::getOwnPropertySlot(ExecState* exec, const Identifier& propertyNam bool JSString::getStringPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) { if (propertyName == exec->propertyNames().length) { - descriptor.setDescriptor(jsNumber(exec, m_value.size()), DontEnum | DontDelete | ReadOnly); + descriptor.setDescriptor(jsNumber(exec, m_stringLength), DontEnum | DontDelete | ReadOnly); return true; } bool isStrictUInt32; unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); - if (isStrictUInt32 && i < static_cast<unsigned>(m_value.size())) { - descriptor.setDescriptor(jsSingleCharacterSubstring(exec, m_value, i), DontDelete | ReadOnly); + if (isStrictUInt32 && i < m_stringLength) { + descriptor.setDescriptor(jsSingleCharacterSubstring(exec, value(exec), i), DontDelete | ReadOnly); return true; } @@ -139,60 +248,4 @@ bool JSString::getOwnPropertySlot(ExecState* exec, unsigned propertyName, Proper return JSString::getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot); } -bool JSString::getStringPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const -{ - if (propertyName == exec->propertyNames().length) { - attributes = DontEnum | DontDelete | ReadOnly; - return true; - } - bool isStrictUInt32; - unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); - if (isStrictUInt32 && i < static_cast<unsigned>(m_value.size())) { - attributes = DontDelete | ReadOnly; - return true; - } - return false; -} - -JSString* jsString(JSGlobalData* globalData, const UString& s) -{ - int size = s.size(); - if (!size) - return globalData->smallStrings.emptyString(globalData); - if (size == 1) { - UChar c = s.data()[0]; - if (c <= 0xFF) - return globalData->smallStrings.singleCharacterString(globalData, c); - } - return new (globalData) JSString(globalData, s); -} - -JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length) -{ - ASSERT(offset <= static_cast<unsigned>(s.size())); - ASSERT(length <= static_cast<unsigned>(s.size())); - ASSERT(offset + length <= static_cast<unsigned>(s.size())); - if (!length) - return globalData->smallStrings.emptyString(globalData); - if (length == 1) { - UChar c = s.data()[offset]; - if (c <= 0xFF) - return globalData->smallStrings.singleCharacterString(globalData, c); - } - return new (globalData) JSString(globalData, UString::Rep::create(s.rep(), offset, length)); -} - -JSString* jsOwnedString(JSGlobalData* globalData, const UString& s) -{ - int size = s.size(); - if (!size) - return globalData->smallStrings.emptyString(globalData); - if (size == 1) { - UChar c = s.data()[0]; - if (c <= 0xFF) - return globalData->smallStrings.singleCharacterString(globalData, c); - } - return new (globalData) JSString(globalData, s, JSString::HasOtherOwner); -} - } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.h index eeada2e..e1c6aba 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.h @@ -59,14 +59,117 @@ namespace JSC { JSString* jsOwnedString(JSGlobalData*, const UString&); JSString* jsOwnedString(ExecState*, const UString&); - class JSString : public JSCell { - friend class JIT; - friend struct VPtrSet; + typedef void (*JSStringFinalizerCallback)(JSString*, void* context); + JSString* jsStringWithFinalizer(ExecState*, const UString&, JSStringFinalizerCallback callback, void* context); + class JS_EXPORTCLASS JSString : public JSCell { public: - JSString(JSGlobalData* globalData, const UString& value) + friend class JIT; + friend class JSGlobalData; + + // A Rope is a string composed of a set of substrings. + class Rope : public RefCounted<Rope> { + public: + // A Rope is composed from a set of smaller strings called Fibers. + // Each Fiber in a rope is either UString::Rep or another Rope. + class Fiber { + public: + Fiber() : m_value(0) {} + Fiber(UString::Rep* string) : m_value(reinterpret_cast<intptr_t>(string)) {} + Fiber(Rope* rope) : m_value(reinterpret_cast<intptr_t>(rope) | 1) {} + + Fiber(void* nonFiber) : m_value(reinterpret_cast<intptr_t>(nonFiber)) {} + + void deref() + { + if (isRope()) + rope()->deref(); + else + string()->deref(); + } + + Fiber& ref() + { + if (isString()) + string()->ref(); + else + rope()->ref(); + return *this; + } + + unsigned refAndGetLength() + { + if (isString()) { + UString::Rep* rep = string(); + return rep->ref()->size(); + } else { + Rope* r = rope(); + r->ref(); + return r->stringLength(); + } + } + + bool isRope() { return m_value & 1; } + Rope* rope() { return reinterpret_cast<Rope*>(m_value & ~1); } + bool isString() { return !isRope(); } + UString::Rep* string() { return reinterpret_cast<UString::Rep*>(m_value); } + + void* nonFiber() { return reinterpret_cast<void*>(m_value); } + private: + intptr_t m_value; + }; + + // Creates a Rope comprising of 'ropeLength' Fibers. + // The Rope is constructed in an uninitialized state - initialize must be called for each Fiber in the Rope. + static PassRefPtr<Rope> createOrNull(unsigned ropeLength) + { + void* allocation; + if (tryFastMalloc(sizeof(Rope) + (ropeLength - 1) * sizeof(Fiber)).getValue(allocation)) + return adoptRef(new (allocation) Rope(ropeLength)); + return 0; + } + + ~Rope(); + void destructNonRecursive(); + + void append(unsigned &index, Fiber& fiber) + { + m_fibers[index++] = fiber; + m_stringLength += fiber.refAndGetLength(); + } + void append(unsigned &index, const UString& string) + { + UString::Rep* rep = string.rep(); + m_fibers[index++] = Fiber(rep); + m_stringLength += rep->ref()->size(); + } + void append(unsigned& index, JSString* jsString) + { + if (jsString->isRope()) { + for (unsigned i = 0; i < jsString->m_ropeLength; ++i) + append(index, jsString->m_fibers[i]); + } else + append(index, jsString->string()); + } + + unsigned ropeLength() { return m_ropeLength; } + unsigned stringLength() { return m_stringLength; } + Fiber& fibers(unsigned index) { return m_fibers[index]; } + + private: + Rope(unsigned ropeLength) : m_ropeLength(ropeLength), m_stringLength(0) {} + void* operator new(size_t, void* inPlace) { return inPlace; } + + unsigned m_ropeLength; + unsigned m_stringLength; + Fiber m_fibers[1]; + }; + + ALWAYS_INLINE JSString(JSGlobalData* globalData, const UString& value) : JSCell(globalData->stringStructure.get()) + , m_stringLength(value.size()) , m_value(value) + , m_ropeLength(0) { Heap::heap(this)->reportExtraMemoryCost(value.cost()); } @@ -74,33 +177,164 @@ namespace JSC { enum HasOtherOwnerType { HasOtherOwner }; JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType) : JSCell(globalData->stringStructure.get()) + , m_stringLength(value.size()) , m_value(value) + , m_ropeLength(0) { } JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType) : JSCell(globalData->stringStructure.get()) + , m_stringLength(value->size()) , m_value(value) + , m_ropeLength(0) { } - - const UString& value() const { return m_value; } + JSString(JSGlobalData* globalData, PassRefPtr<JSString::Rope> rope) + : JSCell(globalData->stringStructure.get()) + , m_stringLength(rope->stringLength()) + , m_ropeLength(1) + { + m_fibers[0] = rope.releaseRef(); + } + // This constructor constructs a new string by concatenating s1 & s2. + // This should only be called with ropeLength <= 3. + JSString(JSGlobalData* globalData, unsigned ropeLength, JSString* s1, JSString* s2) + : JSCell(globalData->stringStructure.get()) + , m_stringLength(s1->length() + s2->length()) + , m_ropeLength(ropeLength) + { + ASSERT(ropeLength <= s_maxInternalRopeLength); + unsigned index = 0; + appendStringInConstruct(index, s1); + appendStringInConstruct(index, s2); + ASSERT(ropeLength == index); + } + // This constructor constructs a new string by concatenating s1 & s2. + // This should only be called with ropeLength <= 3. + JSString(JSGlobalData* globalData, unsigned ropeLength, JSString* s1, const UString& u2) + : JSCell(globalData->stringStructure.get()) + , m_stringLength(s1->length() + u2.size()) + , m_ropeLength(ropeLength) + { + ASSERT(ropeLength <= s_maxInternalRopeLength); + unsigned index = 0; + appendStringInConstruct(index, s1); + appendStringInConstruct(index, u2); + ASSERT(ropeLength == index); + } + // This constructor constructs a new string by concatenating s1 & s2. + // This should only be called with ropeLength <= 3. + JSString(JSGlobalData* globalData, unsigned ropeLength, const UString& u1, JSString* s2) + : JSCell(globalData->stringStructure.get()) + , m_stringLength(u1.size() + s2->length()) + , m_ropeLength(ropeLength) + { + ASSERT(ropeLength <= s_maxInternalRopeLength); + unsigned index = 0; + appendStringInConstruct(index, u1); + appendStringInConstruct(index, s2); + ASSERT(ropeLength == index); + } + // This constructor constructs a new string by concatenating v1, v2 & v3. + // This should only be called with ropeLength <= 3 ... which since every + // value must require a ropeLength of at least one implies that the length + // for each value must be exactly 1! + JSString(ExecState* exec, JSValue v1, JSValue v2, JSValue v3) + : JSCell(exec->globalData().stringStructure.get()) + , m_stringLength(0) + , m_ropeLength(s_maxInternalRopeLength) + { + unsigned index = 0; + appendValueInConstructAndIncrementLength(exec, index, v1); + appendValueInConstructAndIncrementLength(exec, index, v2); + appendValueInConstructAndIncrementLength(exec, index, v3); + ASSERT(index == s_maxInternalRopeLength); + } + + JSString(JSGlobalData* globalData, const UString& value, JSStringFinalizerCallback finalizer, void* context) + : JSCell(globalData->stringStructure.get()) + , m_stringLength(value.size()) + , m_value(value) + , m_ropeLength(0) + { + // nasty hack because we can't union non-POD types + m_fibers[0] = reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(finalizer)); + m_fibers[1] = context; + Heap::heap(this)->reportExtraMemoryCost(value.cost()); + } + + ~JSString() + { + ASSERT(vptr() == JSGlobalData::jsStringVPtr); + for (unsigned i = 0; i < m_ropeLength; ++i) + m_fibers[i].deref(); + + if (!m_ropeLength && m_fibers[0].nonFiber()) { + JSStringFinalizerCallback finalizer = (JSStringFinalizerCallback)(m_fibers[0].nonFiber()); + finalizer(this, m_fibers[1].nonFiber()); + } + } + + const UString& value(ExecState* exec) const + { + if (isRope()) + resolveRope(exec); + return m_value; + } + const UString tryGetValue() const + { + if (isRope()) + UString(); + return m_value; + } + unsigned length() { return m_stringLength; } bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); bool getStringPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&); - bool getStringPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned&) const; - - bool canGetIndex(unsigned i) { return i < static_cast<unsigned>(m_value.size()); } - JSString* getIndex(JSGlobalData*, unsigned); + bool canGetIndex(unsigned i) { return i < m_stringLength; } + JSString* getIndex(ExecState*, unsigned); - static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, NeedsThisConversion | HasDefaultMark)); } + static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion)); } private: enum VPtrStealingHackType { VPtrStealingHack }; JSString(VPtrStealingHackType) : JSCell(0) + , m_ropeLength(0) + { + } + + void resolveRope(ExecState*) const; + + void appendStringInConstruct(unsigned& index, const UString& string) + { + m_fibers[index++] = Rope::Fiber(string.rep()->ref()); + } + + void appendStringInConstruct(unsigned& index, JSString* jsString) { + if (jsString->isRope()) { + for (unsigned i = 0; i < jsString->m_ropeLength; ++i) + m_fibers[index++] = jsString->m_fibers[i].ref(); + } else + appendStringInConstruct(index, jsString->string()); + } + + void appendValueInConstructAndIncrementLength(ExecState* exec, unsigned& index, JSValue v) + { + if (v.isString()) { + ASSERT(asCell(v)->isString()); + JSString* s = static_cast<JSString*>(asCell(v)); + ASSERT(s->ropeLength() == 1); + appendStringInConstruct(index, s); + m_stringLength += s->length(); + } else { + UString u(v.toString(exec)); + m_fibers[index++] = Rope::Fiber(u.rep()->ref()); + m_stringLength += u.size(); + } } virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; @@ -119,11 +353,38 @@ namespace JSC { virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); - UString m_value; + static const unsigned s_maxInternalRopeLength = 3; + + // A string is represented either by a UString or a Rope. + unsigned m_stringLength; + mutable UString m_value; + mutable unsigned m_ropeLength; + mutable Rope::Fiber m_fibers[s_maxInternalRopeLength]; + + bool isRope() const { return m_ropeLength; } + UString& string() { ASSERT(!isRope()); return m_value; } + unsigned ropeLength() { return m_ropeLength ? m_ropeLength : 1; } + + friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2); + friend JSValue jsString(ExecState* exec, const UString& u1, JSString* s2); + friend JSValue jsString(ExecState* exec, JSString* s1, const UString& u2); + friend JSValue jsString(ExecState* exec, Register* strings, unsigned count); + friend JSValue jsString(ExecState* exec, JSValue thisValue, const ArgList& args); + friend JSString* jsStringWithFinalizer(ExecState*, const UString&, JSStringFinalizerCallback callback, void* context); }; JSString* asString(JSValue); + // When an object is created from a different DLL, MSVC changes vptr to a "local" one right after invoking a constructor, + // see <http://groups.google.com/group/microsoft.public.vc.language/msg/55cdcefeaf770212>. + // This breaks isJSString(), and we don't need that hack anyway, so we change vptr back to primary one. + // The below function must be called by any inline function that invokes a JSString constructor. +#if COMPILER(MSVC) && !defined(BUILDING_JavaScriptCore) + inline JSString* fixupVPtr(JSGlobalData* globalData, JSString* string) { string->setVPtr(globalData->jsStringVPtr); return string; } +#else + inline JSString* fixupVPtr(JSGlobalData*, JSString* string) { return string; } +#endif + inline JSString* asString(JSValue value) { ASSERT(asCell(value)->isString()); @@ -139,7 +400,7 @@ namespace JSC { { if (c <= 0xFF) return globalData->smallStrings.singleCharacterString(globalData, c); - return new (globalData) JSString(globalData, UString(&c, 1)); + return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(&c, 1))); } inline JSString* jsSingleCharacterSubstring(JSGlobalData* globalData, const UString& s, unsigned offset) @@ -148,7 +409,7 @@ namespace JSC { UChar c = s.data()[offset]; if (c <= 0xFF) return globalData->smallStrings.singleCharacterString(globalData, c); - return new (globalData) JSString(globalData, UString::Rep::create(s.rep(), offset, 1)); + return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, 1)))); } inline JSString* jsNontrivialString(JSGlobalData* globalData, const char* s) @@ -156,19 +417,67 @@ namespace JSC { ASSERT(s); ASSERT(s[0]); ASSERT(s[1]); - return new (globalData) JSString(globalData, s); + return fixupVPtr(globalData, new (globalData) JSString(globalData, s)); } inline JSString* jsNontrivialString(JSGlobalData* globalData, const UString& s) { ASSERT(s.size() > 1); - return new (globalData) JSString(globalData, s); + return fixupVPtr(globalData, new (globalData) JSString(globalData, s)); } - inline JSString* JSString::getIndex(JSGlobalData* globalData, unsigned i) + inline JSString* JSString::getIndex(ExecState* exec, unsigned i) { ASSERT(canGetIndex(i)); - return jsSingleCharacterSubstring(globalData, m_value, i); + return jsSingleCharacterSubstring(&exec->globalData(), value(exec), i); + } + + inline JSString* jsString(JSGlobalData* globalData, const UString& s) + { + int size = s.size(); + if (!size) + return globalData->smallStrings.emptyString(globalData); + if (size == 1) { + UChar c = s.data()[0]; + if (c <= 0xFF) + return globalData->smallStrings.singleCharacterString(globalData, c); + } + return fixupVPtr(globalData, new (globalData) JSString(globalData, s)); + } + + inline JSString* jsStringWithFinalizer(ExecState* exec, const UString& s, JSStringFinalizerCallback callback, void* context) + { + ASSERT(s.size() && (s.size() > 1 || s.data()[0] > 0xFF)); + JSGlobalData* globalData = &exec->globalData(); + return fixupVPtr(globalData, new (globalData) JSString(globalData, s, callback, context)); + } + + inline JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length) + { + ASSERT(offset <= static_cast<unsigned>(s.size())); + ASSERT(length <= static_cast<unsigned>(s.size())); + ASSERT(offset + length <= static_cast<unsigned>(s.size())); + if (!length) + return globalData->smallStrings.emptyString(globalData); + if (length == 1) { + UChar c = s.data()[offset]; + if (c <= 0xFF) + return globalData->smallStrings.singleCharacterString(globalData, c); + } + return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, length)), JSString::HasOtherOwner)); + } + + inline JSString* jsOwnedString(JSGlobalData* globalData, const UString& s) + { + int size = s.size(); + if (!size) + return globalData->smallStrings.emptyString(globalData); + if (size == 1) { + UChar c = s.data()[0]; + if (c <= 0xFF) + return globalData->smallStrings.singleCharacterString(globalData, c); + } + return fixupVPtr(globalData, new (globalData) JSString(globalData, s, JSString::HasOtherOwner)); } inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); } @@ -183,14 +492,14 @@ namespace JSC { ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { if (propertyName == exec->propertyNames().length) { - slot.setValue(jsNumber(exec, m_value.size())); + slot.setValue(jsNumber(exec, m_stringLength)); return true; } bool isStrictUInt32; unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); - if (isStrictUInt32 && i < static_cast<unsigned>(m_value.size())) { - slot.setValue(jsSingleCharacterSubstring(exec, m_value, i)); + if (isStrictUInt32 && i < m_stringLength) { + slot.setValue(jsSingleCharacterSubstring(exec, value(exec), i)); return true; } @@ -199,8 +508,8 @@ namespace JSC { ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) { - if (propertyName < static_cast<unsigned>(m_value.size())) { - slot.setValue(jsSingleCharacterSubstring(exec, m_value, propertyName)); + if (propertyName < m_stringLength) { + slot.setValue(jsSingleCharacterSubstring(exec, value(exec), propertyName)); return true; } @@ -219,7 +528,7 @@ namespace JSC { inline UString JSValue::toString(ExecState* exec) const { if (isString()) - return static_cast<JSString*>(asCell())->value(); + return static_cast<JSString*>(asCell())->value(exec); if (isInt32()) return exec->globalData().numericStrings.add(asInt32()); if (isDouble()) @@ -236,6 +545,26 @@ namespace JSC { return asCell()->toString(exec); } + inline UString JSValue::toPrimitiveString(ExecState* exec) const + { + if (isString()) + return static_cast<JSString*>(asCell())->value(exec); + if (isInt32()) + return exec->globalData().numericStrings.add(asInt32()); + if (isDouble()) + return exec->globalData().numericStrings.add(asDouble()); + if (isTrue()) + return "true"; + if (isFalse()) + return "false"; + if (isNull()) + return "null"; + if (isUndefined()) + return "undefined"; + ASSERT(isCell()); + return asCell()->toPrimitive(exec, NoPreference).toString(exec); + } + } // namespace JSC #endif // JSString_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSTypeInfo.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSTypeInfo.h index 279510b..7c89600 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSTypeInfo.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSTypeInfo.h @@ -40,9 +40,9 @@ namespace JSC { static const unsigned OverridesHasInstance = 1 << 2; static const unsigned ImplementsDefaultHasInstance = 1 << 3; static const unsigned NeedsThisConversion = 1 << 4; - static const unsigned HasStandardGetOwnPropertySlot = 1 << 5; - static const unsigned HasDefaultMark = 1 << 6; - static const unsigned HasDefaultGetPropertyNames = 1 << 7; + static const unsigned OverridesGetOwnPropertySlot = 1 << 5; + static const unsigned OverridesMarkChildren = 1 << 6; + static const unsigned OverridesGetPropertyNames = 1 << 7; class TypeInfo { friend class JIT; @@ -63,9 +63,9 @@ namespace JSC { bool implementsHasInstance() const { return m_flags & ImplementsHasInstance; } bool overridesHasInstance() const { return m_flags & OverridesHasInstance; } bool needsThisConversion() const { return m_flags & NeedsThisConversion; } - bool hasStandardGetOwnPropertySlot() const { return m_flags & HasStandardGetOwnPropertySlot; } - bool hasDefaultMark() const { return m_flags & HasDefaultMark; } - bool hasDefaultGetPropertyNames() const { return m_flags & HasDefaultGetPropertyNames; } + bool overridesGetOwnPropertySlot() const { return m_flags & OverridesGetOwnPropertySlot; } + bool overridesMarkChildren() const { return m_flags & OverridesMarkChildren; } + bool overridesGetPropertyNames() const { return m_flags & OverridesGetPropertyNames; } unsigned flags() const { return m_flags; } private: diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSValue.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSValue.h index 3c511d8..6da921f 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSValue.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSValue.h @@ -80,6 +80,7 @@ namespace JSC { enum JSUndefinedTag { JSUndefined }; enum JSTrueTag { JSTrue }; enum JSFalseTag { JSFalse }; + enum EncodeAsDoubleTag { EncodeAsDouble }; JSValue(); JSValue(JSNullTag); @@ -90,6 +91,7 @@ namespace JSC { JSValue(const JSCell* ptr); // Numbers + JSValue(EncodeAsDoubleTag, ExecState*, double); JSValue(ExecState*, double); JSValue(ExecState*, char); JSValue(ExecState*, unsigned char); @@ -135,8 +137,8 @@ namespace JSC { bool getBoolean() const; // false if not a boolean bool getNumber(double&) const; double uncheckedGetNumber() const; - bool getString(UString&) const; - UString getString() const; // null string if not a string + bool getString(ExecState* exec, UString&) const; + UString getString(ExecState* exec) const; // null string if not a string JSObject* getObject() const; // 0 if not an object CallType getCallData(CallData&); @@ -156,6 +158,7 @@ namespace JSC { double toNumber(ExecState*) const; JSValue toJSNumber(ExecState*) const; // Fast path for when you expect that the value is an immediate number. UString toString(ExecState*) const; + UString toPrimitiveString(ExecState*) const; JSObject* toObject(ExecState*) const; // Integer conversions. @@ -166,6 +169,10 @@ namespace JSC { uint32_t toUInt32(ExecState*) const; uint32_t toUInt32(ExecState*, bool& ok) const; +#if ENABLE(JSC_ZOMBIES) + bool isZombie() const; +#endif + // Floating point conversions (this is a convenience method for webcore; // signle precision float is not a representation used in JS or JSC). float toFloat(ExecState* exec) const { return static_cast<float>(toNumber(exec)); } @@ -186,9 +193,9 @@ namespace JSC { static bool equal(ExecState* exec, JSValue v1, JSValue v2); static bool equalSlowCase(ExecState* exec, JSValue v1, JSValue v2); static bool equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2); - static bool strictEqual(JSValue v1, JSValue v2); - static bool strictEqualSlowCase(JSValue v1, JSValue v2); - static bool strictEqualSlowCaseInline(JSValue v1, JSValue v2); + static bool strictEqual(ExecState* exec, JSValue v1, JSValue v2); + static bool strictEqualSlowCase(ExecState* exec, JSValue v1, JSValue v2); + static bool strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2); JSValue getJSNumber(); // JSValue() if this is not a JSNumber or number object @@ -228,7 +235,7 @@ namespace JSC { union { EncodedJSValue asEncodedJSValue; double asDouble; -#if PLATFORM(BIG_ENDIAN) +#if CPU(BIG_ENDIAN) struct { int32_t tag; int32_t payload; @@ -279,6 +286,11 @@ namespace JSC { return b ? JSValue(JSValue::JSTrue) : JSValue(JSValue::JSFalse); } + ALWAYS_INLINE JSValue jsDoubleNumber(ExecState* exec, double d) + { + return JSValue(JSValue::EncodeAsDouble, exec, d); + } + ALWAYS_INLINE JSValue jsNumber(ExecState* exec, double d) { return JSValue(exec, d); @@ -373,6 +385,14 @@ namespace JSC { return static_cast<uint32_t>(val); } + // FIXME: We should deprecate this and just use JSValue::asCell() instead. + JSCell* asCell(JSValue); + + inline JSCell* asCell(JSValue value) + { + return value.asCell(); + } + ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const { if (isInt32()) @@ -423,6 +443,9 @@ namespace JSC { { JSValue v; v.u.asEncodedJSValue = encodedJSValue; +#if ENABLE(JSC_ZOMBIES) + ASSERT(!v.isZombie()); +#endif return v; } @@ -469,6 +492,9 @@ namespace JSC { else u.asBits.tag = EmptyValueTag; u.asBits.payload = reinterpret_cast<int32_t>(ptr); +#if ENABLE(JSC_ZOMBIES) + ASSERT(!isZombie()); +#endif } inline JSValue::JSValue(const JSCell* ptr) @@ -478,6 +504,9 @@ namespace JSC { else u.asBits.tag = EmptyValueTag; u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr)); +#if ENABLE(JSC_ZOMBIES) + ASSERT(!isZombie()); +#endif } inline JSValue::operator bool() const @@ -575,6 +604,11 @@ namespace JSC { return reinterpret_cast<JSCell*>(u.asBits.payload); } + ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, ExecState*, double d) + { + u.asDouble = d; + } + inline JSValue::JSValue(ExecState* exec, double d) { const int32_t asInt32 = static_cast<int32_t>(d); @@ -773,11 +807,17 @@ namespace JSC { inline JSValue::JSValue(JSCell* ptr) : m_ptr(ptr) { +#if ENABLE(JSC_ZOMBIES) + ASSERT(!isZombie()); +#endif } inline JSValue::JSValue(const JSCell* ptr) : m_ptr(const_cast<JSCell*>(ptr)) { +#if ENABLE(JSC_ZOMBIES) + ASSERT(!isZombie()); +#endif } inline JSValue::operator bool() const diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSVariableObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSVariableObject.cpp index ac193ca..7365001 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSVariableObject.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSVariableObject.cpp @@ -34,33 +34,23 @@ namespace JSC { -bool JSVariableObject::deleteProperty(ExecState* exec, const Identifier& propertyName, bool checkDontDelete) +bool JSVariableObject::deleteProperty(ExecState* exec, const Identifier& propertyName) { if (symbolTable().contains(propertyName.ustring().rep())) return false; - return JSObject::deleteProperty(exec, propertyName, checkDontDelete); + return JSObject::deleteProperty(exec, propertyName); } -void JSVariableObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, bool includeNonEnumerable) +void JSVariableObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { SymbolTable::const_iterator end = symbolTable().end(); for (SymbolTable::const_iterator it = symbolTable().begin(); it != end; ++it) { - if (!(it->second.getAttributes() & DontEnum) || includeNonEnumerable) + if (!(it->second.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties)) propertyNames.add(Identifier(exec, it->first.get())); } - JSObject::getOwnPropertyNames(exec, propertyNames, includeNonEnumerable); -} - -bool JSVariableObject::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const -{ - SymbolTableEntry entry = symbolTable().get(propertyName.ustring().rep()); - if (!entry.isNull()) { - attributes = entry.getAttributes() | DontDelete; - return true; - } - return JSObject::getPropertyAttributes(exec, propertyName, attributes); + JSObject::getOwnPropertyNames(exec, propertyNames, mode); } bool JSVariableObject::isVariableObject() const diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSVariableObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSVariableObject.h index fe92729..737816d 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSVariableObject.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSVariableObject.h @@ -48,22 +48,21 @@ namespace JSC { virtual void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes) = 0; - virtual bool deleteProperty(ExecState*, const Identifier&, bool checkDontDelete = true); - virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, bool includeNonEnumerable = false); + virtual bool deleteProperty(ExecState*, const Identifier&); + virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); virtual bool isVariableObject() const; virtual bool isDynamicScope() const = 0; - virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const; - Register& registerAt(int index) const { return d->registers[index]; } static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot | HasDefaultMark)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } protected: + static const unsigned StructureFlags = OverridesGetPropertyNames | JSObject::StructureFlags; // Subclasses of JSVariableObject can subclass this struct to add data // without increasing their own size (since there's a hard limit on the // size of a JSCell). @@ -84,7 +83,7 @@ namespace JSC { JSVariableObjectData& operator=(const JSVariableObjectData&); }; - JSVariableObject(PassRefPtr<Structure> structure, JSVariableObjectData* data) + JSVariableObject(NonNullPassRefPtr<Structure> structure, JSVariableObjectData* data) : JSObject(structure) , d(data) // Subclass owns this pointer. { diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSWrapperObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSWrapperObject.h index b56a58d..191ff3b 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSWrapperObject.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSWrapperObject.h @@ -30,7 +30,7 @@ namespace JSC { // Number, Boolean and Date which are wrappers for primitive types. class JSWrapperObject : public JSObject { protected: - explicit JSWrapperObject(PassRefPtr<Structure>); + explicit JSWrapperObject(NonNullPassRefPtr<Structure>); public: JSValue internalValue() const { return m_internalValue; } @@ -38,7 +38,7 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot | HasDefaultGetPropertyNames | HasDefaultMark)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } private: @@ -47,7 +47,7 @@ namespace JSC { JSValue m_internalValue; }; - inline JSWrapperObject::JSWrapperObject(PassRefPtr<Structure> structure) + inline JSWrapperObject::JSWrapperObject(NonNullPassRefPtr<Structure> structure) : JSObject(structure) { addAnonymousSlots(1); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSZombie.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSZombie.cpp new file mode 100644 index 0000000..072d29b --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSZombie.cpp @@ -0,0 +1,48 @@ +/* + * 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 "JSZombie.h" +#include "ClassInfo.h" + +#if ENABLE(JSC_ZOMBIES) + +namespace JSC { + +const ClassInfo JSZombie::s_info = { "Zombie", 0, 0, 0 }; + +Structure* JSZombie::leakedZombieStructure() { + static Structure* structure = 0; + if (!structure) { + Structure::startIgnoringLeaks(); + structure = Structure::create(jsNull(), TypeInfo(UnspecifiedType)).releaseRef(); + Structure::stopIgnoringLeaks(); + } + return structure; +} + +} + +#endif // ENABLE(JSC_ZOMBIES) diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSZombie.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSZombie.h new file mode 100644 index 0000000..8b33ea6 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSZombie.h @@ -0,0 +1,78 @@ +/* + * 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 JSZombie_h +#define JSZombie_h + +#include "JSCell.h" + +#if ENABLE(JSC_ZOMBIES) +namespace JSC { + +class JSZombie : public JSCell { +public: + JSZombie(const ClassInfo* oldInfo, Structure* structure) + : JSCell(structure) + , m_oldInfo(oldInfo) + { + } + virtual bool isZombie() const { return true; } + virtual const ClassInfo* classInfo() const { return &s_info; } + static Structure* leakedZombieStructure(); + + virtual bool isGetterSetter() const { ASSERT_NOT_REACHED(); return false; } + virtual bool isAPIValueWrapper() const { ASSERT_NOT_REACHED(); return false; } + virtual bool isPropertyNameIterator() const { ASSERT_NOT_REACHED(); return false; } + virtual CallType getCallData(CallData&) { ASSERT_NOT_REACHED(); return CallTypeNone; } + virtual ConstructType getConstructData(ConstructData&) { ASSERT_NOT_REACHED(); return ConstructTypeNone; } + virtual bool getUInt32(uint32_t&) const { ASSERT_NOT_REACHED(); return false; } + virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const { ASSERT_NOT_REACHED(); return jsNull(); } + virtual bool getPrimitiveNumber(ExecState*, double&, JSValue&) { ASSERT_NOT_REACHED(); return false; } + virtual bool toBoolean(ExecState*) const { ASSERT_NOT_REACHED(); return false; } + virtual double toNumber(ExecState*) const { ASSERT_NOT_REACHED(); return 0.0; } + virtual UString toString(ExecState*) const { ASSERT_NOT_REACHED(); return ""; } + virtual JSObject* toObject(ExecState*) const { ASSERT_NOT_REACHED(); return 0; } + virtual void markChildren(MarkStack&) { ASSERT_NOT_REACHED(); } + virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&) { ASSERT_NOT_REACHED(); } + virtual void put(ExecState*, unsigned, JSValue) { ASSERT_NOT_REACHED(); } + virtual bool deleteProperty(ExecState*, const Identifier&) { ASSERT_NOT_REACHED(); return false; } + virtual bool deleteProperty(ExecState*, unsigned) { ASSERT_NOT_REACHED(); return false; } + virtual JSObject* toThisObject(ExecState*) const { ASSERT_NOT_REACHED(); return 0; } + virtual UString toThisString(ExecState*) const { ASSERT_NOT_REACHED(); return ""; } + virtual JSString* toThisJSString(ExecState*) { ASSERT_NOT_REACHED(); return 0; } + virtual JSValue getJSNumber() { ASSERT_NOT_REACHED(); return jsNull(); } + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&) { ASSERT_NOT_REACHED(); return false; } + virtual bool getOwnPropertySlot(ExecState*, unsigned, PropertySlot&) { ASSERT_NOT_REACHED(); return false; } + + static const ClassInfo s_info; +private: + const ClassInfo* m_oldInfo; +}; + +} + +#endif // ENABLE(JSC_ZOMBIES) + +#endif // JSZombie_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/LiteralParser.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/LiteralParser.cpp index d242282..aa1e5ed 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/LiteralParser.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/LiteralParser.cpp @@ -29,6 +29,7 @@ #include "JSArray.h" #include "JSString.h" #include "Lexer.h" +#include "StringBuilder.h" #include <wtf/ASCIICType.h> #include <wtf/dtoa.h> @@ -134,48 +135,48 @@ template <LiteralParser::ParserMode mode> inline LiteralParser::TokenType Litera { ++m_ptr; const UChar* runStart; - token.stringToken = UString(); + StringBuilder builder; do { runStart = m_ptr; while (m_ptr < m_end && isSafeStringCharacter<mode>(*m_ptr)) ++m_ptr; if (runStart < m_ptr) - token.stringToken.append(runStart, m_ptr - runStart); + builder.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('"'); + builder.append('"'); m_ptr++; break; case '\\': - token.stringToken.append('\\'); + builder.append('\\'); m_ptr++; break; case '/': - token.stringToken.append('/'); + builder.append('/'); m_ptr++; break; case 'b': - token.stringToken.append('\b'); + builder.append('\b'); m_ptr++; break; case 'f': - token.stringToken.append('\f'); + builder.append('\f'); m_ptr++; break; case 'n': - token.stringToken.append('\n'); + builder.append('\n'); m_ptr++; break; case 'r': - token.stringToken.append('\r'); + builder.append('\r'); m_ptr++; break; case 't': - token.stringToken.append('\t'); + builder.append('\t'); m_ptr++; break; @@ -186,7 +187,7 @@ template <LiteralParser::ParserMode mode> inline LiteralParser::TokenType Litera 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])); + builder.append(JSC::Lexer::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4])); m_ptr += 5; break; @@ -199,6 +200,7 @@ template <LiteralParser::ParserMode mode> inline LiteralParser::TokenType Litera if (m_ptr >= m_end || *m_ptr != '"') return TokError; + token.stringToken = builder.release(); token.type = TokString; token.end = ++m_ptr; return TokString; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Lookup.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Lookup.cpp index 8359ff7..4e9e086 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Lookup.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Lookup.cpp @@ -34,7 +34,7 @@ void HashTable::createTable(JSGlobalData* globalData) const entries[i].setKey(0); for (int i = 0; values[i].key; ++i) { UString::Rep* identifier = Identifier::add(globalData, values[i].key).releaseRef(); - int hashIndex = identifier->computedHash() & compactHashSizeMask; + int hashIndex = identifier->existingHash() & compactHashSizeMask; HashEntry* entry = &entries[hashIndex]; if (entry->key()) { diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Lookup.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Lookup.h index 4d70689..e673c09 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Lookup.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Lookup.h @@ -144,7 +144,7 @@ namespace JSC { { ASSERT(table); - const HashEntry* entry = &table[identifier.ustring().rep()->computedHash() & compactHashSizeMask]; + const HashEntry* entry = &table[identifier.ustring().rep()->existingHash() & compactHashSizeMask]; if (!entry->key()) return 0; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStack.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStack.h index 5bc85fa..c551bac 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStack.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStack.h @@ -47,7 +47,7 @@ namespace JSC { } ALWAYS_INLINE void append(JSValue); - ALWAYS_INLINE void append(JSCell*); + void append(JSCell*); ALWAYS_INLINE void appendValues(Register* values, size_t count, MarkSetProperties properties = NoNullValues) { @@ -153,7 +153,7 @@ namespace JSC { ASSERT(0 == (size % MarkStack::pageSize())); if (size == m_allocated) return; -#if PLATFORM(WIN) +#if OS(WINDOWS) || OS(SYMBIAN) || PLATFORM(BREWMP) // We cannot release a part of a region with VirtualFree. To get around this, // we'll release the entire region and reallocate the size that we want. releaseStack(m_data, m_allocated); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStackNone.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStackNone.cpp new file mode 100644 index 0000000..b1ff48b --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStackNone.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2009 Company 100, 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 "MarkStack.h" + +#include "FastMalloc.h" + +namespace JSC { + +void MarkStack::initializePagesize() +{ + MarkStack::s_pageSize = 4096; +} + +void* MarkStack::allocateStack(size_t size) +{ + return fastMalloc(size); +} + +void MarkStack::releaseStack(void* addr, size_t) +{ + return fastFree(addr); +} + +} diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStackPosix.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStackPosix.cpp index aec968e..de5e8ba 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStackPosix.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStackPosix.cpp @@ -24,49 +24,29 @@ */ #include "config.h" - - #include "MarkStack.h" +#if OS(UNIX) && !OS(SYMBIAN) + #include <unistd.h> -#if defined (__SYMBIAN32__) -#include "wtf/FastMalloc.h" -#include <e32base.h> -#include <e32std.h> -#include <e32hal.h> -#include <hal.h> -#else #include <sys/mman.h> -#endif namespace JSC { void MarkStack::initializePagesize() { -#if defined (__SYMBIAN32__) - TInt page_size; - UserHal::PageSizeInBytes(page_size); - MarkStack::s_pageSize = page_size; -#else MarkStack::s_pageSize = getpagesize(); -#endif } void* MarkStack::allocateStack(size_t size) { -#if defined (__SYMBIAN32__) - return fastMalloc(size); -#else return mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); -#endif } void MarkStack::releaseStack(void* addr, size_t size) { -#if defined (__SYMBIAN32__) - fastFree(addr); -#else munmap(reinterpret_cast<char*>(addr), size); -#endif } } + +#endif diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStackSymbian.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStackSymbian.cpp new file mode 100644 index 0000000..bda14ac --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStackSymbian.cpp @@ -0,0 +1,48 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "MarkStack.h" + +#if OS(SYMBIAN) + +#include <e32hal.h> + +namespace JSC { + +void MarkStack::initializePagesize() +{ + TInt page_size; + UserHal::PageSizeInBytes(page_size); + MarkStack::s_pageSize = page_size; +} + +void* MarkStack::allocateStack(size_t size) +{ + return fastMalloc(size); +} + +void MarkStack::releaseStack(void* addr, size_t size) +{ + return fastFree(addr); +} + +} + +#endif diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStackWin.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStackWin.cpp index 1fdd06a..a171c78 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStackWin.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MarkStackWin.cpp @@ -24,10 +24,10 @@ */ #include "config.h" - - #include "MarkStack.h" +#if OS(WINDOWS) + #include "windows.h" namespace JSC { @@ -51,3 +51,5 @@ void MarkStack::releaseStack(void* addr, size_t) } } + +#endif diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MathObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MathObject.cpp index 36771ab..98ff3ba 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MathObject.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MathObject.cpp @@ -85,7 +85,7 @@ const ClassInfo MathObject::info = { "Math", 0, 0, ExecState::mathTable }; @end */ -MathObject::MathObject(ExecState* exec, PassRefPtr<Structure> structure) +MathObject::MathObject(ExecState* exec, NonNullPassRefPtr<Structure> structure) : JSObject(structure) { putDirectWithoutTransition(Identifier(exec, "E"), jsNumber(exec, exp(1.0)), DontDelete | DontEnum | ReadOnly); @@ -96,7 +96,6 @@ MathObject::MathObject(ExecState* exec, PassRefPtr<Structure> structure) putDirectWithoutTransition(Identifier(exec, "PI"), jsNumber(exec, piDouble), DontDelete | DontEnum | ReadOnly); putDirectWithoutTransition(Identifier(exec, "SQRT1_2"), jsNumber(exec, sqrt(0.5)), DontDelete | DontEnum | ReadOnly); putDirectWithoutTransition(Identifier(exec, "SQRT2"), jsNumber(exec, sqrt(2.0)), DontDelete | DontEnum | ReadOnly); - WTF::initializeWeakRandomNumberGenerator(); } // ECMA 15.8 @@ -120,22 +119,22 @@ JSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState* exec, JSObject*, JSValue, cons JSValue JSC_HOST_CALL mathProtoFuncACos(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, acos(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, acos(args.at(0).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncASin(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, asin(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, asin(args.at(0).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncATan(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, atan(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, atan(args.at(0).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, atan2(args.at(0).toNumber(exec), args.at(1).toNumber(exec))); + return jsDoubleNumber(exec, atan2(args.at(0).toNumber(exec), args.at(1).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState* exec, JSObject*, JSValue, const ArgList& args) @@ -145,12 +144,12 @@ JSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState* exec, JSObject*, JSValue, con JSValue JSC_HOST_CALL mathProtoFuncCos(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, cos(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, cos(args.at(0).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncExp(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, exp(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, exp(args.at(0).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState* exec, JSObject*, JSValue, const ArgList& args) @@ -160,7 +159,7 @@ JSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState* exec, JSObject*, JSValue, co JSValue JSC_HOST_CALL mathProtoFuncLog(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, log(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, log(args.at(0).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncMax(ExecState* exec, JSObject*, JSValue, const ArgList& args) @@ -211,7 +210,7 @@ JSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec, JSObject*, JSValue, cons JSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState* exec, JSObject*, JSValue, const ArgList&) { - return jsNumber(exec, WTF::weakRandomNumber()); + return jsDoubleNumber(exec, exec->globalData().weakRandom.get()); } JSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec, JSObject*, JSValue, const ArgList& args) @@ -224,17 +223,17 @@ JSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec, JSObject*, JSValue, co JSValue JSC_HOST_CALL mathProtoFuncSin(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, sin(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, sin(args.at(0).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, sqrt(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, sqrt(args.at(0).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncTan(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, tan(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, tan(args.at(0).toNumber(exec))); } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MathObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MathObject.h index a2e065f..7f474b8 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MathObject.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/MathObject.h @@ -27,7 +27,7 @@ namespace JSC { class MathObject : public JSObject { public: - MathObject(ExecState*, PassRefPtr<Structure>); + MathObject(ExecState*, NonNullPassRefPtr<Structure>); virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); @@ -37,8 +37,11 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, HasDefaultMark | HasDefaultGetPropertyNames)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } + + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags; }; } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorConstructor.cpp index 0205fc5..403fc7e 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorConstructor.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorConstructor.cpp @@ -32,8 +32,8 @@ ASSERT_CLASS_FITS_IN_CELL(NativeErrorConstructor); const ClassInfo NativeErrorConstructor::info = { "Function", &InternalFunction::info, 0, 0 }; -NativeErrorConstructor::NativeErrorConstructor(ExecState* exec, PassRefPtr<Structure> structure, NativeErrorPrototype* nativeErrorPrototype) - : InternalFunction(&exec->globalData(), structure, Identifier(exec, nativeErrorPrototype->getDirect(exec->propertyNames().name).getString())) +NativeErrorConstructor::NativeErrorConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, NativeErrorPrototype* nativeErrorPrototype) + : InternalFunction(&exec->globalData(), structure, Identifier(exec, nativeErrorPrototype->getDirect(exec->propertyNames().name).getString(exec))) , m_errorStructure(ErrorInstance::createStructure(nativeErrorPrototype)) { putDirect(exec->propertyNames().length, jsNumber(exec, 1), DontDelete | ReadOnly | DontEnum); // ECMA 15.11.7.5 diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorConstructor.h index 118d1f4..152dbac 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorConstructor.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorConstructor.h @@ -31,7 +31,7 @@ namespace JSC { class NativeErrorConstructor : public InternalFunction { public: - NativeErrorConstructor(ExecState*, PassRefPtr<Structure>, NativeErrorPrototype*); + NativeErrorConstructor(ExecState*, NonNullPassRefPtr<Structure>, NativeErrorPrototype*); static const ClassInfo info; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorPrototype.cpp index 650a0fd..ca12798 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorPrototype.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorPrototype.cpp @@ -29,7 +29,7 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(NativeErrorPrototype); -NativeErrorPrototype::NativeErrorPrototype(ExecState* exec, PassRefPtr<Structure> structure, const UString& name, const UString& message) +NativeErrorPrototype::NativeErrorPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure, const UString& name, const UString& message) #ifdef QT_BUILD_SCRIPT_LIB : ErrorInstance(structure) #else diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorPrototype.h index 48a9d7e..39a02c8 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorPrototype.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NativeErrorPrototype.h @@ -36,7 +36,7 @@ namespace JSC { #endif { public: - NativeErrorPrototype(ExecState*, PassRefPtr<Structure>, const UString& name, const UString& message); + NativeErrorPrototype(ExecState*, NonNullPassRefPtr<Structure>, const UString& name, const UString& message); }; } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberConstructor.cpp index a95106d..cc6c51d 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberConstructor.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberConstructor.cpp @@ -53,7 +53,7 @@ const ClassInfo NumberConstructor::info = { "Function", &InternalFunction::info, @end */ -NumberConstructor::NumberConstructor(ExecState* exec, PassRefPtr<Structure> structure, NumberPrototype* numberPrototype) +NumberConstructor::NumberConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, NumberPrototype* numberPrototype) : InternalFunction(&exec->globalData(), structure, Identifier(exec, numberPrototype->info.className)) { // Number.Prototype diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberConstructor.h index 710ac86..cf19b6f 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberConstructor.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberConstructor.h @@ -29,7 +29,7 @@ namespace JSC { class NumberConstructor : public InternalFunction { public: - NumberConstructor(ExecState*, PassRefPtr<Structure>, NumberPrototype*); + NumberConstructor(ExecState*, NonNullPassRefPtr<Structure>, NumberPrototype*); virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); @@ -39,11 +39,14 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, ImplementsHasInstance | HasDefaultMark | HasDefaultGetPropertyNames)); + return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); } enum { NaNValue, NegInfinity, PosInfinity, MaxValue, MinValue }; + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | InternalFunction::StructureFlags; + private: virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberObject.cpp index 0e8df17..1a7e44c 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberObject.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberObject.cpp @@ -31,7 +31,7 @@ ASSERT_CLASS_FITS_IN_CELL(NumberObject); const ClassInfo NumberObject::info = { "Number", 0, 0, 0 }; -NumberObject::NumberObject(PassRefPtr<Structure> structure) +NumberObject::NumberObject(NonNullPassRefPtr<Structure> structure) : JSWrapperObject(structure) { } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberObject.h index f502bee..8223a90 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberObject.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberObject.h @@ -27,20 +27,22 @@ namespace JSC { class NumberObject : public JSWrapperObject { public: - explicit NumberObject(PassRefPtr<Structure>); + explicit NumberObject(NonNullPassRefPtr<Structure>); static const ClassInfo info; -#if USE(JSVALUE32) + static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot | HasDefaultGetPropertyNames)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } + + protected: +#if USE(JSVALUE32) + static const unsigned StructureFlags = OverridesMarkChildren | JSWrapperObject::StructureFlags; #else - static PassRefPtr<Structure> createStructure(JSValue prototype) - { - return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot | HasDefaultMark | HasDefaultGetPropertyNames)); - } + static const unsigned StructureFlags = JSWrapperObject::StructureFlags; #endif + private: virtual const ClassInfo* classInfo() const { return &info; } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberPrototype.cpp index 947324c..67210fa 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberPrototype.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberPrototype.cpp @@ -25,9 +25,10 @@ #include "Error.h" #include "JSFunction.h" #include "JSString.h" +#include "Operations.h" #include "PrototypeFunction.h" +#include "StringBuilder.h" #include "dtoa.h" -#include "Operations.h" #include <wtf/Assertions.h> #include <wtf/MathExtras.h> #include <wtf/Vector.h> @@ -45,7 +46,7 @@ static JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*, JSObject*, J // ECMA 15.7.4 -NumberPrototype::NumberPrototype(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) +NumberPrototype::NumberPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) : NumberObject(structure) { setInternalValue(jsNumber(exec, 0)); @@ -73,11 +74,12 @@ static UString integerPartNoExp(double d) bool resultIsInfOrNan = (decimalPoint == 9999); size_t length = strlen(result); - UString str = sign ? "-" : ""; + StringBuilder builder; + builder.append(sign ? "-" : ""); if (resultIsInfOrNan) - str += result; + builder.append((const char*)result); else if (decimalPoint <= 0) - str += "0"; + builder.append("0"); else { Vector<char, 1024> buf(decimalPoint + 1); @@ -89,10 +91,10 @@ static UString integerPartNoExp(double d) strncpy(buf.data(), result, decimalPoint); buf[decimalPoint] = '\0'; - str.append(buf.data()); + builder.append((const char*)(buf.data())); } - return str; + return builder.release(); } static UString charSequence(char c, int count) @@ -236,13 +238,16 @@ JSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec, JSObject*, JSValue UString s; if (x < 0) { - s.append('-'); + s = "-"; x = -x; - } else if (x == -0.0) - x = 0; + } else { + s = ""; + if (x == -0.0) + x = 0; + } if (x >= pow(10.0, 21.0)) - return jsString(exec, s + UString::from(x)); + return jsString(exec, makeString(s, UString::from(x))); const double tenToTheF = pow(10.0, f); double n = floor(x * tenToTheF); @@ -253,17 +258,19 @@ JSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec, JSObject*, JSValue int k = m.size(); if (k <= f) { - UString z; + StringBuilder z; for (int i = 0; i < f + 1 - k; i++) z.append('0'); - m = z + m; + z.append(m); + m = z.release(); k = f + 1; ASSERT(k == m.size()); } int kMinusf = k - f; + if (kMinusf < m.size()) - return jsString(exec, s + m.substr(0, kMinusf) + "." + m.substr(kMinusf)); - return jsString(exec, s + m.substr(0, kMinusf)); + return jsString(exec, makeString(s, m.substr(0, kMinusf), ".", m.substr(kMinusf))); + return jsString(exec, makeString(s, m.substr(0, kMinusf))); } static void fractionalPartToString(char* buf, int& i, const char* result, int resultLength, int fractionalDigits) @@ -391,7 +398,8 @@ JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSV if (x < 0) { s = "-"; x = -x; - } + } else + s = ""; if (!(doublePrecision >= 1 && doublePrecision <= 21)) // true for NaN return throwError(exec, RangeError, "toPrecision() argument must be between 1 and 21"); @@ -422,10 +430,10 @@ JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSV m = integerPartNoExp(n); if (e < -6 || e >= precision) { if (m.size() > 1) - m = m.substr(0, 1) + "." + m.substr(1); + m = makeString(m.substr(0, 1), ".", m.substr(1)); if (e >= 0) - return jsNontrivialString(exec, s + m + "e+" + UString::from(e)); - return jsNontrivialString(exec, s + m + "e-" + UString::from(-e)); + return jsNontrivialString(exec, makeString(s, m, "e+", UString::from(e))); + return jsNontrivialString(exec, makeString(s, m, "e-", UString::from(-e))); } } else { m = charSequence('0', precision); @@ -433,13 +441,13 @@ JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSV } if (e == precision - 1) - return jsString(exec, s + m); + return jsString(exec, makeString(s, m)); if (e >= 0) { if (e + 1 < m.size()) - return jsString(exec, s + m.substr(0, e + 1) + "." + m.substr(e + 1)); - return jsString(exec, s + m); + return jsString(exec, makeString(s, m.substr(0, e + 1), ".", m.substr(e + 1))); + return jsString(exec, makeString(s, m)); } - return jsNontrivialString(exec, s + "0." + charSequence('0', -(e + 1)) + m); + return jsNontrivialString(exec, makeString(s, "0.", charSequence('0', -(e + 1)), m)); } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberPrototype.h index 0a3a544..1fb2077 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberPrototype.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/NumberPrototype.h @@ -27,7 +27,7 @@ namespace JSC { class NumberPrototype : public NumberObject { public: - NumberPrototype(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure); + NumberPrototype(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure); }; } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectConstructor.cpp index 2992f1b..0838eb4 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectConstructor.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectConstructor.cpp @@ -36,12 +36,13 @@ ASSERT_CLASS_FITS_IN_CELL(ObjectConstructor); static JSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*, JSObject*, JSValue, const ArgList&); static JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState*, JSObject*, JSValue, const ArgList&); static JSValue JSC_HOST_CALL objectConstructorKeys(ExecState*, JSObject*, JSValue, const ArgList&); static JSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState*, JSObject*, JSValue, const ArgList&); static JSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState*, JSObject*, JSValue, const ArgList&); static JSValue JSC_HOST_CALL objectConstructorCreate(ExecState*, JSObject*, JSValue, const ArgList&); -ObjectConstructor::ObjectConstructor(ExecState* exec, PassRefPtr<Structure> structure, ObjectPrototype* objectPrototype, Structure* prototypeFunctionStructure) +ObjectConstructor::ObjectConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, ObjectPrototype* objectPrototype, Structure* prototypeFunctionStructure) : InternalFunction(&exec->globalData(), structure, Identifier(exec, "Object")) { // ECMA 15.2.3.1 @@ -52,6 +53,7 @@ ObjectConstructor::ObjectConstructor(ExecState* exec, PassRefPtr<Structure> stru putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().getPrototypeOf, objectConstructorGetPrototypeOf), DontEnum); putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().getOwnPropertyDescriptor, objectConstructorGetOwnPropertyDescriptor), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().getOwnPropertyNames, objectConstructorGetOwnPropertyNames), DontEnum); putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().keys, objectConstructorKeys), DontEnum); putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 3, exec->propertyNames().defineProperty, objectConstructorDefineProperty), DontEnum); putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().defineProperties, objectConstructorDefineProperties), DontEnum); @@ -125,6 +127,21 @@ JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec, return description; } +// FIXME: Use the enumeration cache. +JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + if (!args.at(0).isObject()) + return throwError(exec, TypeError, "Requested property names of a value that is not an object."); + PropertyNameArray properties(exec); + asObject(args.at(0))->getOwnPropertyNames(exec, properties, IncludeDontEnumProperties); + JSArray* names = constructEmptyArray(exec); + size_t numProperties = properties.size(); + for (size_t i = 0; i < numProperties; i++) + names->push(exec, jsOwnedString(exec, properties[i].ustring())); + return names; +} + +// FIXME: Use the enumeration cache. JSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec, JSObject*, JSValue, const ArgList& args) { if (!args.at(0).isObject()) @@ -147,14 +164,14 @@ static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor } JSObject* description = asObject(in); - PropertySlot enumerableSlot; + PropertySlot enumerableSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().enumerable, enumerableSlot)) { desc.setEnumerable(enumerableSlot.getValue(exec, exec->propertyNames().enumerable).toBoolean(exec)); if (exec->hadException()) return false; } - PropertySlot configurableSlot; + PropertySlot configurableSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().configurable, configurableSlot)) { desc.setConfigurable(configurableSlot.getValue(exec, exec->propertyNames().configurable).toBoolean(exec)); if (exec->hadException()) @@ -162,21 +179,21 @@ static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor } JSValue value; - PropertySlot valueSlot; + PropertySlot valueSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().value, valueSlot)) { desc.setValue(valueSlot.getValue(exec, exec->propertyNames().value)); if (exec->hadException()) return false; } - PropertySlot writableSlot; + PropertySlot writableSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().writable, writableSlot)) { desc.setWritable(writableSlot.getValue(exec, exec->propertyNames().writable).toBoolean(exec)); if (exec->hadException()) return false; } - PropertySlot getSlot; + PropertySlot getSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().get, getSlot)) { JSValue get = getSlot.getValue(exec, exec->propertyNames().get); if (exec->hadException()) @@ -192,7 +209,7 @@ static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor desc.setGetter(get); } - PropertySlot setSlot; + PropertySlot setSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().set, setSlot)) { JSValue set = setSlot.getValue(exec, exec->propertyNames().set); if (exec->hadException()) diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectConstructor.h index 9373781..1d2cdde 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectConstructor.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectConstructor.h @@ -29,7 +29,7 @@ namespace JSC { class ObjectConstructor : public InternalFunction { public: - ObjectConstructor(ExecState*, PassRefPtr<Structure>, ObjectPrototype*, Structure* prototypeFunctionStructure); + ObjectConstructor(ExecState*, NonNullPassRefPtr<Structure>, ObjectPrototype*, Structure* prototypeFunctionStructure); private: virtual ConstructType getConstructData(ConstructData&); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectPrototype.cpp index fccc44a..3065c6d 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectPrototype.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectPrototype.cpp @@ -40,7 +40,7 @@ static JSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState*, JSObject*, static JSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState*, JSObject*, JSValue, const ArgList&); static JSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState*, JSObject*, JSValue, const ArgList&); -ObjectPrototype::ObjectPrototype(ExecState* exec, PassRefPtr<Structure> stucture, Structure* prototypeFunctionStructure) +ObjectPrototype::ObjectPrototype(ExecState* exec, NonNullPassRefPtr<Structure> stucture, Structure* prototypeFunctionStructure) : JSObject(stucture) , m_hasNoPropertiesWithUInt32Names(true) { @@ -148,7 +148,7 @@ JSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue JSC_HOST_CALL objectProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - return jsNontrivialString(exec, "[object " + thisValue.toThisObject(exec)->className() + "]"); + return jsNontrivialString(exec, makeString("[object ", thisValue.toThisObject(exec)->className(), "]")); } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectPrototype.h index 6dd3c28..489d962 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectPrototype.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ObjectPrototype.h @@ -27,7 +27,7 @@ namespace JSC { class ObjectPrototype : public JSObject { public: - ObjectPrototype(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure); + ObjectPrototype(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure); private: virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.cpp index 093bbec..0e1887c 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.cpp @@ -29,10 +29,6 @@ #include <stdio.h> #include <wtf/MathExtras.h> -#if HAVE(FLOAT_H) -#include <float.h> -#endif - namespace JSC { bool JSValue::equalSlowCase(ExecState* exec, JSValue v1, JSValue v2) @@ -40,9 +36,9 @@ bool JSValue::equalSlowCase(ExecState* exec, JSValue v1, JSValue v2) return equalSlowCaseInline(exec, v1, v2); } -bool JSValue::strictEqualSlowCase(JSValue v1, JSValue v2) +bool JSValue::strictEqualSlowCase(ExecState* exec, JSValue v1, JSValue v2) { - return strictEqualSlowCaseInline(v1, v2); + return strictEqualSlowCaseInline(exec, v1, v2); } NEVER_INLINE JSValue throwOutOfMemoryError(ExecState* exec) @@ -58,12 +54,13 @@ NEVER_INLINE JSValue jsAddSlowCase(CallFrame* callFrame, JSValue v1, JSValue v2) JSValue p1 = v1.toPrimitive(callFrame); JSValue p2 = v2.toPrimitive(callFrame); - if (p1.isString() || p2.isString()) { - RefPtr<UString::Rep> value = concatenate(p1.toString(callFrame).rep(), p2.toString(callFrame).rep()); - if (!value) - return throwOutOfMemoryError(callFrame); - return jsString(callFrame, value.release()); + if (p1.isString()) { + return p2.isString() + ? jsString(callFrame, asString(p1), asString(p2)) + : jsString(callFrame, asString(p1), p2.toString(callFrame)); } + if (p2.isString()) + return jsString(callFrame, p1.toString(callFrame), asString(p2)); return jsNumber(callFrame, p1.toNumber(callFrame) + p2.toNumber(callFrame)); } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.h index 21120f5..d1d6eaa 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Operations.h @@ -35,6 +35,136 @@ namespace JSC { bool jsIsObjectType(JSValue); bool jsIsFunctionType(JSValue); + ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2) + { + if (!s1->length()) + return s2; + if (!s2->length()) + return s1; + + unsigned ropeLength = s1->ropeLength() + s2->ropeLength(); + JSGlobalData* globalData = &exec->globalData(); + + if (ropeLength <= JSString::s_maxInternalRopeLength) + return new (globalData) JSString(globalData, ropeLength, s1, s2); + + unsigned index = 0; + RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); + if (UNLIKELY(!rope)) + return throwOutOfMemoryError(exec); + rope->append(index, s1); + rope->append(index, s2); + ASSERT(index == ropeLength); + return new (globalData) JSString(globalData, rope.release()); + } + + ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, JSString* s2) + { + unsigned ropeLength = 1 + s2->ropeLength(); + JSGlobalData* globalData = &exec->globalData(); + + if (ropeLength <= JSString::s_maxInternalRopeLength) + return new (globalData) JSString(globalData, ropeLength, u1, s2); + + unsigned index = 0; + RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); + if (UNLIKELY(!rope)) + return throwOutOfMemoryError(exec); + rope->append(index, u1); + rope->append(index, s2); + ASSERT(index == ropeLength); + return new (globalData) JSString(globalData, rope.release()); + } + + ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, const UString& u2) + { + unsigned ropeLength = s1->ropeLength() + 1; + JSGlobalData* globalData = &exec->globalData(); + + if (ropeLength <= JSString::s_maxInternalRopeLength) + return new (globalData) JSString(globalData, ropeLength, s1, u2); + + unsigned index = 0; + RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); + if (UNLIKELY(!rope)) + return throwOutOfMemoryError(exec); + rope->append(index, s1); + rope->append(index, u2); + ASSERT(index == ropeLength); + return new (globalData) JSString(globalData, rope.release()); + } + + ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count) + { + ASSERT(count >= 3); + + unsigned ropeLength = 0; + for (unsigned i = 0; i < count; ++i) { + JSValue v = strings[i].jsValue(); + if (LIKELY(v.isString())) + ropeLength += asString(v)->ropeLength(); + else + ++ropeLength; + } + + JSGlobalData* globalData = &exec->globalData(); + if (ropeLength == 3) + return new (globalData) JSString(exec, strings[0].jsValue(), strings[1].jsValue(), strings[2].jsValue()); + + RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); + if (UNLIKELY(!rope)) + return throwOutOfMemoryError(exec); + + unsigned index = 0; + for (unsigned i = 0; i < count; ++i) { + JSValue v = strings[i].jsValue(); + if (LIKELY(v.isString())) + rope->append(index, asString(v)); + else + rope->append(index, v.toString(exec)); + } + + ASSERT(index == ropeLength); + return new (globalData) JSString(globalData, rope.release()); + } + + ALWAYS_INLINE JSValue jsString(ExecState* exec, JSValue thisValue, const ArgList& args) + { + unsigned ropeLength = 0; + if (LIKELY(thisValue.isString())) + ropeLength += asString(thisValue)->ropeLength(); + else + ++ropeLength; + for (unsigned i = 0; i < args.size(); ++i) { + JSValue v = args.at(i); + if (LIKELY(v.isString())) + ropeLength += asString(v)->ropeLength(); + else + ++ropeLength; + } + + RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); + if (UNLIKELY(!rope)) + return throwOutOfMemoryError(exec); + + unsigned index = 0; + if (LIKELY(thisValue.isString())) + rope->append(index, asString(thisValue)); + else + rope->append(index, thisValue.toString(exec)); + for (unsigned i = 0; i < args.size(); ++i) { + JSValue v = args.at(i); + if (LIKELY(v.isString())) + rope->append(index, asString(v)); + else + rope->append(index, v.toString(exec)); + } + ASSERT(index == ropeLength); + + JSGlobalData* globalData = &exec->globalData(); + return new (globalData) JSString(globalData, rope.release()); + } + // ECMA 11.9.3 inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2) { @@ -53,7 +183,7 @@ namespace JSC { bool s1 = v1.isString(); bool s2 = v2.isString(); if (s1 && s2) - return asString(v1)->value() == asString(v2)->value(); + return asString(v1)->value(exec) == asString(v2)->value(exec); if (v1.isUndefinedOrNull()) { if (v2.isUndefinedOrNull()) @@ -70,13 +200,12 @@ namespace JSC { } if (v1.isObject()) { - if (v2.isObject()) { + if (v2.isObject()) return v1 == v2 #ifdef QT_BUILD_SCRIPT_LIB || asObject(v1)->compareToObject(exec, asObject(v2)) #endif ; - } JSValue p1 = v1.toPrimitive(exec); if (exec->hadException()) return false; @@ -115,17 +244,17 @@ namespace JSC { } // ECMA 11.9.3 - ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(JSValue v1, JSValue v2) + ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2) { ASSERT(v1.isCell() && v2.isCell()); if (v1.asCell()->isString() && v2.asCell()->isString()) - return asString(v1)->value() == asString(v2)->value(); + return asString(v1)->value(exec) == asString(v2)->value(exec); return v1 == v2; } - inline bool JSValue::strictEqual(JSValue v1, JSValue v2) + inline bool JSValue::strictEqual(ExecState* exec, JSValue v1, JSValue v2) { if (v1.isInt32() && v2.isInt32()) return v1 == v2; @@ -136,10 +265,10 @@ namespace JSC { if (!v1.isCell() || !v2.isCell()) return v1 == v2; - return strictEqualSlowCaseInline(v1, v2); + return strictEqualSlowCaseInline(exec, v1, v2); } - inline bool jsLess(CallFrame* callFrame, JSValue v1, JSValue v2) + ALWAYS_INLINE bool jsLess(CallFrame* callFrame, JSValue v1, JSValue v2) { if (v1.isInt32() && v2.isInt32()) return v1.asInt32() < v2.asInt32(); @@ -151,7 +280,7 @@ namespace JSC { JSGlobalData* globalData = &callFrame->globalData(); if (isJSString(globalData, v1) && isJSString(globalData, v2)) - return asString(v1)->value() < asString(v2)->value(); + return asString(v1)->value(callFrame) < asString(v2)->value(callFrame); JSValue p1; JSValue p2; @@ -161,7 +290,7 @@ namespace JSC { if (wasNotString1 | wasNotString2) return n1 < n2; - return asString(p1)->value() < asString(p2)->value(); + return asString(p1)->value(callFrame) < asString(p2)->value(callFrame); } inline bool jsLessEq(CallFrame* callFrame, JSValue v1, JSValue v2) @@ -176,7 +305,7 @@ namespace JSC { JSGlobalData* globalData = &callFrame->globalData(); if (isJSString(globalData, v1) && isJSString(globalData, v2)) - return !(asString(v2)->value() < asString(v1)->value()); + return !(asString(v2)->value(callFrame) < asString(v1)->value(callFrame)); JSValue p1; JSValue p2; @@ -186,7 +315,7 @@ namespace JSC { if (wasNotString1 | wasNotString2) return n1 <= n2; - return !(asString(p2)->value() < asString(p1)->value()); + return !(asString(p2)->value(callFrame) < asString(p1)->value(callFrame)); } // Fast-path choices here are based on frequency data from SunSpider: @@ -200,44 +329,29 @@ namespace JSC { ALWAYS_INLINE JSValue jsAdd(CallFrame* callFrame, JSValue v1, JSValue v2) { - double left; - double right = 0.0; - - bool rightIsNumber = v2.getNumber(right); - if (rightIsNumber && v1.getNumber(left)) + double left = 0.0, right; + if (v1.getNumber(left) && v2.getNumber(right)) return jsNumber(callFrame, left + right); - bool leftIsString = v1.isString(); - if (leftIsString && v2.isString()) { - RefPtr<UString::Rep> value = concatenate(asString(v1)->value().rep(), asString(v2)->value().rep()); - if (!value) - return throwOutOfMemoryError(callFrame); - return jsString(callFrame, value.release()); - } - - if (rightIsNumber & leftIsString) { - RefPtr<UString::Rep> value = v2.isInt32() ? - concatenate(asString(v1)->value().rep(), v2.asInt32()) : - concatenate(asString(v1)->value().rep(), right); - - if (!value) - return throwOutOfMemoryError(callFrame); - return jsString(callFrame, value.release()); + if (v1.isString()) { + return v2.isString() + ? jsString(callFrame, asString(v1), asString(v2)) + : jsString(callFrame, asString(v1), v2.toPrimitiveString(callFrame)); } // All other cases are pretty uncommon return jsAddSlowCase(callFrame, v1, v2); } - inline size_t countPrototypeChainEntriesAndCheckForProxies(CallFrame* callFrame, JSValue baseValue, const PropertySlot& slot) + inline size_t normalizePrototypeChain(CallFrame* callFrame, JSValue base, JSValue slotBase, const Identifier& propertyName, size_t& slotOffset) { - JSCell* cell = asCell(baseValue); + JSCell* cell = asCell(base); size_t count = 0; - while (slot.slotBase() != cell) { + while (slotBase != cell) { JSValue v = cell->structure()->prototypeForLookup(callFrame); - // If we didn't find slotBase in baseValue's prototype chain, then baseValue + // If we didn't find slotBase in base's prototype chain, then base // must be a proxy for another object. if (v.isNull()) @@ -247,8 +361,11 @@ namespace JSC { // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. - if (cell->structure()->isDictionary()) - asObject(cell)->setStructure(Structure::fromDictionaryTransition(cell->structure())); + if (cell->structure()->isDictionary()) { + asObject(cell)->flattenDictionaryObject(); + if (slotBase == cell) + slotOffset = cell->structure()->get(propertyName); + } ++count; } @@ -257,6 +374,25 @@ namespace JSC { return count; } + inline size_t normalizePrototypeChain(CallFrame* callFrame, JSCell* base) + { + size_t count = 0; + while (1) { + JSValue v = base->structure()->prototypeForLookup(callFrame); + if (v.isNull()) + return count; + + base = asCell(v); + + // Since we're accessing a prototype in a loop, it's a good bet that it + // should not be treated as a dictionary. + if (base->structure()->isDictionary()) + asObject(base)->flattenDictionaryObject(); + + ++count; + } + } + ALWAYS_INLINE JSValue resolveBase(CallFrame* callFrame, Identifier& property, ScopeChainNode* scopeChain) { ScopeChainIterator iter = scopeChain->begin(); @@ -279,52 +415,6 @@ namespace JSC { ASSERT_NOT_REACHED(); return JSValue(); } - - ALWAYS_INLINE JSValue concatenateStrings(CallFrame* callFrame, Register* strings, unsigned count) - { - ASSERT(count >= 3); - - // Estimate the amount of space required to hold the entire string. If all - // arguments are strings, we can easily calculate the exact amount of space - // required. For any other arguments, for now let's assume they may require - // 11 UChars of storage. This is enouch to hold any int, and likely is also - // reasonable for the other immediates. We may want to come back and tune - // this value at some point. - unsigned bufferSize = 0; - for (unsigned i = 0; i < count; ++i) { - JSValue v = strings[i].jsValue(); - if (LIKELY(v.isString())) - bufferSize += asString(v)->value().size(); - else - bufferSize += 11; - } - - // Allocate an output string to store the result. - // If the first argument is a String, and if it has the capacity (or can grow - // its capacity) to hold the entire result then use this as a base to concatenate - // onto. Otherwise, allocate a new empty output buffer. - JSValue firstValue = strings[0].jsValue(); - RefPtr<UString::Rep> resultRep; - if (firstValue.isString() && (resultRep = asString(firstValue)->value().rep())->reserveCapacity(bufferSize)) { - // We're going to concatenate onto the first string - remove it from the list of items to be appended. - ++strings; - --count; - } else - resultRep = UString::Rep::createEmptyBuffer(bufferSize); - UString result(resultRep); - - // Loop over the operands, writing them into the output buffer. - for (unsigned i = 0; i < count; ++i) { - JSValue v = strings[i].jsValue(); - if (LIKELY(v.isString())) - result.append(asString(v)->value()); - else - result.append(v.toString(callFrame)); - } - - return jsString(callFrame, result); - } - } // namespace JSC #endif // Operations_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyDescriptor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyDescriptor.cpp index 4db814f..558ae28 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyDescriptor.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyDescriptor.cpp @@ -153,15 +153,15 @@ void PropertyDescriptor::setGetter(JSValue getter) m_attributes &= ~ReadOnly; } -bool PropertyDescriptor::equalTo(const PropertyDescriptor& other) const +bool PropertyDescriptor::equalTo(ExecState* exec, const PropertyDescriptor& other) const { if (!other.m_value == m_value || !other.m_getter == m_getter || !other.m_setter == m_setter) return false; - return (!m_value || JSValue::strictEqual(other.m_value, m_value)) && - (!m_getter || JSValue::strictEqual(other.m_getter, m_getter)) && - (!m_setter || JSValue::strictEqual(other.m_setter, m_setter)) && + return (!m_value || JSValue::strictEqual(exec, other.m_value, m_value)) && + (!m_getter || JSValue::strictEqual(exec, other.m_getter, m_getter)) && + (!m_setter || JSValue::strictEqual(exec, other.m_setter, m_setter)) && attributesEqual(other); } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyDescriptor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyDescriptor.h index 40bec86..ff9f160 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyDescriptor.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyDescriptor.h @@ -61,7 +61,7 @@ namespace JSC { bool configurablePresent() const { return m_seenAttributes & ConfigurablePresent; } bool setterPresent() const { return m_setter; } bool getterPresent() const { return m_getter; } - bool equalTo(const PropertyDescriptor& other) const; + bool equalTo(ExecState* exec, const PropertyDescriptor& other) const; bool attributesEqual(const PropertyDescriptor& other) const; unsigned attributesWithOverride(const PropertyDescriptor& other) const; private: diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyNameArray.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyNameArray.cpp index 0878e73..5108272 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyNameArray.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyNameArray.cpp @@ -21,13 +21,16 @@ #include "config.h" #include "PropertyNameArray.h" +#include "Structure.h" +#include "StructureChain.h" + namespace JSC { static const size_t setThreshold = 20; void PropertyNameArray::add(UString::Rep* identifier) { - ASSERT(identifier == &UString::Rep::null() || identifier == &UString::Rep::empty() || identifier->identifierTable()); + ASSERT(identifier == &UString::Rep::null() || identifier == &UString::Rep::empty() || identifier->isIdentifier()); size_t size = m_data->propertyNameVector().size(); if (size < setThreshold) { @@ -44,7 +47,7 @@ void PropertyNameArray::add(UString::Rep* identifier) return; } - m_data->propertyNameVector().append(Identifier(m_globalData, identifier)); + addKnownUnique(identifier); } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyNameArray.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyNameArray.h index 67ee9c8..3dbcc9d 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyNameArray.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PropertyNameArray.h @@ -23,46 +23,35 @@ #include "CallFrame.h" #include "Identifier.h" -#include "Structure.h" -#include "StructureChain.h" #include <wtf/HashSet.h> +#include <wtf/OwnArrayPtr.h> #include <wtf/Vector.h> namespace JSC { + + class Structure; + class StructureChain; + // FIXME: Rename to PropertyNameArray. class PropertyNameArrayData : public RefCounted<PropertyNameArrayData> { public: typedef Vector<Identifier, 20> PropertyNameVector; - typedef PropertyNameVector::const_iterator const_iterator; static PassRefPtr<PropertyNameArrayData> create() { return adoptRef(new PropertyNameArrayData); } - const_iterator begin() const { return m_propertyNameVector.begin(); } - const_iterator end() const { return m_propertyNameVector.end(); } - PropertyNameVector& propertyNameVector() { return m_propertyNameVector; } - void setCachedStructure(Structure* structure) { m_cachedStructure = structure; } - Structure* cachedStructure() const { return m_cachedStructure; } - - void setCachedPrototypeChain(PassRefPtr<StructureChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; } - StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); } - private: PropertyNameArrayData() - : m_cachedStructure(0) { } PropertyNameVector m_propertyNameVector; - Structure* m_cachedStructure; - RefPtr<StructureChain> m_cachedPrototypeChain; }; + // FIXME: Rename to PropertyNameArrayBuilder. class PropertyNameArray { public: - typedef PropertyNameArrayData::const_iterator const_iterator; - PropertyNameArray(JSGlobalData* globalData) : m_data(PropertyNameArrayData::create()) , m_globalData(globalData) @@ -83,21 +72,18 @@ namespace JSC { void add(UString::Rep*); void addKnownUnique(UString::Rep* identifier) { m_data->propertyNameVector().append(Identifier(m_globalData, identifier)); } - size_t size() const { return m_data->propertyNameVector().size(); } - Identifier& operator[](unsigned i) { return m_data->propertyNameVector()[i]; } const Identifier& operator[](unsigned i) const { return m_data->propertyNameVector()[i]; } - const_iterator begin() const { return m_data->begin(); } - const_iterator end() const { return m_data->end(); } - void setData(PassRefPtr<PropertyNameArrayData> data) { m_data = data; } PropertyNameArrayData* data() { return m_data.get(); } - PassRefPtr<PropertyNameArrayData> releaseData() { return m_data.release(); } - void setShouldCache(bool shouldCache) { m_shouldCache = shouldCache; } - bool shouldCache() const { return m_shouldCache; } + // FIXME: Remove these functions. + typedef PropertyNameArrayData::PropertyNameVector::const_iterator const_iterator; + size_t size() const { return m_data->propertyNameVector().size(); } + const_iterator begin() const { return m_data->propertyNameVector().begin(); } + const_iterator end() const { return m_data->propertyNameVector().end(); } private: typedef HashSet<UString::Rep*, PtrHash<UString::Rep*> > IdentifierSet; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Protect.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Protect.h index 6e7984c..c2d7f0c 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Protect.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Protect.h @@ -22,8 +22,8 @@ #ifndef Protect_h #define Protect_h -#include "JSCell.h" #include "Collector.h" +#include "JSValue.h" namespace JSC { diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PrototypeFunction.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PrototypeFunction.cpp index 8e3d107..38f8adb 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PrototypeFunction.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PrototypeFunction.cpp @@ -40,7 +40,7 @@ PrototypeFunction::PrototypeFunction(ExecState* exec, int length, const Identifi putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum); } -PrototypeFunction::PrototypeFunction(ExecState* exec, PassRefPtr<Structure> prototypeFunctionStructure, int length, const Identifier& name, NativeFunction function) +PrototypeFunction::PrototypeFunction(ExecState* exec, NonNullPassRefPtr<Structure> prototypeFunctionStructure, int length, const Identifier& name, NativeFunction function) : InternalFunction(&exec->globalData(), prototypeFunctionStructure, name) , m_function(function) { diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PrototypeFunction.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PrototypeFunction.h index 99ab327..70ee034 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PrototypeFunction.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/PrototypeFunction.h @@ -32,7 +32,7 @@ namespace JSC { class PrototypeFunction : public InternalFunction { public: PrototypeFunction(ExecState*, int length, const Identifier&, NativeFunction); - PrototypeFunction(ExecState*, PassRefPtr<Structure>, int length, const Identifier&, NativeFunction); + PrototypeFunction(ExecState*, NonNullPassRefPtr<Structure>, int length, const Identifier&, NativeFunction); private: virtual CallType getCallData(CallData&); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExp.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExp.cpp index b366b58..430a5c0 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExp.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExp.cpp @@ -65,7 +65,6 @@ inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern) inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern, const UString& flags) : m_pattern(pattern) - , m_flags(flags) , m_flagBits(0) , m_constructionError(0) , m_numSubpatterns(0) diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExp.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExp.h index 24d4199..61ab0bc 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExp.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExp.h @@ -49,7 +49,6 @@ namespace JSC { bool multiline() const { return m_flagBits & Multiline; } const UString& pattern() const { return m_pattern; } - const UString& flags() const { return m_flags; } bool isValid() const { return !m_constructionError; } const char* errorMessage() const { return m_constructionError; } @@ -66,7 +65,6 @@ namespace JSC { enum FlagBits { Global = 1, IgnoreCase = 2, Multiline = 4 }; UString m_pattern; // FIXME: Just decompile m_regExp instead of storing this. - UString m_flags; // FIXME: Just decompile m_regExp instead of storing this. int m_flagBits; const char* m_constructionError; unsigned m_numSubpatterns; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpConstructor.cpp index 1c95175..6f00142 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpConstructor.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpConstructor.cpp @@ -90,29 +90,7 @@ const ClassInfo RegExpConstructor::info = { "Function", &InternalFunction::info, @end */ -struct RegExpConstructorPrivate : FastAllocBase { - // Global search cache / settings - RegExpConstructorPrivate() - : lastNumSubPatterns(0) - , multiline(false) - , lastOvectorIndex(0) - { - } - - const Vector<int, 32>& lastOvector() const { return ovector[lastOvectorIndex]; } - Vector<int, 32>& lastOvector() { return ovector[lastOvectorIndex]; } - Vector<int, 32>& tempOvector() { return ovector[lastOvectorIndex ? 0 : 1]; } - void changeLastOvector() { lastOvectorIndex = lastOvectorIndex ? 0 : 1; } - - UString input; - UString lastInput; - Vector<int, 32> ovector[2]; - unsigned lastNumSubPatterns : 30; - bool multiline : 1; - unsigned lastOvectorIndex : 1; -}; - -RegExpConstructor::RegExpConstructor(ExecState* exec, PassRefPtr<Structure> structure, RegExpPrototype* regExpPrototype) +RegExpConstructor::RegExpConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, RegExpPrototype* regExpPrototype) : InternalFunction(&exec->globalData(), structure, Identifier(exec, "RegExp")) , d(new RegExpConstructorPrivate) { @@ -123,30 +101,6 @@ RegExpConstructor::RegExpConstructor(ExecState* exec, PassRefPtr<Structure> stru putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly | DontDelete | DontEnum); } -/* - To facilitate result caching, exec(), test(), match(), search(), and replace() dipatch regular - expression matching through the performMatch function. We use cached results to calculate, - e.g., RegExp.lastMatch and RegExp.leftParen. -*/ -void RegExpConstructor::performMatch(RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector) -{ - position = r->match(s, startOffset, &d->tempOvector()); - - if (ovector) - *ovector = d->tempOvector().data(); - - if (position != -1) { - ASSERT(!d->tempOvector().isEmpty()); - - length = d->tempOvector()[1] - d->tempOvector()[0]; - - d->input = s; - d->lastInput = s; - d->changeLastOvector(); - d->lastNumSubPatterns = r->numSubpatterns(); - } -} - RegExpMatchesArray::RegExpMatchesArray(ExecState* exec, RegExpConstructorPrivate* data) : JSArray(exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), data->lastNumSubPatterns + 1) { @@ -178,6 +132,8 @@ void RegExpMatchesArray::fillArrayInstance(ExecState* exec) int start = d->lastOvector()[2 * i]; if (start >= 0) JSArray::put(exec, i, jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start)); + else + JSArray::put(exec, i, jsUndefined()); } PutPropertySlot slot; @@ -346,7 +302,7 @@ JSObject* constructRegExp(ExecState* exec, const ArgList& args) RefPtr<RegExp> regExp = RegExp::create(&exec->globalData(), pattern, flags); if (!regExp->isValid()) - return throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage())); + return throwError(exec, SyntaxError, makeString("Invalid regular expression: ", regExp->errorMessage())); return new (exec) RegExpObject(exec->lexicalGlobalObject()->regExpStructure(), regExp.release()); } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpConstructor.h index 4b06b51..f9ca9cf 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpConstructor.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpConstructor.h @@ -22,6 +22,7 @@ #define RegExpConstructor_h #include "InternalFunction.h" +#include "RegExp.h" #include <wtf/OwnPtr.h> namespace JSC { @@ -30,13 +31,35 @@ namespace JSC { class RegExpPrototype; struct RegExpConstructorPrivate; + struct RegExpConstructorPrivate : FastAllocBase { + // Global search cache / settings + RegExpConstructorPrivate() + : lastNumSubPatterns(0) + , multiline(false) + , lastOvectorIndex(0) + { + } + + const Vector<int, 32>& lastOvector() const { return ovector[lastOvectorIndex]; } + Vector<int, 32>& lastOvector() { return ovector[lastOvectorIndex]; } + Vector<int, 32>& tempOvector() { return ovector[lastOvectorIndex ? 0 : 1]; } + void changeLastOvector() { lastOvectorIndex = lastOvectorIndex ? 0 : 1; } + + UString input; + UString lastInput; + Vector<int, 32> ovector[2]; + unsigned lastNumSubPatterns : 30; + bool multiline : 1; + unsigned lastOvectorIndex : 1; + }; + class RegExpConstructor : public InternalFunction { public: - RegExpConstructor(ExecState*, PassRefPtr<Structure>, RegExpPrototype*); + RegExpConstructor(ExecState*, NonNullPassRefPtr<Structure>, RegExpPrototype*); static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, ImplementsHasInstance | HasDefaultMark | HasDefaultGetPropertyNames)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); @@ -59,6 +82,9 @@ namespace JSC { JSValue getLeftContext(ExecState*) const; JSValue getRightContext(ExecState*) const; + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | InternalFunction::StructureFlags; + private: virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); @@ -78,6 +104,30 @@ namespace JSC { return static_cast<RegExpConstructor*>(asObject(value)); } + /* + To facilitate result caching, exec(), test(), match(), search(), and replace() dipatch regular + expression matching through the performMatch function. We use cached results to calculate, + e.g., RegExp.lastMatch and RegExp.leftParen. + */ + inline void RegExpConstructor::performMatch(RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector) + { + position = r->match(s, startOffset, &d->tempOvector()); + + if (ovector) + *ovector = d->tempOvector().data(); + + if (position != -1) { + ASSERT(!d->tempOvector().isEmpty()); + + length = d->tempOvector()[1] - d->tempOvector()[0]; + + d->input = s; + d->lastInput = s; + d->changeLastOvector(); + d->lastNumSubPatterns = r->numSubpatterns(); + } + } + } // namespace JSC #endif // RegExpConstructor_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpMatchesArray.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpMatchesArray.h index c1a5a25..38d3cb4 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpMatchesArray.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpMatchesArray.h @@ -65,25 +65,25 @@ namespace JSC { JSArray::put(exec, propertyName, v); } - virtual bool deleteProperty(ExecState* exec, const Identifier& propertyName, bool checkDontDelete = true) + virtual bool deleteProperty(ExecState* exec, const Identifier& propertyName) { if (lazyCreationData()) fillArrayInstance(exec); - return JSArray::deleteProperty(exec, propertyName, checkDontDelete); + return JSArray::deleteProperty(exec, propertyName); } - virtual bool deleteProperty(ExecState* exec, unsigned propertyName, bool checkDontDelete = true) + virtual bool deleteProperty(ExecState* exec, unsigned propertyName) { if (lazyCreationData()) fillArrayInstance(exec); - return JSArray::deleteProperty(exec, propertyName, checkDontDelete); + return JSArray::deleteProperty(exec, propertyName); } - virtual void getOwnPropertyNames(ExecState* exec, PropertyNameArray& arr, bool includeNonEnumerable = false) + virtual void getOwnPropertyNames(ExecState* exec, PropertyNameArray& arr, EnumerationMode mode = ExcludeDontEnumProperties) { if (lazyCreationData()) fillArrayInstance(exec); - JSArray::getOwnPropertyNames(exec, arr, includeNonEnumerable); + JSArray::getOwnPropertyNames(exec, arr, mode); } void fillArrayInstance(ExecState*); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpObject.cpp index 9d9dd7d..42bfcef 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpObject.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpObject.cpp @@ -57,7 +57,7 @@ const ClassInfo RegExpObject::info = { "RegExp", 0, 0, ExecState::regExpTable }; @end */ -RegExpObject::RegExpObject(PassRefPtr<Structure> structure, PassRefPtr<RegExp> regExp) +RegExpObject::RegExpObject(NonNullPassRefPtr<Structure> structure, NonNullPassRefPtr<RegExp> regExp) : JSObject(structure) , d(new RegExpObjectData(regExp, 0)) { @@ -142,7 +142,7 @@ bool RegExpObject::match(ExecState* exec, const ArgList& args) UString input = args.isEmpty() ? regExpConstructor->input() : args.at(0).toString(exec); if (input.isNull()) { - throwError(exec, GeneralError, "No input to " + toString(exec) + "."); + throwError(exec, GeneralError, makeString("No input to ", toString(exec), ".")); return false; } @@ -159,7 +159,7 @@ bool RegExpObject::match(ExecState* exec, const ArgList& args) } int position; - int length; + int length = 0; regExpConstructor->performMatch(d->regExp.get(), input, static_cast<int>(d->lastIndex), position, length); if (position < 0) { d->lastIndex = 0; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpObject.h index 67113b6..3117c86 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpObject.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpObject.h @@ -28,7 +28,7 @@ namespace JSC { class RegExpObject : public JSObject { public: - RegExpObject(PassRefPtr<Structure>, PassRefPtr<RegExp>); + RegExpObject(NonNullPassRefPtr<Structure>, NonNullPassRefPtr<RegExp>); virtual ~RegExpObject(); void setRegExp(PassRefPtr<RegExp> r) { d->regExp = r; } @@ -49,16 +49,19 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, HasDefaultMark | HasDefaultGetPropertyNames)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags; + private: bool match(ExecState*, const ArgList&); virtual CallType getCallData(CallData&); struct RegExpObjectData : FastAllocBase { - RegExpObjectData(PassRefPtr<RegExp> regExp, double lastIndex) + RegExpObjectData(NonNullPassRefPtr<RegExp> regExp, double lastIndex) : regExp(regExp) , lastIndex(lastIndex) { diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpPrototype.cpp index 4714171..5f9d357 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpPrototype.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpPrototype.cpp @@ -46,7 +46,7 @@ static JSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*, JSObject*, JSVa const ClassInfo RegExpPrototype::info = { "RegExpPrototype", 0, 0, 0 }; -RegExpPrototype::RegExpPrototype(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) +RegExpPrototype::RegExpPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) : JSObject(structure) { putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().compile, regExpProtoFuncCompile), DontEnum); @@ -91,7 +91,7 @@ JSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec, JSObject*, JSValue } if (!regExp->isValid()) - return throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage())); + return throwError(exec, SyntaxError, makeString("Invalid regular expression: ", regExp->errorMessage())); asRegExpObject(thisValue)->setRegExp(regExp.release()); asRegExpObject(thisValue)->setLastIndex(0); @@ -106,19 +106,17 @@ JSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec, JSObject*, JSValu return throwError(exec, TypeError); } - UString result = "/" + asRegExpObject(thisValue)->get(exec, exec->propertyNames().source).toString(exec); -#ifdef QT_BUILD_SCRIPT_LIB - if (result.size() == 1) - result.append("(?:)"); -#endif - result.append('/'); + char postfix[5] = { '/', 0, 0, 0, 0 }; + int index = 1; if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().global).toBoolean(exec)) - result.append('g'); + postfix[index++] = 'g'; if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().ignoreCase).toBoolean(exec)) - result.append('i'); + postfix[index++] = 'i'; if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().multiline).toBoolean(exec)) - result.append('m'); - return jsNontrivialString(exec, result); + postfix[index] = 'm'; + UString source = asRegExpObject(thisValue)->get(exec, exec->propertyNames().source).toString(exec); + // If source is empty, use "/(?:)/" to avoid colliding with comment syntax + return jsNontrivialString(exec, makeString("/", source.size() ? source : UString("(?:)"), postfix)); } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpPrototype.h index f5db720..d3979bd 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpPrototype.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/RegExpPrototype.h @@ -27,7 +27,7 @@ namespace JSC { class RegExpPrototype : public JSObject { public: - RegExpPrototype(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure); + RegExpPrototype(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure); virtual const ClassInfo* classInfo() const { return &info; } static const ClassInfo info; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChain.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChain.cpp index 960c525..981794b 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChain.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChain.cpp @@ -36,8 +36,8 @@ void ScopeChainNode::print() const ScopeChainIterator scopeEnd = end(); for (ScopeChainIterator scopeIter = begin(); scopeIter != scopeEnd; ++scopeIter) { JSObject* o = *scopeIter; - PropertyNameArray propertyNames(globalObject()->globalExec()); - o->getPropertyNames(globalObject()->globalExec(), propertyNames); + PropertyNameArray propertyNames(globalObject->globalExec()); + o->getPropertyNames(globalObject->globalExec(), propertyNames); PropertyNameArray::const_iterator propEnd = propertyNames.end(); fprintf(stderr, "----- [scope %p] -----\n", o); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChain.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChain.h index c5e16c9..0b15b67 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChain.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/ScopeChain.h @@ -33,14 +33,16 @@ namespace JSC { class ScopeChainNode : public FastAllocBase { public: - ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSObject* globalThis) + ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis) : next(next) , object(object) , globalData(globalData) + , globalObject(globalObject) , globalThis(globalThis) , refCount(1) { ASSERT(globalData); + ASSERT(globalObject); } #ifndef NDEBUG // Due to the number of subtle and timing dependent bugs that have occurred due @@ -51,6 +53,7 @@ namespace JSC { next = 0; object = 0; globalData = 0; + globalObject = 0; globalThis = 0; } #endif @@ -58,6 +61,7 @@ namespace JSC { ScopeChainNode* next; JSObject* object; JSGlobalData* globalData; + JSGlobalObject* globalObject; JSObject* globalThis; int refCount; @@ -82,9 +86,6 @@ namespace JSC { ScopeChainIterator begin() const; ScopeChainIterator end() const; - JSGlobalObject* globalObject() const; // defined in JSGlobalObject.h - JSObject* globalThisObject() const { return globalThis; } - #ifndef NDEBUG void print() const; #endif @@ -93,7 +94,7 @@ namespace JSC { inline ScopeChainNode* ScopeChainNode::push(JSObject* o) { ASSERT(o); - return new ScopeChainNode(this, o, globalData, globalThis); + return new ScopeChainNode(this, o, globalData, globalObject, globalThis); } inline ScopeChainNode* ScopeChainNode::pop() @@ -163,8 +164,8 @@ namespace JSC { { } - ScopeChain(JSObject* o, JSGlobalData* globalData, JSObject* globalThis) - : m_node(new ScopeChainNode(0, o, globalData, globalThis)) + ScopeChain(JSObject* o, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis) + : m_node(new ScopeChainNode(0, o, globalData, globalObject, globalThis)) { } @@ -203,7 +204,7 @@ namespace JSC { void pop() { m_node = m_node->pop(); } void clear() { m_node->deref(); m_node = 0; } - JSGlobalObject* globalObject() const { return m_node->globalObject(); } + JSGlobalObject* globalObject() const { return m_node->globalObject; } void markAggregate(MarkStack&) const; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/SmallStrings.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/SmallStrings.cpp index 04701cb..ac71735 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/SmallStrings.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/SmallStrings.cpp @@ -41,30 +41,16 @@ public: UString::Rep* rep(unsigned char character) { return &m_reps[character]; } private: - UChar m_characters[numCharactersToStore]; - UString::BaseString m_base; UString::Rep m_reps[numCharactersToStore]; }; SmallStringsStorage::SmallStringsStorage() - : m_base(m_characters, numCharactersToStore) { - m_base.rc = numCharactersToStore + 1; - // make sure UString doesn't try to reuse the buffer by pretending we have one more character in it - m_base.usedCapacity = numCharactersToStore + 1; - m_base.capacity = numCharactersToStore + 1; - m_base.checkConsistency(); - - for (unsigned i = 0; i < numCharactersToStore; ++i) - m_characters[i] = i; - - memset(&m_reps, 0, sizeof(m_reps)); + UChar* characterBuffer = 0; + RefPtr<UStringImpl> baseString = UStringImpl::createUninitialized(numCharactersToStore, characterBuffer); for (unsigned i = 0; i < numCharactersToStore; ++i) { - m_reps[i].offset = i; - m_reps[i].len = 1; - m_reps[i].rc = 1; - m_reps[i].setBaseString(&m_base); - m_reps[i].checkConsistency(); + characterBuffer[i] = i; + new (&m_reps[i]) UString::Rep(&characterBuffer[i], 1, PassRefPtr<UStringImpl>(baseString)); } } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringBuilder.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringBuilder.h new file mode 100644 index 0000000..8e18d37 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringBuilder.h @@ -0,0 +1,81 @@ +/* + * 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 StringBuilder_h +#define StringBuilder_h + +#include <wtf/Vector.h> + +namespace JSC { + +class StringBuilder { +public: + void append(const UChar u) + { + buffer.append(u); + } + + void append(const char* str) + { + buffer.append(str, strlen(str)); + } + + void append(const char* str, size_t len) + { + buffer.reserveCapacity(buffer.size() + len); + for (size_t i = 0; i < len; i++) + buffer.append(static_cast<unsigned char>(str[i])); + } + + void append(const UChar* str, size_t len) + { + buffer.append(str, len); + } + + void append(const UString& str) + { + buffer.append(str.data(), str.size()); + } + + bool isEmpty() { return buffer.isEmpty(); } + void reserveCapacity(size_t newCapacity) { buffer.reserveCapacity(newCapacity); } + void resize(size_t size) { buffer.resize(size); } + size_t size() const { return buffer.size(); } + + UChar operator[](size_t i) const { return buffer.at(i); } + + UString release() + { + buffer.shrinkToFit(); + return UString::adopt(buffer); + } + +private: + Vector<UChar, 64> buffer; +}; + +} + +#endif diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringConstructor.cpp index 6380445..c7b62bf 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringConstructor.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringConstructor.cpp @@ -30,12 +30,12 @@ namespace JSC { static NEVER_INLINE JSValue stringFromCharCodeSlowCase(ExecState* exec, const ArgList& args) { - UChar* buf = static_cast<UChar*>(fastMalloc(args.size() * sizeof(UChar))); - UChar* p = buf; - ArgList::const_iterator end = args.end(); - for (ArgList::const_iterator it = args.begin(); it != end; ++it) - *p++ = static_cast<UChar>((*it).toUInt32(exec)); - return jsString(exec, UString(buf, p - buf, false)); + unsigned length = args.size(); + UChar* buf; + PassRefPtr<UStringImpl> impl = UStringImpl::createUninitialized(length, buf); + for (unsigned i = 0; i < length; ++i) + buf[i] = static_cast<UChar>(args.at(i).toUInt32(exec)); + return jsString(exec, impl); } static JSValue JSC_HOST_CALL stringFromCharCode(ExecState* exec, JSObject*, JSValue, const ArgList& args) @@ -47,7 +47,7 @@ static JSValue JSC_HOST_CALL stringFromCharCode(ExecState* exec, JSObject*, JSVa ASSERT_CLASS_FITS_IN_CELL(StringConstructor); -StringConstructor::StringConstructor(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure, StringPrototype* stringPrototype) +StringConstructor::StringConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure, StringPrototype* stringPrototype) : InternalFunction(&exec->globalData(), structure, Identifier(exec, stringPrototype->classInfo()->className)) { // ECMA 15.5.3.1 String.prototype diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringConstructor.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringConstructor.h index 7d52c69..e511f7b 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringConstructor.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringConstructor.h @@ -29,7 +29,7 @@ namespace JSC { class StringConstructor : public InternalFunction { public: - StringConstructor(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure, StringPrototype*); + StringConstructor(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure, StringPrototype*); virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObject.cpp index dd1ac5d..f8e0e87 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObject.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObject.cpp @@ -29,19 +29,19 @@ ASSERT_CLASS_FITS_IN_CELL(StringObject); const ClassInfo StringObject::info = { "String", 0, 0, 0 }; -StringObject::StringObject(ExecState* exec, PassRefPtr<Structure> structure) +StringObject::StringObject(ExecState* exec, NonNullPassRefPtr<Structure> structure) : JSWrapperObject(structure) { setInternalValue(jsEmptyString(exec)); } -StringObject::StringObject(PassRefPtr<Structure> structure, JSString* string) +StringObject::StringObject(NonNullPassRefPtr<Structure> structure, JSString* string) : JSWrapperObject(structure) { setInternalValue(string); } -StringObject::StringObject(ExecState* exec, PassRefPtr<Structure> structure, const UString& string) +StringObject::StringObject(ExecState* exec, NonNullPassRefPtr<Structure> structure, const UString& string) : JSWrapperObject(structure) { setInternalValue(jsString(exec, string)); @@ -75,7 +75,7 @@ void StringObject::put(ExecState* exec, const Identifier& propertyName, JSValue JSObject::put(exec, propertyName, value, slot); } -bool StringObject::deleteProperty(ExecState* exec, const Identifier& propertyName, bool checkDontDelete) +bool StringObject::deleteProperty(ExecState* exec, const Identifier& propertyName) { if (propertyName == exec->propertyNames().length) return false; @@ -83,15 +83,17 @@ bool StringObject::deleteProperty(ExecState* exec, const Identifier& propertyNam unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); if (isStrictUInt32 && internalValue()->canGetIndex(i)) return false; - return JSObject::deleteProperty(exec, propertyName, checkDontDelete); + return JSObject::deleteProperty(exec, propertyName); } -void StringObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, bool includeNonEnumerable) +void StringObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { - int size = internalValue()->value().size(); + int size = internalValue()->length(); for (int i = 0; i < size; ++i) propertyNames.add(Identifier(exec, UString::from(i))); - return JSObject::getOwnPropertyNames(exec, propertyNames); + if (mode == IncludeDontEnumProperties) + propertyNames.add(exec->propertyNames().length); + return JSObject::getOwnPropertyNames(exec, propertyNames, mode); } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObject.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObject.h index 2f5927a..b720b90 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObject.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObject.h @@ -28,8 +28,8 @@ namespace JSC { class StringObject : public JSWrapperObject { public: - StringObject(ExecState*, PassRefPtr<Structure>); - StringObject(ExecState*, PassRefPtr<Structure>, const UString&); + StringObject(ExecState*, NonNullPassRefPtr<Structure>); + StringObject(ExecState*, NonNullPassRefPtr<Structure>, const UString&); static StringObject* create(ExecState*, JSString*); @@ -38,8 +38,8 @@ namespace JSC { virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual void put(ExecState* exec, const Identifier& propertyName, JSValue, PutPropertySlot&); - virtual bool deleteProperty(ExecState*, const Identifier& propertyName, bool checkDontDelete = true); - virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, bool includeNonEnumerable = false); + virtual bool deleteProperty(ExecState*, const Identifier& propertyName); + virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); virtual const ClassInfo* classInfo() const { return &info; } static const JS_EXPORTDATA ClassInfo info; @@ -48,11 +48,12 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } protected: - StringObject(PassRefPtr<Structure>, JSString*); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSWrapperObject::StructureFlags; + StringObject(NonNullPassRefPtr<Structure>, JSString*); }; StringObject* asStringObject(JSValue); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h index 1d2e03f..69e1939 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h @@ -37,16 +37,18 @@ namespace JSC { } private: - StringObjectThatMasqueradesAsUndefined(ExecState* exec, PassRefPtr<Structure> structure, const UString& string) + StringObjectThatMasqueradesAsUndefined(ExecState* exec, NonNullPassRefPtr<Structure> structure, const UString& string) : StringObject(exec, structure, string) { } static PassRefPtr<Structure> createStructure(JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, MasqueradesAsUndefined | HasDefaultMark)); + return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); } + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | MasqueradesAsUndefined | OverridesGetPropertyNames | StringObject::StructureFlags; + virtual bool toBoolean(ExecState*) const { return false; } }; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringPrototype.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringPrototype.cpp index c9a32b6..d002e07 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringPrototype.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringPrototype.cpp @@ -25,9 +25,11 @@ #include "CachedCall.h" #include "Error.h" #include "Executable.h" +#include "JSGlobalObjectFunctions.h" #include "JSArray.h" #include "JSFunction.h" #include "ObjectPrototype.h" +#include "Operations.h" #include "PropertyNameArray.h" #include "RegExpConstructor.h" #include "RegExpObject.h" @@ -72,6 +74,10 @@ static JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState*, JSObject*, JSVa static JSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState*, JSObject*, JSValue, const ArgList&); static JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*, JSObject*, JSValue, const ArgList&); + } #include "StringPrototype.lut.h" @@ -117,11 +123,14 @@ const ClassInfo StringPrototype::info = { "String", &StringObject::info, 0, Exec fontsize stringProtoFuncFontsize DontEnum|Function 1 anchor stringProtoFuncAnchor DontEnum|Function 1 link stringProtoFuncLink DontEnum|Function 1 + trim stringProtoFuncTrim DontEnum|Function 0 + trimLeft stringProtoFuncTrimLeft DontEnum|Function 0 + trimRight stringProtoFuncTrimRight DontEnum|Function 0 @end */ // ECMA 15.5.4 -StringPrototype::StringPrototype(ExecState* exec, PassRefPtr<Structure> structure) +StringPrototype::StringPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure) : StringObject(exec, structure) { // The constructor will be added later, after StringConstructor has been built @@ -140,12 +149,11 @@ bool StringPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier // ------------------------------ Functions -------------------------- -static inline UString substituteBackreferences(const UString& replacement, const UString& source, const int* ovector, RegExp* reg) +static NEVER_INLINE UString substituteBackreferencesSlow(const UString& replacement, const UString& source, const int* ovector, RegExp* reg, int i) { - UString substitutedReplacement; + Vector<UChar> substitutedReplacement; int offset = 0; - int i = -1; - while ((i = replacement.find('$', i + 1)) != -1) { + do { if (i + 1 == replacement.size()) break; @@ -197,15 +205,21 @@ static inline UString substituteBackreferences(const UString& replacement, const i += 1 + advance; offset = i + 1; substitutedReplacement.append(source.data() + backrefStart, backrefLength); - } - - if (!offset) - return replacement; + } while ((i = replacement.find('$', i + 1)) != -1); if (replacement.size() - offset) substitutedReplacement.append(replacement.data() + offset, replacement.size() - offset); - return substitutedReplacement; + substitutedReplacement.shrinkToFit(); + return UString::adopt(substitutedReplacement); +} + +static inline UString substituteBackreferences(const UString& replacement, const UString& source, const int* ovector, RegExp* reg) +{ + int i = replacement.find('$', 0); + if (UNLIKELY(i != -1)) + return substituteBackreferencesSlow(replacement, source, ovector, reg, i); + return replacement; } static inline int localeCompare(const UString& a, const UString& b) @@ -216,7 +230,7 @@ static inline int localeCompare(const UString& a, const UString& b) JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { JSString* sourceVal = thisValue.toThisJSString(exec); - const UString& source = sourceVal->value(); + const UString& source = sourceVal->value(exec); JSValue pattern = args.at(0); @@ -249,7 +263,7 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue return jsNull(); while (true) { int matchIndex; - int matchLen; + int matchLen = 0; int* ovector; regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector); if (matchIndex < 0) @@ -273,7 +287,8 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue cachedCall.setArgument(i++, sourceVal); cachedCall.setThis(exec->globalThisValue()); - replacements.append(cachedCall.call().toString(cachedCall.newCallFrame())); + JSValue result = cachedCall.call(); + replacements.append(result.toString(cachedCall.newCallFrame(exec))); if (exec->hadException()) break; @@ -290,7 +305,7 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue } else { do { int matchIndex; - int matchLen; + int matchLen = 0; int* ovector; regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector); if (matchIndex < 0) @@ -414,12 +429,14 @@ JSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState* exec, JSObject*, JSVa JSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { - UString s = thisValue.toThisString(exec); + if (thisValue.isString() && (args.size() == 1)) { + JSValue v = args.at(0); + return v.isString() + ? jsString(exec, asString(thisValue), asString(v)) + : jsString(exec, asString(thisValue), v.toString(exec)); + } - ArgList::const_iterator end = args.end(); - for (ArgList::const_iterator it = args.begin(); it != end; ++it) - s += (*it).toString(exec); - return jsString(exec, s); + return jsString(exec, thisValue, args); } JSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) @@ -461,6 +478,11 @@ JSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec, JSObject*, JSV dpos = 0; else if (!(dpos <= len)) // true for NaN dpos = len; +#if OS(SYMBIAN) + // Work around for broken NaN compare operator + else if (isnan(dpos)) + dpos = len; +#endif return jsNumber(exec, s.rfind(u2, static_cast<int>(dpos))); } @@ -485,7 +507,7 @@ JSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec, JSObject*, JSValue t } RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); int pos; - int matchLength; + int matchLength = 0; regExpConstructor->performMatch(reg.get(), u, 0, pos, matchLength); if (!(reg->global())) { // case without 'g' flag is handled like RegExp.prototype.exec @@ -535,7 +557,7 @@ JSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec, JSObject*, JSValue } RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); int pos; - int matchLength; + int matchLength = 0; regExpConstructor->performMatch(reg.get(), u, 0, pos, matchLength); return jsNumber(exec, pos); } @@ -683,7 +705,7 @@ JSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec, JSObject*, JSVal JSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { JSString* sVal = thisValue.toThisJSString(exec); - const UString& s = sVal->value(); + const UString& s = sVal->value(exec); int sSize = s.size(); if (!sSize) @@ -699,7 +721,7 @@ JSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec, JSObject*, JSV buffer[i] = toASCIILower(c); } if (!(ored & ~0x7f)) - return jsString(exec, UString(buffer.releaseBuffer(), sSize, false)); + return jsString(exec, UString::adopt(buffer)); bool error; int length = Unicode::toLower(buffer.data(), sSize, sData, sSize, &error); @@ -709,15 +731,18 @@ JSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec, JSObject*, JSV if (error) return sVal; } - if (length == sSize && memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0) - return sVal; - return jsString(exec, UString(buffer.releaseBuffer(), length, false)); + if (length == sSize) { + if (memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0) + return sVal; + } else + buffer.resize(length); + return jsString(exec, UString::adopt(buffer)); } JSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { JSString* sVal = thisValue.toThisJSString(exec); - const UString& s = sVal->value(); + const UString& s = sVal->value(exec); int sSize = s.size(); if (!sSize) @@ -733,7 +758,7 @@ JSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec, JSObject*, JSV buffer[i] = toASCIIUpper(c); } if (!(ored & ~0x7f)) - return jsString(exec, UString(buffer.releaseBuffer(), sSize, false)); + return jsString(exec, UString::adopt(buffer)); bool error; int length = Unicode::toUpper(buffer.data(), sSize, sData, sSize, &error); @@ -743,9 +768,12 @@ JSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec, JSObject*, JSV if (error) return sVal; } - if (length == sSize && memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0) - return sVal; - return jsString(exec, UString(buffer.releaseBuffer(), length, false)); + if (length == sSize) { + if (memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0) + return sVal; + } else + buffer.resize(length); + return jsString(exec, UString::adopt(buffer)); } JSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) @@ -761,62 +789,62 @@ JSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec, JSObject*, J JSValue JSC_HOST_CALL stringProtoFuncBig(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsNontrivialString(exec, "<big>" + s + "</big>"); + return jsNontrivialString(exec, makeString("<big>", s, "</big>")); } JSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsNontrivialString(exec, "<small>" + s + "</small>"); + return jsNontrivialString(exec, makeString("<small>", s, "</small>")); } JSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsNontrivialString(exec, "<blink>" + s + "</blink>"); + return jsNontrivialString(exec, makeString("<blink>", s, "</blink>")); } JSValue JSC_HOST_CALL stringProtoFuncBold(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsNontrivialString(exec, "<b>" + s + "</b>"); + return jsNontrivialString(exec, makeString("<b>", s, "</b>")); } JSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsString(exec, "<tt>" + s + "</tt>"); + return jsString(exec, makeString("<tt>", s, "</tt>")); } JSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsNontrivialString(exec, "<i>" + s + "</i>"); + return jsNontrivialString(exec, makeString("<i>", s, "</i>")); } JSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsNontrivialString(exec, "<strike>" + s + "</strike>"); + return jsNontrivialString(exec, makeString("<strike>", s, "</strike>")); } JSValue JSC_HOST_CALL stringProtoFuncSub(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsNontrivialString(exec, "<sub>" + s + "</sub>"); + return jsNontrivialString(exec, makeString("<sub>", s, "</sub>")); } JSValue JSC_HOST_CALL stringProtoFuncSup(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsNontrivialString(exec, "<sup>" + s + "</sup>"); + return jsNontrivialString(exec, makeString("<sup>", s, "</sup>")); } JSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { UString s = thisValue.toThisString(exec); JSValue a0 = args.at(0); - return jsNontrivialString(exec, "<font color=\"" + a0.toString(exec) + "\">" + s + "</font>"); + return jsNontrivialString(exec, makeString("<font color=\"", a0.toString(exec), "\">", s, "</font>")); } JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) @@ -829,7 +857,8 @@ JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec, JSObject*, JSValu unsigned stringSize = s.size(); unsigned bufferSize = 22 + stringSize; UChar* buffer; - if (!tryFastMalloc(bufferSize * sizeof(UChar)).getValue(buffer)) + PassRefPtr<UStringImpl> impl = UStringImpl::tryCreateUninitialized(bufferSize, buffer); + if (!impl) return jsUndefined(); buffer[0] = '<'; buffer[1] = 'f'; @@ -854,17 +883,17 @@ JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec, JSObject*, JSValu buffer[19 + stringSize] = 'n'; buffer[20 + stringSize] = 't'; buffer[21 + stringSize] = '>'; - return jsNontrivialString(exec, UString(buffer, bufferSize, false)); + return jsNontrivialString(exec, impl); } - return jsNontrivialString(exec, "<font size=\"" + a0.toString(exec) + "\">" + s + "</font>"); + return jsNontrivialString(exec, makeString("<font size=\"", a0.toString(exec), "\">", s, "</font>")); } JSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { UString s = thisValue.toThisString(exec); JSValue a0 = args.at(0); - return jsNontrivialString(exec, "<a name=\"" + a0.toString(exec) + "\">" + s + "</a>"); + return jsNontrivialString(exec, makeString("<a name=\"", a0.toString(exec), "\">", s, "</a>")); } JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) @@ -877,7 +906,8 @@ JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec, JSObject*, JSValue th unsigned stringSize = s.size(); unsigned bufferSize = 15 + linkTextSize + stringSize; UChar* buffer; - if (!tryFastMalloc(bufferSize * sizeof(UChar)).getValue(buffer)) + PassRefPtr<UStringImpl> impl = UStringImpl::tryCreateUninitialized(bufferSize, buffer); + if (!impl) return jsUndefined(); buffer[0] = '<'; buffer[1] = 'a'; @@ -896,7 +926,54 @@ JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec, JSObject*, JSValue th buffer[12 + linkTextSize + stringSize] = '/'; buffer[13 + linkTextSize + stringSize] = 'a'; buffer[14 + linkTextSize + stringSize] = '>'; - return jsNontrivialString(exec, UString(buffer, bufferSize, false)); + return jsNontrivialString(exec, impl); } +enum { + TrimLeft = 1, + TrimRight = 2 +}; + +static inline bool isTrimWhitespace(UChar c) +{ + return isStrWhiteSpace(c) || c == 0x200b; +} + +static inline JSValue trimString(ExecState* exec, JSValue thisValue, int trimKind) +{ + UString str = thisValue.toThisString(exec); + int left = 0; + if (trimKind & TrimLeft) { + while (left < str.size() && isTrimWhitespace(str[left])) + left++; + } + int right = str.size(); + if (trimKind & TrimRight) { + while (right > left && isTrimWhitespace(str[right - 1])) + right--; + } + + // Don't gc allocate a new string if we don't have to. + if (left == 0 && right == str.size() && thisValue.isString()) + return thisValue; + + return jsString(exec, str.substr(left, right - left)); +} + +JSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + return trimString(exec, thisValue, TrimLeft | TrimRight); +} + +JSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + return trimString(exec, thisValue, TrimLeft); +} + +JSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + return trimString(exec, thisValue, TrimRight); +} + + } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringPrototype.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringPrototype.h index 580e13d..3a6a2a3 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringPrototype.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StringPrototype.h @@ -29,7 +29,7 @@ namespace JSC { class StringPrototype : public StringObject { public: - StringPrototype(ExecState*, PassRefPtr<Structure>); + StringPrototype(ExecState*, NonNullPassRefPtr<Structure>); virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Structure.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Structure.cpp index be817c3..8e50dd1 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Structure.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Structure.cpp @@ -28,9 +28,10 @@ #include "Identifier.h" #include "JSObject.h" +#include "JSPropertyNameIterator.h" +#include "Lookup.h" #include "PropertyNameArray.h" #include "StructureChain.h" -#include "Lookup.h" #include <wtf/RefCountedLeakCounter.h> #include <wtf/RefPtr.h> @@ -75,6 +76,8 @@ static HashSet<Structure*>& ignoreSet = *(new HashSet<Structure*>); static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>); #endif +static int comparePropertyMapEntryIndices(const void* a, const void* b); + void Structure::dumpStatistics() { #if DUMP_STRUCTURE_ID_STATISTICS @@ -130,6 +133,7 @@ Structure::Structure(JSValue prototype, const TypeInfo& typeInfo) , m_isPinnedPropertyTable(false) , m_hasGetterSetterProperties(false) , m_attributesInPrevious(0) + , m_specificFunctionThrashCount(0) { ASSERT(m_prototype); ASSERT(m_prototype.isObject() || m_prototype.isNull()); @@ -158,9 +162,9 @@ Structure::~Structure() m_previous->table.removeAnonymousSlotTransition(m_anonymousSlotsInPrevious); } - - if (m_cachedPropertyNameArrayData) - m_cachedPropertyNameArrayData->setCachedStructure(0); + + if (m_enumerationCache) + m_enumerationCache->setCachedStructure(0); if (m_propertyTable) { unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; @@ -281,59 +285,6 @@ void Structure::materializePropertyMap() } } -void Structure::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, JSObject* baseObject, bool includeNonEnumerable) -{ - getNamesFromPropertyTable(propertyNames, includeNonEnumerable); - getNamesFromClassInfoTable(exec, baseObject->classInfo(), propertyNames, includeNonEnumerable); -} - -void Structure::getEnumerablePropertyNames(ExecState* exec, PropertyNameArray& propertyNames, JSObject* baseObject) -{ - bool shouldCache = propertyNames.shouldCache() && !(propertyNames.size() || isDictionary()); - - if (shouldCache && m_cachedPropertyNameArrayData) { - if (m_cachedPropertyNameArrayData->cachedPrototypeChain() == prototypeChain(exec)) { - propertyNames.setData(m_cachedPropertyNameArrayData); - return; - } - clearEnumerationCache(); - } - - baseObject->getOwnPropertyNames(exec, propertyNames); - - if (m_prototype.isObject()) { - propertyNames.setShouldCache(false); // No need for our prototypes to waste memory on caching, since they're not being enumerated directly. - JSObject* prototype = asObject(m_prototype); - while(1) { - if (!prototype->structure()->typeInfo().hasDefaultGetPropertyNames()) { - prototype->getPropertyNames(exec, propertyNames); - break; - } - prototype->getOwnPropertyNames(exec, propertyNames); - JSValue nextProto = prototype->prototype(); - if (!nextProto.isObject()) - break; - prototype = asObject(nextProto); - } - } - - if (shouldCache) { - StructureChain* protoChain = prototypeChain(exec); - m_cachedPropertyNameArrayData = propertyNames.data(); - if (!protoChain->isCacheable()) - return; - m_cachedPropertyNameArrayData->setCachedPrototypeChain(protoChain); - m_cachedPropertyNameArrayData->setCachedStructure(this); - } -} - -void Structure::clearEnumerationCache() -{ - if (m_cachedPropertyNameArrayData) - m_cachedPropertyNameArrayData->setCachedStructure(0); - m_cachedPropertyNameArrayData.clear(); -} - void Structure::growPropertyStorageCapacity() { if (m_propertyStorageCapacity == JSObject::inlineStorageCapacity) @@ -351,7 +302,7 @@ void Structure::despecifyDictionaryFunction(const Identifier& propertyName) ASSERT(isDictionary()); ASSERT(m_propertyTable); - unsigned i = rep->computedHash(); + unsigned i = rep->existingHash(); #if DUMP_PROPERTYMAP_STATS ++numProbes; @@ -369,7 +320,7 @@ void Structure::despecifyDictionaryFunction(const Identifier& propertyName) ++numCollisions; #endif - unsigned k = 1 | doubleHash(rep->computedHash()); + unsigned k = 1 | doubleHash(rep->existingHash()); while (1) { i += k; @@ -407,6 +358,9 @@ PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, con ASSERT(!structure->isDictionary()); ASSERT(structure->typeInfo().type() == ObjectType); ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset)); + + if (structure->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount) + specificValue = 0; if (structure->transitionCount() > s_maxTransitionLength) { RefPtr<Structure> transition = toCacheableDictionaryTransition(structure); @@ -426,6 +380,8 @@ PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, con transition->m_specificValueInPrevious = specificValue; transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; + transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; + transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount; if (structure->m_propertyTable) { if (structure->m_isPinnedPropertyTable) @@ -468,6 +424,8 @@ PassRefPtr<Structure> Structure::changePrototypeTransition(Structure* structure, transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; + transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; + transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount; // Don't set m_offset, as one can not transition to this. @@ -480,10 +438,13 @@ PassRefPtr<Structure> Structure::changePrototypeTransition(Structure* structure, PassRefPtr<Structure> Structure::despecifyFunctionTransition(Structure* structure, const Identifier& replaceFunction) { + ASSERT(structure->m_specificFunctionThrashCount < maxSpecificFunctionThrashCount); RefPtr<Structure> transition = create(structure->storedPrototype(), structure->typeInfo()); transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; + transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; + transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount + 1; // Don't set m_offset, as one can not transition to this. @@ -491,8 +452,12 @@ PassRefPtr<Structure> Structure::despecifyFunctionTransition(Structure* structur transition->m_propertyTable = structure->copyPropertyTable(); transition->m_isPinnedPropertyTable = true; - bool removed = transition->despecifyFunction(replaceFunction); - ASSERT_UNUSED(removed, removed); + if (transition->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount) + transition->despecifyAllFunctions(); + else { + bool removed = transition->despecifyFunction(replaceFunction); + ASSERT_UNUSED(removed, removed); + } return transition.release(); } @@ -515,6 +480,8 @@ PassRefPtr<Structure> Structure::addAnonymousSlotsTransition(Structure* structur transition->m_specificValueInPrevious = 0; transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; + transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; + transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount; if (structure->m_propertyTable) { if (structure->m_isPinnedPropertyTable) @@ -543,6 +510,8 @@ PassRefPtr<Structure> Structure::getterSetterTransition(Structure* structure) RefPtr<Structure> transition = create(structure->storedPrototype(), structure->typeInfo()); transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; transition->m_hasGetterSetterProperties = transition->m_hasGetterSetterProperties; + transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; + transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount; // Don't set m_offset, as one can not transition to this. @@ -561,6 +530,8 @@ PassRefPtr<Structure> Structure::toDictionaryTransition(Structure* structure, Di transition->m_dictionaryKind = kind; transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; + transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; + transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount; structure->materializePropertyMapIfNecessary(); transition->m_propertyTable = structure->copyPropertyTable(); @@ -579,43 +550,75 @@ PassRefPtr<Structure> Structure::toUncacheableDictionaryTransition(Structure* st return toDictionaryTransition(structure, UncachedDictionaryKind); } -PassRefPtr<Structure> Structure::fromDictionaryTransition(Structure* structure) +PassRefPtr<Structure> Structure::flattenDictionaryStructure(JSObject* object) { - ASSERT(structure->isDictionary()); - - // Since dictionary Structures are not shared, and no opcodes specialize - // for them, we don't need to allocate a new Structure when transitioning - // to non-dictionary status. - - // FIMXE: We can make this more efficient by canonicalizing the Structure (draining the - // deleted offsets vector) before transitioning from dictionary. - if (!structure->m_propertyTable || !structure->m_propertyTable->deletedOffsets || structure->m_propertyTable->deletedOffsets->isEmpty()) - structure->m_dictionaryKind = NoneDictionaryKind; + ASSERT(isDictionary()); + if (isUncacheableDictionary()) { + ASSERT(m_propertyTable); + Vector<PropertyMapEntry*> sortedPropertyEntries(m_propertyTable->keyCount); + PropertyMapEntry** p = sortedPropertyEntries.data(); + unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; + for (unsigned i = 1; i <= entryCount; i++) { + if (m_propertyTable->entries()[i].key) + *p++ = &m_propertyTable->entries()[i]; + } + size_t propertyCount = p - sortedPropertyEntries.data(); + qsort(sortedPropertyEntries.data(), propertyCount, sizeof(PropertyMapEntry*), comparePropertyMapEntryIndices); + sortedPropertyEntries.resize(propertyCount); + + // We now have the properties currently defined on this object + // in the order that they are expected to be in, but we need to + // reorder the storage, so we have to copy the current values out + Vector<JSValue> values(propertyCount); + unsigned anonymousSlotCount = m_propertyTable->anonymousSlotCount; + for (unsigned i = 0; i < propertyCount; i++) { + PropertyMapEntry* entry = sortedPropertyEntries[i]; + values[i] = object->getDirectOffset(entry->offset); + // Update property table to have the new property offsets + entry->offset = anonymousSlotCount + i; + entry->index = i; + } + + // Copy the original property values into their final locations + for (unsigned i = 0; i < propertyCount; i++) + object->putDirectOffset(anonymousSlotCount + i, values[i]); + + if (m_propertyTable->deletedOffsets) { + delete m_propertyTable->deletedOffsets; + m_propertyTable->deletedOffsets = 0; + } + } - return structure; + m_dictionaryKind = NoneDictionaryKind; + return this; } size_t Structure::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue) { + ASSERT(!m_enumerationCache); + + if (m_specificFunctionThrashCount == maxSpecificFunctionThrashCount) + specificValue = 0; + materializePropertyMapIfNecessary(); m_isPinnedPropertyTable = true; + size_t offset = put(propertyName, attributes, specificValue); if (propertyStorageSize() > propertyStorageCapacity()) growPropertyStorageCapacity(); - clearEnumerationCache(); return offset; } size_t Structure::removePropertyWithoutTransition(const Identifier& propertyName) { ASSERT(isUncacheableDictionary()); + ASSERT(!m_enumerationCache); materializePropertyMapIfNecessary(); m_isPinnedPropertyTable = true; size_t offset = remove(propertyName); - clearEnumerationCache(); return offset; } @@ -682,7 +685,7 @@ size_t Structure::get(const UString::Rep* rep, unsigned& attributes, JSCell*& sp if (!m_propertyTable) return notFound; - unsigned i = rep->computedHash(); + unsigned i = rep->existingHash(); #if DUMP_PROPERTYMAP_STATS ++numProbes; @@ -702,7 +705,7 @@ size_t Structure::get(const UString::Rep* rep, unsigned& attributes, JSCell*& sp ++numCollisions; #endif - unsigned k = 1 | doubleHash(rep->computedHash()); + unsigned k = 1 | doubleHash(rep->existingHash()); while (1) { i += k; @@ -733,7 +736,7 @@ bool Structure::despecifyFunction(const Identifier& propertyName) UString::Rep* rep = propertyName._ustring.rep(); - unsigned i = rep->computedHash(); + unsigned i = rep->existingHash(); #if DUMP_PROPERTYMAP_STATS ++numProbes; @@ -753,7 +756,7 @@ bool Structure::despecifyFunction(const Identifier& propertyName) ++numCollisions; #endif - unsigned k = 1 | doubleHash(rep->computedHash()); + unsigned k = 1 | doubleHash(rep->existingHash()); while (1) { i += k; @@ -774,6 +777,17 @@ bool Structure::despecifyFunction(const Identifier& propertyName) } } +void Structure::despecifyAllFunctions() +{ + materializePropertyMapIfNecessary(); + if (!m_propertyTable) + return; + + unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; + for (unsigned i = 1; i <= entryCount; ++i) + m_propertyTable->entries()[i].specificValue = 0; +} + size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue) { ASSERT(!propertyName.isNull()); @@ -781,6 +795,9 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel checkConsistency(); + if (attributes & DontEnum) + m_hasNonEnumerableProperties = true; + UString::Rep* rep = propertyName._ustring.rep(); if (!m_propertyTable) @@ -788,7 +805,7 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel // FIXME: Consider a fast case for tables with no deleted sentinels. - unsigned i = rep->computedHash(); + unsigned i = rep->existingHash(); unsigned k = 0; bool foundDeletedElement = false; unsigned deletedElementIndex = 0; // initialize to make the compiler happy @@ -811,7 +828,7 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel } if (k == 0) { - k = 1 | doubleHash(rep->computedHash()); + k = 1 | doubleHash(rep->existingHash()); #if DUMP_PROPERTYMAP_STATS ++numCollisions; #endif @@ -891,7 +908,7 @@ size_t Structure::remove(const Identifier& propertyName) #endif // Find the thing to remove. - unsigned i = rep->computedHash(); + unsigned i = rep->existingHash(); unsigned k = 0; unsigned entryIndex; UString::Rep* key = 0; @@ -905,7 +922,7 @@ size_t Structure::remove(const Identifier& propertyName) break; if (k == 0) { - k = 1 | doubleHash(rep->computedHash()); + k = 1 | doubleHash(rep->existingHash()); #if DUMP_PROPERTYMAP_STATS ++numCollisions; #endif @@ -949,7 +966,7 @@ void Structure::insertIntoPropertyMapHashTable(const PropertyMapEntry& entry) { ASSERT(m_propertyTable); - unsigned i = entry.key->computedHash(); + unsigned i = entry.key->existingHash(); unsigned k = 0; #if DUMP_PROPERTYMAP_STATS @@ -962,7 +979,7 @@ void Structure::insertIntoPropertyMapHashTable(const PropertyMapEntry& entry) break; if (k == 0) { - k = 1 | doubleHash(entry.key->computedHash()); + k = 1 | doubleHash(entry.key->existingHash()); #if DUMP_PROPERTYMAP_STATS ++numCollisions; #endif @@ -1045,7 +1062,7 @@ void Structure::rehashPropertyMapHashTable(unsigned newTableSize) checkConsistency(); } -static int comparePropertyMapEntryIndices(const void* a, const void* b) +int comparePropertyMapEntryIndices(const void* a, const void* b) { unsigned ia = static_cast<PropertyMapEntry* const*>(a)[0]->index; unsigned ib = static_cast<PropertyMapEntry* const*>(b)[0]->index; @@ -1056,7 +1073,7 @@ static int comparePropertyMapEntryIndices(const void* a, const void* b) return 0; } -void Structure::getNamesFromPropertyTable(PropertyNameArray& propertyNames, bool includeNonEnumerable) +void Structure::getPropertyNames(PropertyNameArray& propertyNames, EnumerationMode mode) { materializePropertyMapIfNecessary(); if (!m_propertyTable) @@ -1067,7 +1084,8 @@ void Structure::getNamesFromPropertyTable(PropertyNameArray& propertyNames, bool int i = 0; unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; for (unsigned k = 1; k <= entryCount; k++) { - if (m_propertyTable->entries()[k].key && (!(m_propertyTable->entries()[k].attributes & DontEnum) || includeNonEnumerable)) { + ASSERT(m_hasNonEnumerableProperties || !(m_propertyTable->entries()[k].attributes & DontEnum)); + if (m_propertyTable->entries()[k].key && (!(m_propertyTable->entries()[k].attributes & DontEnum) || (mode == IncludeDontEnumProperties))) { PropertyMapEntry* value = &m_propertyTable->entries()[k]; int j; for (j = i - 1; j >= 0 && a[j]->index > value->index; --j) @@ -1094,7 +1112,7 @@ void Structure::getNamesFromPropertyTable(PropertyNameArray& propertyNames, bool PropertyMapEntry** p = sortedEnumerables.data(); unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; for (unsigned i = 1; i <= entryCount; i++) { - if (m_propertyTable->entries()[i].key && (!(m_propertyTable->entries()[i].attributes & DontEnum) || includeNonEnumerable)) + if (m_propertyTable->entries()[i].key && (!(m_propertyTable->entries()[i].attributes & DontEnum) || (mode == IncludeDontEnumProperties))) *p++ = &m_propertyTable->entries()[i]; } @@ -1113,25 +1131,6 @@ void Structure::getNamesFromPropertyTable(PropertyNameArray& propertyNames, bool } } -void Structure::getNamesFromClassInfoTable(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, bool includeNonEnumerable) -{ - // Add properties from the static hashtables of properties - for (; classInfo; classInfo = classInfo->parentClass) { - const HashTable* table = classInfo->propHashTable(exec); - if (!table) - continue; - table->initializeIfNeeded(exec); - ASSERT(table->table); - - int hashSizeMask = table->compactSize - 1; - const HashEntry* entry = table->table; - for (int i = 0; i <= hashSizeMask; ++i, ++entry) { - if (entry->key() && (!(entry->attributes() & DontEnum) || includeNonEnumerable)) - propertyNames.add(entry->key()); - } - } -} - #if DO_PROPERTYMAP_CONSTENCY_CHECK void Structure::checkConsistency() @@ -1173,11 +1172,12 @@ void Structure::checkConsistency() unsigned nonEmptyEntryCount = 0; for (unsigned c = 1; c <= m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; ++c) { + ASSERT(m_hasNonEnumerableProperties || !(m_propertyTable->entries()[c].attributes & DontEnum)); UString::Rep* rep = m_propertyTable->entries()[c].key; if (!rep) continue; ++nonEmptyEntryCount; - unsigned i = rep->computedHash(); + unsigned i = rep->existingHash(); unsigned k = 0; unsigned entryIndex; while (1) { @@ -1186,7 +1186,7 @@ void Structure::checkConsistency() if (rep == m_propertyTable->entries()[entryIndex - 1].key) break; if (k == 0) - k = 1 | doubleHash(rep->computedHash()); + k = 1 | doubleHash(rep->existingHash()); i += k; } ASSERT(entryIndex == c + 1); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Structure.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Structure.h index d012ba9..5284258 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Structure.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Structure.h @@ -30,6 +30,8 @@ #include "JSType.h" #include "JSValue.h" #include "PropertyMapHashTable.h" +#include "PropertyNameArray.h" +#include "Protect.h" #include "StructureTransitionTable.h" #include "JSTypeInfo.h" #include "UString.h" @@ -49,6 +51,11 @@ namespace JSC { class PropertyNameArrayData; class StructureChain; + enum EnumerationMode { + ExcludeDontEnumProperties, + IncludeDontEnumProperties + }; + class Structure : public RefCounted<Structure> { public: friend class JIT; @@ -72,11 +79,10 @@ namespace JSC { static PassRefPtr<Structure> getterSetterTransition(Structure*); static PassRefPtr<Structure> toCacheableDictionaryTransition(Structure*); static PassRefPtr<Structure> toUncacheableDictionaryTransition(Structure*); - static PassRefPtr<Structure> fromDictionaryTransition(Structure*); - ~Structure(); + PassRefPtr<Structure> flattenDictionaryStructure(JSObject*); - void markAggregate(MarkStack&); + ~Structure(); // These should be used with caution. size_t addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue); @@ -95,8 +101,8 @@ namespace JSC { Structure* previousID() const { return m_previous.get(); } void growPropertyStorageCapacity(); - size_t propertyStorageCapacity() const { return m_propertyStorageCapacity; } - size_t propertyStorageSize() const { return m_propertyTable ? m_propertyTable->keyCount + m_propertyTable->anonymousSlotCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : m_offset + 1; } + unsigned propertyStorageCapacity() const { return m_propertyStorageCapacity; } + unsigned propertyStorageSize() const { return m_propertyTable ? m_propertyTable->keyCount + m_propertyTable->anonymousSlotCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : m_offset + 1; } bool isUsingInlineStorage() const; size_t get(const Identifier& propertyName); @@ -116,17 +122,22 @@ namespace JSC { return hasTransition(propertyName._ustring.rep(), attributes); } - void getEnumerablePropertyNames(ExecState*, PropertyNameArray&, JSObject*); - void getOwnPropertyNames(ExecState*, PropertyNameArray&, JSObject*, bool includeNonEnumerable = false); - bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; } void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; } + bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; } + + bool hasAnonymousSlots() const { return m_propertyTable && m_propertyTable->anonymousSlotCount; } + bool isEmpty() const { return m_propertyTable ? !m_propertyTable->keyCount : m_offset == noOffset; } - JSCell* specificValue() { return m_specificValueInPrevious; } void despecifyDictionaryFunction(const Identifier& propertyName); + void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; } + void setEnumerationCache(JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h. + JSPropertyNameIterator* enumerationCache() { return m_enumerationCache.get(); } + void getPropertyNames(PropertyNameArray&, EnumerationMode mode); + private: Structure(JSValue prototype, const TypeInfo&); @@ -140,8 +151,6 @@ namespace JSC { size_t put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue); size_t remove(const Identifier& propertyName); void addAnonymousSlots(unsigned slotCount); - void getNamesFromPropertyTable(PropertyNameArray&, bool includeNonEnumerable = false); - void getNamesFromClassInfoTable(ExecState*, const ClassInfo*, PropertyNameArray&, bool includeNonEnumerable = false); void expandPropertyMapHashTable(); void rehashPropertyMapHashTable(); @@ -152,6 +161,7 @@ namespace JSC { void checkConsistency(); bool despecifyFunction(const Identifier&); + void despecifyAllFunctions(); PropertyMapHashTable* copyPropertyTable(); void materializePropertyMap(); @@ -162,8 +172,6 @@ namespace JSC { materializePropertyMap(); } - void clearEnumerationCache(); - signed char transitionCount() const { // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both. @@ -178,6 +186,8 @@ namespace JSC { static const signed char noOffset = -1; + static const unsigned maxSpecificFunctionThrashCount = 3; + TypeInfo m_typeInfo; JSValue m_prototype; @@ -189,16 +199,17 @@ namespace JSC { StructureTransitionTable table; - RefPtr<PropertyNameArrayData> m_cachedPropertyNameArrayData; + ProtectedPtr<JSPropertyNameIterator> m_enumerationCache; PropertyMapHashTable* m_propertyTable; - size_t m_propertyStorageCapacity; + uint32_t m_propertyStorageCapacity; signed char m_offset; unsigned m_dictionaryKind : 2; bool m_isPinnedPropertyTable : 1; bool m_hasGetterSetterProperties : 1; + bool m_hasNonEnumerableProperties : 1; #if COMPILER(WINSCW) // Workaround for Symbian WINSCW compiler that cannot resolve unsigned type of the declared // bitfield, when used as argument in make_pair() function calls in structure.ccp. @@ -208,6 +219,8 @@ namespace JSC { unsigned m_attributesInPrevious : 7; #endif unsigned m_anonymousSlotsInPrevious : 6; + unsigned m_specificFunctionThrashCount : 2; + // 4 free bits }; inline size_t Structure::get(const Identifier& propertyName) @@ -220,7 +233,7 @@ namespace JSC { UString::Rep* rep = propertyName._ustring.rep(); - unsigned i = rep->computedHash(); + unsigned i = rep->existingHash(); #if DUMP_PROPERTYMAP_STATS ++numProbes; @@ -237,7 +250,7 @@ namespace JSC { ++numCollisions; #endif - unsigned k = 1 | WTF::doubleHash(rep->computedHash()); + unsigned k = 1 | WTF::doubleHash(rep->existingHash()); while (1) { i += k; @@ -304,7 +317,7 @@ namespace JSC { TransitionTable* transitionTable = new TransitionTable; setTransitionTable(transitionTable); if (existingTransition) - add(make_pair(RefPtr<UString::Rep>(existingTransition->m_nameInPrevious.get()), existingTransition->m_attributesInPrevious), existingTransition, existingTransition->m_specificValueInPrevious); + add(std::make_pair(RefPtr<UString::Rep>(existingTransition->m_nameInPrevious.get()), existingTransition->m_attributesInPrevious), existingTransition, existingTransition->m_specificValueInPrevious); } } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureChain.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureChain.cpp index 2c38b67..76e5518 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureChain.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureChain.cpp @@ -25,7 +25,6 @@ #include "config.h" #include "StructureChain.h" -#include "Structure.h" #include "JSObject.h" #include "Structure.h" @@ -47,23 +46,11 @@ StructureChain::StructureChain(Structure* head) m_vector[i] = 0; } +#if OS(HPUX) PassRefPtr<StructureChain> StructureChain::create(Structure* head) { return adoptRef(new StructureChain(head)); } - -bool StructureChain::isCacheable() const -{ - uint32_t i = 0; - - while (m_vector[i]) { - // Both classes of dictionary structure may change arbitrarily so we can't cache them - if (m_vector[i]->isDictionary()) - return false; - if (!m_vector[i++]->typeInfo().hasDefaultGetPropertyNames()) - return false; - } - return true; -} +#endif } // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureChain.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureChain.h index 5990e17..3496400 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureChain.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureChain.h @@ -36,10 +36,15 @@ namespace JSC { class Structure; class StructureChain : public RefCounted<StructureChain> { + friend class JIT; + public: +#if OS(HPUX) static PassRefPtr<StructureChain> create(Structure* head); +#else + static PassRefPtr<StructureChain> create(Structure* head) { return adoptRef(new StructureChain(head)); } +#endif RefPtr<Structure>* head() { return m_vector.get(); } - bool isCacheable() const; private: StructureChain(Structure* head); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureTransitionTable.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureTransitionTable.h index 0fa7b73..35fb7e4 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureTransitionTable.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureTransitionTable.h @@ -42,7 +42,7 @@ namespace JSC { typedef std::pair<RefPtr<UString::Rep>, unsigned> Key; static unsigned hash(const Key& p) { - return p.first->computedHash(); + return p.first->existingHash(); } static bool equal(const Key& a, const Key& b) diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/TimeoutChecker.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/TimeoutChecker.cpp index 0a8bbd3..9e1f8b4 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/TimeoutChecker.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/TimeoutChecker.cpp @@ -33,9 +33,9 @@ #include "CallFrame.h" #include "JSGlobalObject.h" -#if PLATFORM(DARWIN) +#if OS(DARWIN) #include <mach/mach.h> -#elif PLATFORM(WIN_OS) +#elif OS(WINDOWS) #include <windows.h> #else #include "CurrentTime.h" @@ -54,7 +54,7 @@ static const int defaultIntervalBetweenChecks = 1000; // Returns the time the current thread has spent executing, in milliseconds. static inline unsigned getCPUTime() { -#if PLATFORM(DARWIN) +#if OS(DARWIN) mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT; thread_basic_info_data_t info; @@ -67,7 +67,7 @@ static inline unsigned getCPUTime() time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000; return time; -#elif PLATFORM(WIN_OS) +#elif OS(WINDOWS) union { FILETIME fileTime; unsigned long long fileTimeAsLong; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Tracing.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Tracing.h index e544f66..c28c85f 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Tracing.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Tracing.h @@ -33,7 +33,7 @@ #define JAVASCRIPTCORE_GC_BEGIN() #define JAVASCRIPTCORE_GC_BEGIN_ENABLED() 0 -#define JAVASCRIPTCORE_GC_END(arg0, arg1) +#define JAVASCRIPTCORE_GC_END() #define JAVASCRIPTCORE_GC_END_ENABLED() 0 #define JAVASCRIPTCORE_GC_MARKED() diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UString.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UString.cpp index e66ca93..a6b66cb 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UString.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UString.cpp @@ -30,12 +30,12 @@ #include "Identifier.h" #include "Operations.h" #include <ctype.h> -#include <float.h> #include <limits.h> #include <limits> #include <math.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <wtf/ASCIICType.h> #include <wtf/Assertions.h> #include <wtf/MathExtras.h> @@ -44,9 +44,6 @@ #include <wtf/unicode/UTF8.h> #include <wtf/StringExtras.h> -#if HAVE(STRING_H) -#include <string.h> -#endif #if HAVE(STRINGS_H) #include <strings.h> #endif @@ -55,52 +52,11 @@ using namespace WTF; using namespace WTF::Unicode; using namespace std; -// This can be tuned differently per platform by putting platform #ifs right here. -// If you don't define this macro at all, then copyChars will just call directly -// to memcpy. -#define USTRING_COPY_CHARS_INLINE_CUTOFF 20 - namespace JSC { 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 = 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); } - -static inline PossiblyNull<UChar*> allocChars(size_t length) -{ - ASSERT(length); - if (length > maxUChars()) - return 0; - return tryFastMalloc(sizeof(UChar) * length); -} - -static inline PossiblyNull<UChar*> reallocChars(UChar* buffer, size_t length) -{ - ASSERT(length); - if (length > maxUChars()) - return 0; - return tryFastRealloc(buffer, sizeof(UChar) * length); -} - -static inline void copyChars(UChar* destination, const UChar* source, unsigned numCharacters) -{ -#ifdef USTRING_COPY_CHARS_INLINE_CUTOFF - if (numCharacters <= USTRING_COPY_CHARS_INLINE_CUTOFF) { - for (unsigned i = 0; i < numCharacters; ++i) - destination[i] = source[i]; - return; - } -#endif - memcpy(destination, source, numCharacters * sizeof(UChar)); -} - -COMPILE_ASSERT(sizeof(UChar) == 2, uchar_is_2_bytes); - CString::CString(const char* c) : m_length(strlen(c)) , m_data(new char[m_length + 1]) @@ -193,389 +149,52 @@ bool operator==(const CString& c1, const CString& c2) // These static strings are immutable, except for rc, whose initial value is chosen to // reduce the possibility of it becoming zero due to ref/deref not being thread-safe. static UChar sharedEmptyChar; -UString::BaseString* UString::Rep::nullBaseString; -UString::BaseString* UString::Rep::emptyBaseString; +UStringImpl* UStringImpl::s_null; +UStringImpl* UStringImpl::s_empty; UString* UString::nullUString; -static void initializeStaticBaseString(UString::BaseString& base) -{ - base.rc = INT_MAX / 2; - base.m_identifierTableAndFlags.setFlag(UString::Rep::StaticFlag); - base.checkConsistency(); -} - void initializeUString() { - UString::Rep::nullBaseString = new UString::BaseString(0, 0); - initializeStaticBaseString(*UString::Rep::nullBaseString); - - UString::Rep::emptyBaseString = new UString::BaseString(&sharedEmptyChar, 0); - initializeStaticBaseString(*UString::Rep::emptyBaseString); - + UStringImpl::s_null = new UStringImpl(0, 0, UStringImpl::ConstructStaticString); + UStringImpl::s_empty = new UStringImpl(&sharedEmptyChar, 0, UStringImpl::ConstructStaticString); UString::nullUString = new UString; } -static char* statBuffer = 0; // Only used for debugging via UString::ascii(). - -PassRefPtr<UString::Rep> UString::Rep::createCopying(const UChar* d, int l) -{ - UChar* copyD = static_cast<UChar*>(fastMalloc(l * sizeof(UChar))); - copyChars(copyD, d, l); - return create(copyD, l); -} - -PassRefPtr<UString::Rep> UString::Rep::createFromUTF8(const char* string) +static PassRefPtr<UString::Rep> createRep(const char* c) { - if (!string) - return &UString::Rep::null(); - - size_t length = strlen(string); - Vector<UChar, 1024> buffer(length); - UChar* p = buffer.data(); - if (conversionOK != convertUTF8ToUTF16(&string, string + length, &p, p + length)) + if (!c) return &UString::Rep::null(); - return UString::Rep::createCopying(buffer.data(), p - buffer.data()); -} - -PassRefPtr<UString::Rep> UString::Rep::create(UChar* string, int length, PassRefPtr<UString::SharedUChar> sharedBuffer) -{ - PassRefPtr<UString::Rep> rep = create(string, length); - rep->baseString()->setSharedBuffer(sharedBuffer); - rep->checkConsistency(); - return rep; -} - -UString::SharedUChar* UString::Rep::sharedBuffer() -{ - UString::BaseString* base = baseString(); - if (len < minLengthToShare) - return 0; - - return base->sharedBuffer(); -} - -void UString::Rep::destroy() -{ - checkConsistency(); - - // Static null and empty strings can never be destroyed, but we cannot rely on - // reference counting, because ref/deref are not thread-safe. - if (!isStatic()) { - if (identifierTable()) - Identifier::remove(this); - - UString::BaseString* base = baseString(); - if (base == this) { - if (m_sharedBuffer) - m_sharedBuffer->deref(); - else - fastFree(base->buf); - } else - base->deref(); - - delete this; - } -} - -// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's -// or anything like that. -const unsigned PHI = 0x9e3779b9U; - -// Paul Hsieh's SuperFastHash -// http://www.azillionmonkeys.com/qed/hash.html -unsigned UString::Rep::computeHash(const UChar* s, int len) -{ - unsigned l = len; - uint32_t hash = PHI; - uint32_t tmp; - - int rem = l & 1; - l >>= 1; - - // Main loop - for (; l > 0; l--) { - hash += s[0]; - tmp = (s[1] << 11) ^ hash; - hash = (hash << 16) ^ tmp; - s += 2; - hash += hash >> 11; - } - - // Handle end case - if (rem) { - hash += s[0]; - hash ^= hash << 11; - hash += hash >> 17; - } - - // Force "avalanching" of final 127 bits - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 2; - hash += hash >> 15; - hash ^= hash << 10; - - // this avoids ever returning a hash code of 0, since that is used to - // signal "hash not computed yet", using a value that is likely to be - // effectively the same as 0 when the low bits are masked - if (hash == 0) - hash = 0x80000000; - - return hash; -} - -// Paul Hsieh's SuperFastHash -// http://www.azillionmonkeys.com/qed/hash.html -unsigned UString::Rep::computeHash(const char* s, int l) -{ - // This hash is designed to work on 16-bit chunks at a time. But since the normal case - // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they - // were 16-bit chunks, which should give matching results - - uint32_t hash = PHI; - uint32_t tmp; - - size_t rem = l & 1; - l >>= 1; - - // Main loop - for (; l > 0; l--) { - hash += static_cast<unsigned char>(s[0]); - tmp = (static_cast<unsigned char>(s[1]) << 11) ^ hash; - hash = (hash << 16) ^ tmp; - s += 2; - hash += hash >> 11; - } - - // Handle end case - if (rem) { - hash += static_cast<unsigned char>(s[0]); - hash ^= hash << 11; - hash += hash >> 17; - } - - // Force "avalanching" of final 127 bits - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 2; - hash += hash >> 15; - hash ^= hash << 10; - - // this avoids ever returning a hash code of 0, since that is used to - // signal "hash not computed yet", using a value that is likely to be - // effectively the same as 0 when the low bits are masked - if (hash == 0) - hash = 0x80000000; - - return hash; -} - -#ifndef NDEBUG -void UString::Rep::checkConsistency() const -{ - const UString::BaseString* base = baseString(); - - // There is no recursion for base strings. - ASSERT(base == base->baseString()); - - if (isStatic()) { - // There are only two static strings: null and empty. - ASSERT(!len); - - // Static strings cannot get in identifier tables, because they are globally shared. - ASSERT(!identifierTable()); - } - - // The string fits in buffer. - ASSERT(base->usedPreCapacity <= base->preCapacity); - ASSERT(base->usedCapacity <= base->capacity); - ASSERT(-offset <= base->usedPreCapacity); - ASSERT(offset + len <= base->usedCapacity); -} -#endif - -UString::SharedUChar* UString::BaseString::sharedBuffer() -{ - if (!m_sharedBuffer) - setSharedBuffer(SharedUChar::create(new OwnFastMallocPtr<UChar>(buf))); - return m_sharedBuffer; -} - -void UString::BaseString::setSharedBuffer(PassRefPtr<UString::SharedUChar> sharedBuffer) -{ - // The manual steps below are because m_sharedBuffer can't be a RefPtr. m_sharedBuffer - // is in a union with another variable to avoid making BaseString any larger. - if (m_sharedBuffer) - m_sharedBuffer->deref(); - m_sharedBuffer = sharedBuffer.releaseRef(); -} - -bool UString::BaseString::slowIsBufferReadOnly() -{ - // The buffer may not be modified as soon as the underlying data has been shared with another class. - if (m_sharedBuffer->isShared()) - return true; - - // At this point, we know it that the underlying buffer isn't shared outside of this base class, - // so get rid of m_sharedBuffer. - OwnPtr<OwnFastMallocPtr<UChar> > mallocPtr(m_sharedBuffer->release()); - UChar* unsharedBuf = const_cast<UChar*>(mallocPtr->release()); - setSharedBuffer(0); - preCapacity += (buf - unsharedBuf); - buf = unsharedBuf; - return false; -} - -// Put these early so they can be inlined. -static inline size_t expandedSize(size_t capacitySize, size_t precapacitySize) -{ - // Combine capacitySize & precapacitySize to produce a single size to allocate, - // check that doing so does not result in overflow. - size_t size = capacitySize + precapacitySize; - if (size < capacitySize) - return overflowIndicator(); - - // Small Strings (up to 4 pages): - // Expand the allocation size to 112.5% of the amount requested. This is largely sicking - // to our previous policy, however 112.5% is cheaper to calculate. - if (size < 0x4000) { - size_t expandedSize = ((size + (size >> 3)) | 15) + 1; - // Given the limited range within which we calculate the expansion in this - // fashion the above calculation should never overflow. - ASSERT(expandedSize >= size); - ASSERT(expandedSize < maxUChars()); - return expandedSize; - } - - // Medium Strings (up to 128 pages): - // For pages covering multiple pages over-allocation is less of a concern - any unused - // space will not be paged in if it is not used, so this is purely a VM overhead. For - // these strings allocate 2x the requested size. - if (size < 0x80000) { - size_t expandedSize = ((size + size) | 0xfff) + 1; - // Given the limited range within which we calculate the expansion in this - // fashion the above calculation should never overflow. - ASSERT(expandedSize >= size); - ASSERT(expandedSize < maxUChars()); - return expandedSize; - } - - // Large Strings (to infinity and beyond!): - // Revert to our 112.5% policy - probably best to limit the amount of unused VM we allow - // any individual string be responsible for. - size_t expandedSize = ((size + (size >> 3)) | 0xfff) + 1; - - // Check for overflow - any result that is at least as large as requested (but - // still below the limit) is okay. - if ((expandedSize >= size) && (expandedSize < maxUChars())) - return expandedSize; - return overflowIndicator(); -} - -static inline bool expandCapacity(UString::Rep* rep, int requiredLength) -{ - rep->checkConsistency(); - ASSERT(!rep->baseString()->isBufferReadOnly()); - - UString::BaseString* base = rep->baseString(); - - if (requiredLength > base->capacity) { - size_t newCapacity = expandedSize(requiredLength, base->preCapacity); - UChar* oldBuf = base->buf; - if (!reallocChars(base->buf, newCapacity).getValue(base->buf)) { - base->buf = oldBuf; - return false; - } - base->capacity = newCapacity - base->preCapacity; - } - if (requiredLength > base->usedCapacity) - base->usedCapacity = requiredLength; - - rep->checkConsistency(); - return true; -} - -bool UString::Rep::reserveCapacity(int capacity) -{ - // If this is an empty string there is no point 'growing' it - just allocate a new one. - // If the BaseString is shared with another string that is using more capacity than this - // string is, then growing the buffer won't help. - // If the BaseString's buffer is readonly, then it isn't allowed to grow. - UString::BaseString* base = baseString(); - if (!base->buf || !base->capacity || (offset + len) != base->usedCapacity || base->isBufferReadOnly()) - return false; - - // If there is already sufficient capacity, no need to grow! - if (capacity <= base->capacity) - return true; - - checkConsistency(); - - size_t newCapacity = expandedSize(capacity, base->preCapacity); - UChar* oldBuf = base->buf; - if (!reallocChars(base->buf, newCapacity).getValue(base->buf)) { - base->buf = oldBuf; - return false; - } - base->capacity = newCapacity - base->preCapacity; - - checkConsistency(); - return true; -} - -void UString::expandCapacity(int requiredLength) -{ - if (!JSC::expandCapacity(m_rep.get(), requiredLength)) - makeNull(); -} - -void UString::expandPreCapacity(int requiredPreCap) -{ - m_rep->checkConsistency(); - ASSERT(!m_rep->baseString()->isBufferReadOnly()); - - BaseString* base = m_rep->baseString(); - - if (requiredPreCap > base->preCapacity) { - size_t newCapacity = expandedSize(requiredPreCap, base->capacity); - int delta = newCapacity - base->capacity - base->preCapacity; - - UChar* newBuf; - if (!allocChars(newCapacity).getValue(newBuf)) { - makeNull(); - return; - } - copyChars(newBuf + delta, base->buf, base->capacity + base->preCapacity); - fastFree(base->buf); - base->buf = newBuf; + if (!c[0]) + return &UString::Rep::empty(); - base->preCapacity = newCapacity - base->capacity; - } - if (requiredPreCap > base->usedPreCapacity) - base->usedPreCapacity = requiredPreCap; + size_t length = strlen(c); + UChar* d; + PassRefPtr<UStringImpl> result = UStringImpl::tryCreateUninitialized(length, d); + if (!result) + return &UString::Rep::null(); - m_rep->checkConsistency(); + for (size_t i = 0; i < length; i++) + d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend + return result; } -static PassRefPtr<UString::Rep> createRep(const char* c) +static inline PassRefPtr<UString::Rep> createRep(const char* c, int length) { if (!c) return &UString::Rep::null(); - if (!c[0]) + if (!length) return &UString::Rep::empty(); - size_t length = strlen(c); UChar* d; - if (!allocChars(length).getValue(d)) + PassRefPtr<UStringImpl> result = UStringImpl::tryCreateUninitialized(length, d); + if (!result) return &UString::Rep::null(); - else { - for (size_t i = 0; i < length; i++) - d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend - return UString::Rep::create(d, static_cast<int>(length)); - } + for (int i = 0; i < length; i++) + d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend + return result; } UString::UString(const char* c) @@ -583,335 +202,31 @@ UString::UString(const char* c) { } -UString::UString(const UChar* c, int length) +UString::UString(const char* c, int length) + : m_rep(createRep(c, length)) { - if (length == 0) - m_rep = &Rep::empty(); - else - m_rep = Rep::createCopying(c, length); } -UString::UString(UChar* c, int length, bool copy) +UString::UString(const UChar* c, int length) { - if (length == 0) + if (length == 0) m_rep = &Rep::empty(); - else if (copy) - m_rep = Rep::createCopying(c, length); else m_rep = Rep::create(c, length); } -UString::UString(const Vector<UChar>& buffer) -{ - if (!buffer.size()) - m_rep = &Rep::empty(); - else - m_rep = Rep::createCopying(buffer.data(), buffer.size()); -} - -static ALWAYS_INLINE int newCapacityWithOverflowCheck(const int currentCapacity, const int extendLength, const bool plusOne = false) -{ - ASSERT_WITH_MESSAGE(extendLength >= 0, "extendedLength = %d", extendLength); - - const int plusLength = plusOne ? 1 : 0; - if (currentCapacity > std::numeric_limits<int>::max() - extendLength - plusLength) - CRASH(); - - return currentCapacity + extendLength + plusLength; -} - -static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Rep> r, const UChar* tData, int tSize) -{ - RefPtr<UString::Rep> rep = r; - - rep->checkConsistency(); - - int thisSize = rep->size(); - int thisOffset = rep->offset; - int length = thisSize + tSize; - UString::BaseString* base = rep->baseString(); - - // possible cases: - if (tSize == 0) { - // t is empty - } else if (thisSize == 0) { - // this is empty - rep = UString::Rep::createCopying(tData, tSize); - } else if (rep == base && !base->isShared()) { - // this is direct and has refcount of 1 (so we can just alter it directly) - if (!expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length))) - rep = &UString::Rep::null(); - if (rep->data()) { - copyChars(rep->data() + thisSize, tData, tSize); - rep->len = length; - rep->_hash = 0; - } - } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize && !base->isBufferReadOnly()) { - // this reaches the end of the buffer - extend it if it's long enough to append to - if (!expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length))) - rep = &UString::Rep::null(); - if (rep->data()) { - copyChars(rep->data() + thisSize, tData, tSize); - rep = UString::Rep::create(rep, 0, length); - } - } else { - // This is shared in some way that prevents us from modifying base, so we must make a whole new string. - size_t newCapacity = expandedSize(length, 0); - UChar* d; - if (!allocChars(newCapacity).getValue(d)) - rep = &UString::Rep::null(); - else { - copyChars(d, rep->data(), thisSize); - copyChars(d + thisSize, tData, tSize); - rep = UString::Rep::create(d, length); - rep->baseString()->capacity = newCapacity; - } - } - - rep->checkConsistency(); - - return rep.release(); -} - -static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Rep> r, const char* t) -{ - RefPtr<UString::Rep> rep = r; - - rep->checkConsistency(); - - int thisSize = rep->size(); - int thisOffset = rep->offset; - int tSize = static_cast<int>(strlen(t)); - int length = thisSize + tSize; - UString::BaseString* base = rep->baseString(); - - // possible cases: - if (thisSize == 0) { - // this is empty - rep = createRep(t); - } else if (tSize == 0) { - // t is empty, we'll just return *this below. - } else if (rep == base && !base->isShared()) { - // this is direct and has refcount of 1 (so we can just alter it directly) - expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length)); - UChar* d = rep->data(); - if (d) { - for (int i = 0; i < tSize; ++i) - d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend - rep->len = length; - rep->_hash = 0; - } - } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize && !base->isBufferReadOnly()) { - // this string reaches the end of the buffer - extend it - expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length)); - UChar* d = rep->data(); - if (d) { - for (int i = 0; i < tSize; ++i) - d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend - rep = UString::Rep::create(rep, 0, length); - } - } else { - // This is shared in some way that prevents us from modifying base, so we must make a whole new string. - size_t newCapacity = expandedSize(length, 0); - UChar* d; - if (!allocChars(newCapacity).getValue(d)) - rep = &UString::Rep::null(); - else { - copyChars(d, rep->data(), thisSize); - for (int i = 0; i < tSize; ++i) - d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend - rep = UString::Rep::create(d, length); - rep->baseString()->capacity = newCapacity; - } - } - - rep->checkConsistency(); - - return rep.release(); -} - -PassRefPtr<UString::Rep> concatenate(UString::Rep* a, UString::Rep* b) -{ - a->checkConsistency(); - b->checkConsistency(); - - int aSize = a->size(); - int bSize = b->size(); - int aOffset = a->offset; - - // possible cases: - - UString::BaseString* aBase = a->baseString(); - if (bSize == 1 && aOffset + aSize == aBase->usedCapacity && aOffset + aSize < aBase->capacity && !aBase->isBufferReadOnly()) { - // b is a single character (common fast case) - ++aBase->usedCapacity; - a->data()[aSize] = b->data()[0]; - return UString::Rep::create(a, 0, aSize + 1); - } - - // a is empty - if (aSize == 0) - return b; - // b is empty - if (bSize == 0) - return a; - - int bOffset = b->offset; - int length = aSize + bSize; - - UString::BaseString* bBase = b->baseString(); - if (aOffset + aSize == aBase->usedCapacity && aSize >= minShareSize && 4 * aSize >= bSize - && (-bOffset != bBase->usedPreCapacity || aSize >= bSize) && !aBase->isBufferReadOnly()) { - // - a reaches the end of its buffer so it qualifies for shared append - // - also, it's at least a quarter the length of b - appending to a much shorter - // string does more harm than good - // - however, if b qualifies for prepend and is longer than a, we'd rather prepend - - UString x(a); - x.expandCapacity(newCapacityWithOverflowCheck(aOffset, length)); - if (!a->data() || !x.data()) - return 0; - copyChars(a->data() + aSize, b->data(), bSize); - PassRefPtr<UString::Rep> result = UString::Rep::create(a, 0, length); - - a->checkConsistency(); - b->checkConsistency(); - result->checkConsistency(); - - return result; - } - - if (-bOffset == bBase->usedPreCapacity && bSize >= minShareSize && 4 * bSize >= aSize && !bBase->isBufferReadOnly()) { - // - b reaches the beginning of its buffer so it qualifies for shared prepend - // - also, it's at least a quarter the length of a - prepending to a much shorter - // string does more harm than good - UString y(b); - y.expandPreCapacity(-bOffset + aSize); - if (!b->data() || !y.data()) - return 0; - copyChars(b->data() - aSize, a->data(), aSize); - PassRefPtr<UString::Rep> result = UString::Rep::create(b, -aSize, length); - - a->checkConsistency(); - b->checkConsistency(); - result->checkConsistency(); - - return result; - } - - // a does not qualify for append, and b does not qualify for prepend, gotta make a whole new string - size_t newCapacity = expandedSize(length, 0); - UChar* d; - if (!allocChars(newCapacity).getValue(d)) - return 0; - copyChars(d, a->data(), aSize); - copyChars(d + aSize, b->data(), bSize); - PassRefPtr<UString::Rep> result = UString::Rep::create(d, length); - result->baseString()->capacity = newCapacity; - - a->checkConsistency(); - b->checkConsistency(); - result->checkConsistency(); - - return result; -} - -PassRefPtr<UString::Rep> concatenate(UString::Rep* rep, int i) -{ - UChar buf[1 + sizeof(i) * 3]; - UChar* end = buf + sizeof(buf) / sizeof(UChar); - UChar* p = end; - - if (i == 0) - *--p = '0'; - else if (i == INT_MIN) { - char minBuf[1 + sizeof(i) * 3]; - sprintf(minBuf, "%d", INT_MIN); - return concatenate(rep, minBuf); - } else { - bool negative = false; - if (i < 0) { - negative = true; - i = -i; - } - while (i) { - *--p = static_cast<unsigned short>((i % 10) + '0'); - i /= 10; - } - if (negative) - *--p = '-'; - } - - return concatenate(rep, p, static_cast<int>(end - p)); - -} - -PassRefPtr<UString::Rep> concatenate(UString::Rep* rep, double d) +UString UString::createFromUTF8(const char* string) { - // avoid ever printing -NaN, in JS conceptually there is only one NaN value - if (isnan(d)) - return concatenate(rep, "NaN"); - - if (d == 0.0) // stringify -0 as 0 - d = 0.0; + if (!string) + return null(); - char buf[80]; - int decimalPoint; - int sign; + size_t length = strlen(string); + Vector<UChar, 1024> buffer(length); + UChar* p = buffer.data(); + if (conversionOK != convertUTF8ToUTF16(&string, string + length, &p, p + length)) + return null(); - char result[80]; - WTF::dtoa(result, d, 0, &decimalPoint, &sign, NULL); - int length = static_cast<int>(strlen(result)); - - int i = 0; - if (sign) - buf[i++] = '-'; - - if (decimalPoint <= 0 && decimalPoint > -6) { - buf[i++] = '0'; - buf[i++] = '.'; - for (int j = decimalPoint; j < 0; j++) - buf[i++] = '0'; - strcpy(buf + i, result); - } else if (decimalPoint <= 21 && decimalPoint > 0) { - if (length <= decimalPoint) { - strcpy(buf + i, result); - i += length; - for (int j = 0; j < decimalPoint - length; j++) - buf[i++] = '0'; - buf[i] = '\0'; - } else { - strncpy(buf + i, result, decimalPoint); - i += decimalPoint; - buf[i++] = '.'; - strcpy(buf + i, result + decimalPoint); - } - } else if (result[0] < '0' || result[0] > '9') - strcpy(buf + i, result); - else { - buf[i++] = result[0]; - if (length > 1) { - buf[i++] = '.'; - strcpy(buf + i, result + 1); - i += length - 1; - } - - buf[i++] = 'e'; - buf[i++] = (decimalPoint >= 0) ? '+' : '-'; - // decimalPoint can't be more than 3 digits decimal given the - // nature of float representation - int exponential = decimalPoint - 1; - if (exponential < 0) - exponential = -exponential; - if (exponential >= 100) - buf[i++] = static_cast<char>('0' + exponential / 100); - if (exponential >= 10) - buf[i++] = static_cast<char>('0' + (exponential % 100) / 10); - buf[i++] = static_cast<char>('0' + exponential % 10); - buf[i++] = '\0'; - } - - return concatenate(rep, buf); + return UString(buffer.data(), p - buffer.data()); } UString UString::from(int i) @@ -953,7 +268,7 @@ UString UString::from(long long i) *--p = '0'; else if (i == std::numeric_limits<long long>::min()) { char minBuf[1 + sizeof(i) * 3]; -#if PLATFORM(WIN_OS) +#if OS(WINDOWS) snprintf(minBuf, sizeof(minBuf) - 1, "%I64d", std::numeric_limits<long long>::min()); #else snprintf(minBuf, sizeof(minBuf) - 1, "%lld", std::numeric_limits<long long>::min()); @@ -1025,69 +340,10 @@ UString UString::from(long l) UString UString::from(double d) { - // avoid ever printing -NaN, in JS conceptually there is only one NaN value - if (isnan(d)) - return "NaN"; - if (!d) - return "0"; // -0 -> "0" - - char buf[80]; - int decimalPoint; - int sign; - - char result[80]; - WTF::dtoa(result, d, 0, &decimalPoint, &sign, NULL); - int length = static_cast<int>(strlen(result)); - - int i = 0; - if (sign) - buf[i++] = '-'; - - if (decimalPoint <= 0 && decimalPoint > -6) { - buf[i++] = '0'; - buf[i++] = '.'; - for (int j = decimalPoint; j < 0; j++) - buf[i++] = '0'; - strcpy(buf + i, result); - } else if (decimalPoint <= 21 && decimalPoint > 0) { - if (length <= decimalPoint) { - strcpy(buf + i, result); - i += length; - for (int j = 0; j < decimalPoint - length; j++) - buf[i++] = '0'; - buf[i] = '\0'; - } else { - strncpy(buf + i, result, decimalPoint); - i += decimalPoint; - buf[i++] = '.'; - strcpy(buf + i, result + decimalPoint); - } - } else if (result[0] < '0' || result[0] > '9') - strcpy(buf + i, result); - else { - buf[i++] = result[0]; - if (length > 1) { - buf[i++] = '.'; - strcpy(buf + i, result + 1); - i += length - 1; - } - - buf[i++] = 'e'; - buf[i++] = (decimalPoint >= 0) ? '+' : '-'; - // decimalPoint can't be more than 3 digits decimal given the - // nature of float representation - int exponential = decimalPoint - 1; - if (exponential < 0) - exponential = -exponential; - if (exponential >= 100) - buf[i++] = static_cast<char>('0' + exponential / 100); - if (exponential >= 10) - buf[i++] = static_cast<char>('0' + (exponential % 100) / 10); - buf[i++] = static_cast<char>('0' + exponential % 10); - buf[i++] = '\0'; - } - - return UString(buf); + DtoaBuffer buffer; + unsigned length; + doubleToStringInJavaScriptFormat(d, buffer, &length); + return UString(buffer, length); } UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const @@ -1113,23 +369,24 @@ UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, in return ""; UChar* buffer; - if (!allocChars(totalLength).getValue(buffer)) + PassRefPtr<Rep> rep = Rep::tryCreateUninitialized(totalLength, buffer); + if (!rep) return null(); int maxCount = max(rangeCount, separatorCount); int bufferPos = 0; for (int i = 0; i < maxCount; i++) { if (i < rangeCount) { - copyChars(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length); + UStringImpl::copyChars(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length); bufferPos += substringRanges[i].length; } if (i < separatorCount) { - copyChars(buffer + bufferPos, separators[i].data(), separators[i].size()); + UStringImpl::copyChars(buffer + bufferPos, separators[i].data(), separators[i].size()); bufferPos += separators[i].size(); } } - return UString::Rep::create(buffer, totalLength); + return rep; } UString UString::replaceRange(int rangeStart, int rangeLength, const UString& replacement) const @@ -1142,136 +399,16 @@ UString UString::replaceRange(int rangeStart, int rangeLength, const UString& re return ""; UChar* buffer; - if (!allocChars(totalLength).getValue(buffer)) + PassRefPtr<Rep> rep = Rep::tryCreateUninitialized(totalLength, buffer); + if (!rep) return null(); - copyChars(buffer, data(), rangeStart); - copyChars(buffer + rangeStart, replacement.data(), replacementLength); + UStringImpl::copyChars(buffer, data(), rangeStart); + UStringImpl::copyChars(buffer + rangeStart, replacement.data(), replacementLength); int rangeEnd = rangeStart + rangeLength; - copyChars(buffer + rangeStart + replacementLength, data() + rangeEnd, size() - rangeEnd); - - return UString::Rep::create(buffer, totalLength); -} - - -UString& UString::append(const UString &t) -{ - m_rep->checkConsistency(); - t.rep()->checkConsistency(); - - int thisSize = size(); - int thisOffset = m_rep->offset; - int tSize = t.size(); - int length = thisSize + tSize; - BaseString* base = m_rep->baseString(); - - // possible cases: - if (thisSize == 0) { - // this is empty - *this = t; - } else if (tSize == 0) { - // t is empty - } else if (m_rep == base && !base->isShared()) { - // this is direct and has refcount of 1 (so we can just alter it directly) - expandCapacity(newCapacityWithOverflowCheck(thisOffset, length)); - if (data()) { - copyChars(m_rep->data() + thisSize, t.data(), tSize); - m_rep->len = length; - m_rep->_hash = 0; - } - } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize && !base->isBufferReadOnly()) { - // this reaches the end of the buffer - extend it if it's long enough to append to - expandCapacity(newCapacityWithOverflowCheck(thisOffset, length)); - if (data()) { - copyChars(m_rep->data() + thisSize, t.data(), tSize); - m_rep = Rep::create(m_rep, 0, length); - } - } else { - // This is shared in some way that prevents us from modifying base, so we must make a whole new string. - size_t newCapacity = expandedSize(length, 0); - UChar* d; - if (!allocChars(newCapacity).getValue(d)) - makeNull(); - else { - copyChars(d, data(), thisSize); - copyChars(d + thisSize, t.data(), tSize); - m_rep = Rep::create(d, length); - m_rep->baseString()->capacity = newCapacity; - } - } - - m_rep->checkConsistency(); - t.rep()->checkConsistency(); - - return *this; -} - -UString& UString::append(const UChar* tData, int tSize) -{ - m_rep = concatenate(m_rep.release(), tData, tSize); - return *this; -} - -UString& UString::append(const char* t) -{ - m_rep = concatenate(m_rep.release(), t); - return *this; -} - -UString& UString::append(UChar c) -{ - m_rep->checkConsistency(); + UStringImpl::copyChars(buffer + rangeStart + replacementLength, data() + rangeEnd, size() - rangeEnd); - int thisOffset = m_rep->offset; - int length = size(); - BaseString* base = m_rep->baseString(); - - // possible cases: - if (length == 0) { - // this is empty - must make a new m_rep because we don't want to pollute the shared empty one - size_t newCapacity = expandedSize(1, 0); - UChar* d; - if (!allocChars(newCapacity).getValue(d)) - makeNull(); - else { - d[0] = c; - m_rep = Rep::create(d, 1); - m_rep->baseString()->capacity = newCapacity; - } - } else if (m_rep == base && !base->isShared()) { - // this is direct and has refcount of 1 (so we can just alter it directly) - expandCapacity(newCapacityWithOverflowCheck(thisOffset, length, true)); - UChar* d = m_rep->data(); - if (d) { - d[length] = c; - m_rep->len = length + 1; - m_rep->_hash = 0; - } - } else if (thisOffset + length == base->usedCapacity && length >= minShareSize && !base->isBufferReadOnly()) { - // this reaches the end of the string - extend it and share - expandCapacity(newCapacityWithOverflowCheck(thisOffset, length, true)); - UChar* d = m_rep->data(); - if (d) { - d[length] = c; - m_rep = Rep::create(m_rep, 0, length + 1); - } - } else { - // This is shared in some way that prevents us from modifying base, so we must make a whole new string. - size_t newCapacity = expandedSize(length + 1, 0); - UChar* d; - if (!allocChars(newCapacity).getValue(d)) - makeNull(); - else { - copyChars(d, data(), length); - d[length] = c; - m_rep = Rep::create(d, length + 1); - m_rep->baseString()->capacity = newCapacity; - } - } - - m_rep->checkConsistency(); - - return *this; + return rep; } bool UString::getCString(CStringBuffer& buffer) const @@ -1299,13 +436,15 @@ bool UString::getCString(CStringBuffer& buffer) const char* UString::ascii() const { + static char* asciiBuffer = 0; + int length = size(); int neededSize = length + 1; - delete[] statBuffer; - statBuffer = new char[neededSize]; + delete[] asciiBuffer; + asciiBuffer = new char[neededSize]; const UChar* p = data(); - char* q = statBuffer; + char* q = asciiBuffer; const UChar* limit = p + length; while (p != limit) { *q = static_cast<char>(p[0]); @@ -1314,7 +453,7 @@ char* UString::ascii() const } *q = '\0'; - return statBuffer; + return asciiBuffer; } UString& UString::operator=(const char* c) @@ -1330,21 +469,13 @@ UString& UString::operator=(const char* c) } int l = static_cast<int>(strlen(c)); - UChar* d; - BaseString* base = m_rep->baseString(); - if (!base->isShared() && l <= base->capacity && m_rep == base && m_rep->offset == 0 && base->preCapacity == 0) { - d = base->buf; - m_rep->_hash = 0; - m_rep->len = l; - } else { - if (!allocChars(l).getValue(d)) { - makeNull(); - return *this; - } - m_rep = Rep::create(d, l); - } - for (int i = 0; i < l; i++) - d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend + UChar* d = 0; + m_rep = Rep::tryCreateUninitialized(l, d); + if (m_rep) { + for (int i = 0; i < l; i++) + d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend + } else + makeNull(); return *this; } @@ -1502,7 +633,7 @@ uint32_t UString::toStrictUInt32(bool* ok) const *ok = false; // Empty string is not OK. - int len = m_rep->len; + int len = m_rep->size(); if (len == 0) return 0; const UChar* p = m_rep->data(); @@ -1727,10 +858,15 @@ int compare(const UString& s1, const UString& s2) return (l1 > l2) ? 1 : -1; } +#if OS(SOLARIS) && COMPILER(SUNCC) +// Signature must match that of UStringImpl.h, otherwise the linker complains about undefined symbol. +bool equal(const UStringImpl* r, const UStringImpl* b) +#else bool equal(const UString::Rep* r, const UString::Rep* b) +#endif { - int length = r->len; - if (length != b->len) + int length = r->size(); + if (length != b->size()) return false; const UChar* d = r->data(); const UChar* s = b->data(); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UString.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UString.h index 58c3615..c1f32db 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UString.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UString.h @@ -24,6 +24,7 @@ #define UString_h #include "Collector.h" +#include "UStringImpl.h" #include <stdint.h> #include <string.h> #include <wtf/Assertions.h> @@ -35,13 +36,15 @@ #include <wtf/Vector.h> #include <wtf/unicode/Unicode.h> +#if PLATFORM(QT) +#include <QtCore/qstring.h> +#endif + namespace JSC { using WTF::PlacementNewAdoptType; using WTF::PlacementNewAdopt; - class IdentifierTable; - class CString { public: CString() @@ -71,192 +74,58 @@ namespace JSC { char* m_data; }; + bool operator==(const CString&, const CString&); + typedef Vector<char, 32> CStringBuffer; class UString { friend class JIT; public: +#if PLATFORM(QT) + operator QT_PREPEND_NAMESPACE(QString)() const + { + return QT_PREPEND_NAMESPACE(QString)(reinterpret_cast<const QT_PREPEND_NAMESPACE(QChar)*>(this->data()), this->size()); + } - typedef CrossThreadRefCounted<OwnFastMallocPtr<UChar> > SharedUChar; - struct BaseString; - struct Rep : Noncopyable { - friend class JIT; - - static PassRefPtr<Rep> create(UChar* buffer, int length) - { - return adoptRef(new BaseString(buffer, length)); - } - - static PassRefPtr<Rep> createEmptyBuffer(size_t size) - { - // Guard against integer overflow - if (size < (std::numeric_limits<size_t>::max() / sizeof(UChar))) { - void* buf = 0; - if (tryFastMalloc(size * sizeof(UChar)).getValue(buf)) - return adoptRef(new BaseString(static_cast<UChar*>(buf), 0, size)); - } - return adoptRef(new BaseString(0, 0, 0)); - } - - static PassRefPtr<Rep> createCopying(const UChar*, int); - static PassRefPtr<Rep> create(PassRefPtr<Rep> base, int offset, int length); - - // Constructs a string from a UTF-8 string, using strict conversion (see comments in UTF8.h). - // Returns UString::Rep::null for null input or conversion failure. - static PassRefPtr<Rep> createFromUTF8(const char*); - - // 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); } - UChar* data() const; - int size() const { return len; } - - unsigned hash() const { if (_hash == 0) _hash = computeHash(data(), len); return _hash; } - unsigned computedHash() const { ASSERT(_hash); return _hash; } // fast path for Identifiers - - static unsigned computeHash(const UChar*, int length); - static unsigned computeHash(const char*, int length); - static unsigned computeHash(const char* s) { return computeHash(s, strlen(s)); } - - IdentifierTable* identifierTable() const { return m_identifierTableAndFlags.get(); } - void setIdentifierTable(IdentifierTable* table) { ASSERT(!isStatic()); m_identifierTableAndFlags.set(table); } - - bool isStatic() const { return m_identifierTableAndFlags.isFlagSet(StaticFlag); } - void setStatic(bool); - void setBaseString(PassRefPtr<BaseString>); - BaseString* baseString(); - const BaseString* baseString() const; - - Rep* ref() { ++rc; return this; } - ALWAYS_INLINE void deref() { if (--rc == 0) destroy(); } - - void checkConsistency() const; - enum UStringFlags { - StaticFlag, - BaseStringFlag - }; - - // unshared data - int offset; - int len; - int rc; // For null and empty static strings, this field does not reflect a correct count, because ref/deref are not thread-safe. A special case in destroy() guarantees that these do not get deleted. - mutable unsigned _hash; - PtrAndFlags<IdentifierTable, UStringFlags> m_identifierTableAndFlags; - - static BaseString& null() { return *nullBaseString; } - static BaseString& empty() { return *emptyBaseString; } - - bool reserveCapacity(int capacity); - - protected: - // Constructor for use by BaseString subclass; they use the union with m_baseString for another purpose. - Rep(int length) - : offset(0) - , len(length) - , rc(1) - , _hash(0) - , m_baseString(0) - { - } - - Rep(PassRefPtr<BaseString> base, int offsetInBase, int length) - : offset(offsetInBase) - , len(length) - , rc(1) - , _hash(0) - , m_baseString(base.releaseRef()) - { - checkConsistency(); - } - - union { - // If !baseIsSelf() - BaseString* m_baseString; - // If baseIsSelf() - SharedUChar* m_sharedBuffer; - }; - - private: - // For SmallStringStorage which allocates an array and does initialization manually. - Rep() { } - - friend class SmallStringsStorage; - friend void initializeUString(); - JS_EXPORTDATA static BaseString* nullBaseString; - JS_EXPORTDATA static BaseString* emptyBaseString; - }; - - - struct BaseString : public Rep { - bool isShared() { return rc != 1 || isBufferReadOnly(); } - void setSharedBuffer(PassRefPtr<SharedUChar>); - - bool isBufferReadOnly() - { - if (!m_sharedBuffer) - return false; - return slowIsBufferReadOnly(); - } - - // potentially shared data. - UChar* buf; - int preCapacity; - int usedPreCapacity; - int capacity; - int usedCapacity; - - size_t reportedCost; - - private: - BaseString(UChar* buffer, int length, int additionalCapacity = 0) - : Rep(length) - , buf(buffer) - , preCapacity(0) - , usedPreCapacity(0) - , capacity(length + additionalCapacity) - , usedCapacity(length) - , reportedCost(0) - { - m_identifierTableAndFlags.setFlag(BaseStringFlag); - checkConsistency(); - } - - SharedUChar* sharedBuffer(); - bool slowIsBufferReadOnly(); - - friend struct Rep; - friend class SmallStringsStorage; - friend void initializeUString(); - }; - + UString(const QT_PREPEND_NAMESPACE(QString)& str) + { + *this = JSC::UString(reinterpret_cast<const UChar*>(str.constData()), str.length()); + } +#endif + typedef UStringImpl Rep; + public: + // UString constructors passed char*s assume ISO Latin-1 encoding; for UTF8 use 'createFromUTF8', below. UString(); - UString(const char*); + UString(const char*); // Constructor for null-terminated string. + UString(const char*, int length); UString(const UChar*, int length); - UString(UChar*, int length, bool copy); + UString(const Vector<UChar>& buffer); UString(const UString& s) : m_rep(s.m_rep) { } - UString(const Vector<UChar>& buffer); + // Special constructor for cases where we overwrite an object in place. + UString(PlacementNewAdoptType) + : m_rep(PlacementNewAdopt) + { + } ~UString() { } - // Special constructor for cases where we overwrite an object in place. - UString(PlacementNewAdoptType) - : m_rep(PlacementNewAdopt) + template<size_t inlineCapacity> + static PassRefPtr<UStringImpl> adopt(Vector<UChar, inlineCapacity>& vector) { + return Rep::adopt(vector); } + static UString createFromUTF8(const char*); + static UString from(int); static UString from(long long); static UString from(unsigned int); @@ -283,12 +152,6 @@ namespace JSC { UString replaceRange(int rangeStart, int RangeEnd, const UString& replacement) const; - UString& append(const UString&); - UString& append(const char*); - UString& append(UChar); - UString& append(char c) { return append(static_cast<UChar>(static_cast<unsigned char>(c))); } - UString& append(const UChar*, int size); - bool getCString(CStringBuffer&) const; // NOTE: This method should only be used for *debugging* purposes as it @@ -307,13 +170,10 @@ namespace JSC { UString& operator=(const char*c); - UString& operator+=(const UString& s) { return append(s); } - UString& operator+=(const char* s) { return append(s); } - const UChar* data() const { return m_rep->data(); } - bool isNull() const { return (m_rep == &Rep::null()); } - bool isEmpty() const { return (!m_rep->len); } + bool isNull() const { return m_rep == &Rep::null(); } + bool isEmpty() const { return !m_rep->size(); } bool is8Bit() const; @@ -349,36 +209,9 @@ namespace JSC { ASSERT(m_rep); } - size_t cost() const; - - // Attempt to grow this string such that it can grow to a total length of 'capacity' - // without reallocation. This may fail a number of reasons - if the BasicString is - // shared and another string is using part of the capacity beyond our end point, if - // the realloc fails, or if this string is empty and has no storage. - // - // This method returns a boolean indicating success. - bool reserveCapacity(int capacity) - { - return m_rep->reserveCapacity(capacity); - } - -#if PLATFORM(QT) - operator QT_PREPEND_NAMESPACE(QString)() const - { - QT_USE_NAMESPACE; - return QString(reinterpret_cast<const QChar*>(this->data()), this->size()); - } - - UString(const QT_PREPEND_NAMESPACE(QString)& str) - { - *this = JSC::UString(reinterpret_cast<const UChar*>(str.constData()), str.length()); - } -#endif - + size_t cost() const { return m_rep->cost(); } private: - void expandCapacity(int requiredLength); - void expandPreCapacity(int requiredPreCap); void makeNull(); RefPtr<Rep> m_rep; @@ -386,13 +219,9 @@ namespace JSC { friend void initializeUString(); friend bool operator==(const UString&, const UString&); - friend PassRefPtr<Rep> concatenate(Rep*, Rep*); // returns 0 if out of memory }; - PassRefPtr<UString::Rep> concatenate(UString::Rep*, UString::Rep*); - PassRefPtr<UString::Rep> concatenate(UString::Rep*, int); - PassRefPtr<UString::Rep> concatenate(UString::Rep*, double); - inline bool operator==(const UString& s1, const UString& s2) + ALWAYS_INLINE bool operator==(const UString& s1, const UString& s2) { int size = s1.size(); switch (size) { @@ -438,72 +267,8 @@ namespace JSC { return !JSC::operator==(s1, s2); } - bool operator==(const CString&, const CString&); - - inline UString operator+(const UString& s1, const UString& s2) - { - RefPtr<UString::Rep> result = concatenate(s1.rep(), s2.rep()); - return UString(result ? result.release() : UString::nullRep()); - } - int compare(const UString&, const UString&); - bool equal(const UString::Rep*, const UString::Rep*); - - inline PassRefPtr<UString::Rep> UString::Rep::create(PassRefPtr<UString::Rep> rep, int offset, int length) - { - ASSERT(rep); - rep->checkConsistency(); - - int repOffset = rep->offset; - - PassRefPtr<BaseString> base = rep->baseString(); - - ASSERT(-(offset + repOffset) <= base->usedPreCapacity); - ASSERT(offset + repOffset + length <= base->usedCapacity); - - // Steal the single reference this Rep was created with. - return adoptRef(new Rep(base, repOffset + offset, length)); - } - - inline UChar* UString::Rep::data() const - { - const BaseString* base = baseString(); - return base->buf + base->preCapacity + offset; - } - - inline void UString::Rep::setStatic(bool v) - { - ASSERT(!identifierTable()); - if (v) - m_identifierTableAndFlags.setFlag(StaticFlag); - else - m_identifierTableAndFlags.clearFlag(StaticFlag); - } - - inline void UString::Rep::setBaseString(PassRefPtr<BaseString> base) - { - ASSERT(base != this); - ASSERT(!baseIsSelf()); - m_baseString = base.releaseRef(); - } - - inline UString::BaseString* UString::Rep::baseString() - { - return !baseIsSelf() ? m_baseString : reinterpret_cast<BaseString*>(this) ; - } - - inline const UString::BaseString* UString::Rep::baseString() const - { - return const_cast<Rep*>(this)->baseString(); - } - -#ifdef NDEBUG - inline void UString::Rep::checkConsistency() const - { - } -#endif - inline UString::UString() : m_rep(&Rep::null()) { @@ -524,45 +289,288 @@ namespace JSC { // huge buffer. // FIXME: this should be size_t but that would cause warnings until we // fix UString sizes to be size_t instead of int - static const int minShareSize = Heap::minExtraCostSize / sizeof(UChar); + static const int minShareSize = Heap::minExtraCost / sizeof(UChar); - inline size_t UString::cost() const - { - BaseString* base = m_rep->baseString(); - size_t capacity = (base->capacity + base->preCapacity) * sizeof(UChar); - size_t reportedCost = base->reportedCost; - ASSERT(capacity >= reportedCost); + struct IdentifierRepHash : PtrHash<RefPtr<JSC::UString::Rep> > { + static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->existingHash(); } + static unsigned hash(JSC::UString::Rep* key) { return key->existingHash(); } + }; - size_t capacityDelta = capacity - reportedCost; + void initializeUString(); + + template<typename StringType> + class StringTypeAdapter { + }; - if (capacityDelta < static_cast<size_t>(minShareSize)) - return 0; + template<> + class StringTypeAdapter<char*> { + public: + StringTypeAdapter<char*>(char* buffer) + : m_buffer((unsigned char*)buffer) + , m_length(strlen(buffer)) + { + } - base->reportedCost = capacity; + unsigned length() { return m_length; } - return capacityDelta; - } + void writeTo(UChar* destination) + { + for (unsigned i = 0; i < m_length; ++i) + destination[i] = m_buffer[i]; + } -#if PLATFORM(QT) + private: + const unsigned char* m_buffer; + unsigned m_length; + }; - inline UString operator+(const char* s1, const UString& s2) + template<> + class StringTypeAdapter<const char*> { + public: + StringTypeAdapter<const char*>(const char* buffer) + : m_buffer((unsigned char*)buffer) + , m_length(strlen(buffer)) { - return operator+(UString(s1), s2); } - inline UString operator+(const UString& s1, const char* s2) + unsigned length() { return m_length; } + + void writeTo(UChar* destination) { - return operator+(s1, UString(s2)); + for (unsigned i = 0; i < m_length; ++i) + destination[i] = m_buffer[i]; } -#endif + private: + const unsigned char* m_buffer; + unsigned m_length; + }; - struct IdentifierRepHash : PtrHash<RefPtr<JSC::UString::Rep> > { - static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->computedHash(); } - static unsigned hash(JSC::UString::Rep* key) { return key->computedHash(); } + template<> + class StringTypeAdapter<UString> { + public: + StringTypeAdapter<UString>(UString& string) + : m_data(string.data()) + , m_length(string.size()) + { + } + + unsigned length() { return m_length; } + + void writeTo(UChar* destination) + { + for (unsigned i = 0; i < m_length; ++i) + destination[i] = m_data[i]; + } + + private: + const UChar* m_data; + unsigned m_length; }; - void initializeUString(); + template<typename StringType1, typename StringType2> + UString makeString(StringType1 string1, StringType2 string2) + { + StringTypeAdapter<StringType1> adapter1(string1); + StringTypeAdapter<StringType2> adapter2(string2); + + UChar* buffer; + unsigned length = adapter1.length() + adapter2.length(); + PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); + if (!resultImpl) + return UString(); + + UChar* result = buffer; + adapter1.writeTo(result); + result += adapter1.length(); + adapter2.writeTo(result); + + return resultImpl; + } + + template<typename StringType1, typename StringType2, typename StringType3> + UString makeString(StringType1 string1, StringType2 string2, StringType3 string3) + { + StringTypeAdapter<StringType1> adapter1(string1); + StringTypeAdapter<StringType2> adapter2(string2); + StringTypeAdapter<StringType3> adapter3(string3); + + UChar* buffer; + unsigned length = adapter1.length() + adapter2.length() + adapter3.length(); + PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); + if (!resultImpl) + return UString(); + + UChar* result = buffer; + adapter1.writeTo(result); + result += adapter1.length(); + adapter2.writeTo(result); + result += adapter2.length(); + adapter3.writeTo(result); + + return resultImpl; + } + + template<typename StringType1, typename StringType2, typename StringType3, typename StringType4> + UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4) + { + StringTypeAdapter<StringType1> adapter1(string1); + StringTypeAdapter<StringType2> adapter2(string2); + StringTypeAdapter<StringType3> adapter3(string3); + StringTypeAdapter<StringType4> adapter4(string4); + + UChar* buffer; + unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length(); + PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); + if (!resultImpl) + return UString(); + + UChar* result = buffer; + adapter1.writeTo(result); + result += adapter1.length(); + adapter2.writeTo(result); + result += adapter2.length(); + adapter3.writeTo(result); + result += adapter3.length(); + adapter4.writeTo(result); + + return resultImpl; + } + + template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5> + UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5) + { + StringTypeAdapter<StringType1> adapter1(string1); + StringTypeAdapter<StringType2> adapter2(string2); + StringTypeAdapter<StringType3> adapter3(string3); + StringTypeAdapter<StringType4> adapter4(string4); + StringTypeAdapter<StringType5> adapter5(string5); + + UChar* buffer; + unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length(); + PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); + if (!resultImpl) + return UString(); + + UChar* result = buffer; + adapter1.writeTo(result); + result += adapter1.length(); + adapter2.writeTo(result); + result += adapter2.length(); + adapter3.writeTo(result); + result += adapter3.length(); + adapter4.writeTo(result); + result += adapter4.length(); + adapter5.writeTo(result); + + return resultImpl; + } + + template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6> + UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6) + { + StringTypeAdapter<StringType1> adapter1(string1); + StringTypeAdapter<StringType2> adapter2(string2); + StringTypeAdapter<StringType3> adapter3(string3); + StringTypeAdapter<StringType4> adapter4(string4); + StringTypeAdapter<StringType5> adapter5(string5); + StringTypeAdapter<StringType6> adapter6(string6); + + UChar* buffer; + unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length(); + PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); + if (!resultImpl) + return UString(); + + UChar* result = buffer; + adapter1.writeTo(result); + result += adapter1.length(); + adapter2.writeTo(result); + result += adapter2.length(); + adapter3.writeTo(result); + result += adapter3.length(); + adapter4.writeTo(result); + result += adapter4.length(); + adapter5.writeTo(result); + result += adapter5.length(); + adapter6.writeTo(result); + + return resultImpl; + } + + template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7> + UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7) + { + StringTypeAdapter<StringType1> adapter1(string1); + StringTypeAdapter<StringType2> adapter2(string2); + StringTypeAdapter<StringType3> adapter3(string3); + StringTypeAdapter<StringType4> adapter4(string4); + StringTypeAdapter<StringType5> adapter5(string5); + StringTypeAdapter<StringType6> adapter6(string6); + StringTypeAdapter<StringType7> adapter7(string7); + + UChar* buffer; + unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length() + adapter7.length(); + PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); + if (!resultImpl) + return UString(); + + UChar* result = buffer; + adapter1.writeTo(result); + result += adapter1.length(); + adapter2.writeTo(result); + result += adapter2.length(); + adapter3.writeTo(result); + result += adapter3.length(); + adapter4.writeTo(result); + result += adapter4.length(); + adapter5.writeTo(result); + result += adapter5.length(); + adapter6.writeTo(result); + result += adapter6.length(); + adapter7.writeTo(result); + + return resultImpl; + } + + template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8> + UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8) + { + StringTypeAdapter<StringType1> adapter1(string1); + StringTypeAdapter<StringType2> adapter2(string2); + StringTypeAdapter<StringType3> adapter3(string3); + StringTypeAdapter<StringType4> adapter4(string4); + StringTypeAdapter<StringType5> adapter5(string5); + StringTypeAdapter<StringType6> adapter6(string6); + StringTypeAdapter<StringType7> adapter7(string7); + StringTypeAdapter<StringType8> adapter8(string8); + + UChar* buffer; + unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length() + adapter7.length() + adapter8.length(); + PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); + if (!resultImpl) + return UString(); + + UChar* result = buffer; + adapter1.writeTo(result); + result += adapter1.length(); + adapter2.writeTo(result); + result += adapter2.length(); + adapter3.writeTo(result); + result += adapter3.length(); + adapter4.writeTo(result); + result += adapter4.length(); + adapter5.writeTo(result); + result += adapter5.length(); + adapter6.writeTo(result); + result += adapter6.length(); + adapter7.writeTo(result); + result += adapter7.length(); + adapter8.writeTo(result); + + return resultImpl; + } + } // namespace JSC namespace WTF { diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UStringImpl.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UStringImpl.cpp new file mode 100644 index 0000000..4b0d1c9 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UStringImpl.cpp @@ -0,0 +1,82 @@ +/* + * 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 "UStringImpl.h" + +#include "Identifier.h" +#include "UString.h" +#include <wtf/unicode/UTF8.h> + +using namespace WTF::Unicode; +using namespace std; + +namespace JSC { + +SharedUChar* UStringImpl::baseSharedBuffer() +{ + ASSERT((bufferOwnership() == BufferShared) + || ((bufferOwnership() == BufferOwned) && !m_dataBuffer.asPtr<void*>())); + + if (bufferOwnership() != BufferShared) + m_dataBuffer = UntypedPtrAndBitfield(SharedUChar::create(new OwnFastMallocPtr<UChar>(m_data)).releaseRef(), BufferShared); + + return m_dataBuffer.asPtr<SharedUChar*>(); +} + +SharedUChar* UStringImpl::sharedBuffer() +{ + if (m_length < s_minLengthToShare) + return 0; + ASSERT(!isStatic()); + + UStringImpl* owner = bufferOwnerString(); + if (owner->bufferOwnership() == BufferInternal) + return 0; + + return owner->baseSharedBuffer(); +} + +UStringImpl::~UStringImpl() +{ + ASSERT(!isStatic()); + checkConsistency(); + + if (isIdentifier()) + Identifier::remove(this); + + if (bufferOwnership() != BufferInternal) { + if (bufferOwnership() == BufferOwned) + fastFree(m_data); + else if (bufferOwnership() == BufferSubstring) + m_dataBuffer.asPtr<UStringImpl*>()->deref(); + else { + ASSERT(bufferOwnership() == BufferShared); + m_dataBuffer.asPtr<SharedUChar*>()->deref(); + } + } +} + +} diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UStringImpl.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UStringImpl.h new file mode 100644 index 0000000..4e1ddc7 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/UStringImpl.h @@ -0,0 +1,313 @@ +/* + * 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 UStringImpl_h +#define UStringImpl_h + +#include <limits> +#include <wtf/CrossThreadRefCounted.h> +#include <wtf/OwnFastMallocPtr.h> +#include <wtf/PossiblyNull.h> +#include <wtf/StringHashFunctions.h> +#include <wtf/Vector.h> +#include <wtf/unicode/Unicode.h> + +namespace JSC { + +class IdentifierTable; + +typedef CrossThreadRefCounted<OwnFastMallocPtr<UChar> > SharedUChar; + +class UntypedPtrAndBitfield { +public: + UntypedPtrAndBitfield() {} + + UntypedPtrAndBitfield(void* ptrValue, uintptr_t bitValue) + : m_value(reinterpret_cast<uintptr_t>(ptrValue) | bitValue) +#ifndef NDEBUG + , m_leaksPtr(ptrValue) +#endif + { + ASSERT(ptrValue == asPtr<void*>()); + ASSERT((*this & ~s_alignmentMask) == bitValue); + } + + template<typename T> + T asPtr() const { return reinterpret_cast<T>(m_value & s_alignmentMask); } + + UntypedPtrAndBitfield& operator&=(uintptr_t bits) + { + m_value &= bits | s_alignmentMask; + return *this; + } + + UntypedPtrAndBitfield& operator|=(uintptr_t bits) + { + m_value |= bits & ~s_alignmentMask; + return *this; + } + + uintptr_t operator&(uintptr_t mask) const + { + return m_value & mask & ~s_alignmentMask; + } + +private: + static const uintptr_t s_alignmentMask = ~static_cast<uintptr_t>(0x7); + uintptr_t m_value; +#ifndef NDEBUG + void* m_leaksPtr; // Only used to allow tools like leaks on OSX to detect that the memory is referenced. +#endif +}; + +class UStringImpl : Noncopyable { +public: + template<size_t inlineCapacity> + static PassRefPtr<UStringImpl> adopt(Vector<UChar, inlineCapacity>& vector) + { + if (unsigned length = vector.size()) + return adoptRef(new UStringImpl(vector.releaseBuffer(), length, BufferOwned)); + return &empty(); + } + + static PassRefPtr<UStringImpl> create(const UChar* buffer, int length) + { + UChar* newBuffer; + if (PassRefPtr<UStringImpl> impl = tryCreateUninitialized(length, newBuffer)) { + copyChars(newBuffer, buffer, length); + return impl; + } + return &null(); + } + + static PassRefPtr<UStringImpl> create(PassRefPtr<UStringImpl> rep, int offset, int length) + { + ASSERT(rep); + rep->checkConsistency(); + return adoptRef(new UStringImpl(rep->m_data + offset, length, rep->bufferOwnerString())); + } + + static PassRefPtr<UStringImpl> create(PassRefPtr<SharedUChar> sharedBuffer, UChar* buffer, int length) + { + return adoptRef(new UStringImpl(buffer, length, sharedBuffer)); + } + + static PassRefPtr<UStringImpl> createUninitialized(unsigned length, UChar*& output) + { + if (!length) { + output = 0; + return &empty(); + } + + if (length > ((std::numeric_limits<size_t>::max() - sizeof(UStringImpl)) / sizeof(UChar))) + CRASH(); + UStringImpl* resultImpl = static_cast<UStringImpl*>(fastMalloc(sizeof(UChar) * length + sizeof(UStringImpl))); + output = reinterpret_cast<UChar*>(resultImpl + 1); + return adoptRef(new(resultImpl) UStringImpl(output, length, BufferInternal)); + } + + static PassRefPtr<UStringImpl> tryCreateUninitialized(unsigned length, UChar*& output) + { + if (!length) { + output = 0; + return &empty(); + } + + if (length > ((std::numeric_limits<size_t>::max() - sizeof(UStringImpl)) / sizeof(UChar))) + return 0; + UStringImpl* resultImpl; + if (!tryFastMalloc(sizeof(UChar) * length + sizeof(UStringImpl)).getValue(resultImpl)) + return 0; + output = reinterpret_cast<UChar*>(resultImpl + 1); + return adoptRef(new(resultImpl) UStringImpl(output, length, BufferInternal)); + } + + SharedUChar* sharedBuffer(); + UChar* data() const { return m_data; } + int size() const { return m_length; } + size_t cost() + { + // For substrings, return the cost of the base string. + if (bufferOwnership() == BufferSubstring) + return m_dataBuffer.asPtr<UStringImpl*>()->cost(); + + if (m_dataBuffer & s_reportedCostBit) + return 0; + m_dataBuffer |= s_reportedCostBit; + return m_length; + } + unsigned hash() const { if (!m_hash) m_hash = computeHash(data(), m_length); return m_hash; } + unsigned existingHash() const { ASSERT(m_hash); return m_hash; } // fast path for Identifiers + void setHash(unsigned hash) { ASSERT(hash == computeHash(data(), m_length)); m_hash = hash; } // fast path for Identifiers + bool isIdentifier() const { return m_isIdentifier; } + void setIsIdentifier(bool isIdentifier) { m_isIdentifier = isIdentifier; } + + UStringImpl* ref() { m_refCount += s_refCountIncrement; return this; } + ALWAYS_INLINE void deref() { if (!(m_refCount -= s_refCountIncrement)) delete this; } + + static void copyChars(UChar* destination, const UChar* source, unsigned numCharacters) + { + if (numCharacters <= s_copyCharsInlineCutOff) { + for (unsigned i = 0; i < numCharacters; ++i) + destination[i] = source[i]; + } else + memcpy(destination, source, numCharacters * sizeof(UChar)); + } + + static unsigned computeHash(const UChar* s, int length) { ASSERT(length >= 0); return WTF::stringHash(s, length); } + static unsigned computeHash(const char* s, int length) { ASSERT(length >= 0); return WTF::stringHash(s, length); } + static unsigned computeHash(const char* s) { return WTF::stringHash(s); } + + static UStringImpl& null() { return *s_null; } + static UStringImpl& empty() { return *s_empty; } + + ALWAYS_INLINE void checkConsistency() const + { + // There is no recursion of substrings. + ASSERT(bufferOwnerString()->bufferOwnership() != BufferSubstring); + // Static strings cannot be put in identifier tables, because they are globally shared. + ASSERT(!isStatic() || !isIdentifier()); + } + +private: + enum BufferOwnership { + BufferInternal, + BufferOwned, + BufferSubstring, + BufferShared, + }; + + // For SmallStringStorage, which allocates an array and uses an in-place new. + UStringImpl() { } + + // Used to construct normal strings with an internal or external buffer. + UStringImpl(UChar* data, int length, BufferOwnership ownership) + : m_data(data) + , m_length(length) + , m_refCount(s_refCountIncrement) + , m_hash(0) + , m_isIdentifier(false) + , m_dataBuffer(0, ownership) + { + ASSERT((ownership == BufferInternal) || (ownership == BufferOwned)); + checkConsistency(); + } + + // Used to construct static strings, which have an special refCount that can never hit zero. + // This means that the static string will never be destroyed, which is important because + // static strings will be shared across threads & ref-counted in a non-threadsafe manner. + enum StaticStringConstructType { ConstructStaticString }; + UStringImpl(UChar* data, int length, StaticStringConstructType) + : m_data(data) + , m_length(length) + , m_refCount(s_staticRefCountInitialValue) + , m_hash(0) + , m_isIdentifier(false) + , m_dataBuffer(0, BufferOwned) + { + checkConsistency(); + } + + // Used to create new strings that are a substring of an existing string. + UStringImpl(UChar* data, int length, PassRefPtr<UStringImpl> base) + : m_data(data) + , m_length(length) + , m_refCount(s_refCountIncrement) + , m_hash(0) + , m_isIdentifier(false) + , m_dataBuffer(base.releaseRef(), BufferSubstring) + { + // Do use static strings as a base for substrings; UntypedPtrAndBitfield assumes + // that all pointers will be at least 8-byte aligned, we cannot guarantee that of + // UStringImpls that are not heap allocated. + ASSERT(m_dataBuffer.asPtr<UStringImpl*>()->size()); + ASSERT(!m_dataBuffer.asPtr<UStringImpl*>()->isStatic()); + checkConsistency(); + } + + // Used to construct new strings sharing an existing shared buffer. + UStringImpl(UChar* data, int length, PassRefPtr<SharedUChar> sharedBuffer) + : m_data(data) + , m_length(length) + , m_refCount(s_refCountIncrement) + , m_hash(0) + , m_isIdentifier(false) + , m_dataBuffer(sharedBuffer.releaseRef(), BufferShared) + { + checkConsistency(); + } + +#if OS(SOLARIS) && COMPILER(SUNCC) +public: // Otherwise the compiler complains about operator new not being accessible. +#endif +#if COMPILER(WINSCW) || COMPILER(XLC) + void* operator new(size_t size) { return Noncopyable::operator new(size); } +#else + using Noncopyable::operator new; +#endif +#if OS(SOLARIS) && COMPILER(SUNCC) +private: +#endif + void* operator new(size_t, void* p) { return p; } + + ~UStringImpl(); + + // This number must be at least 2 to avoid sharing empty, null as well as 1 character strings from SmallStrings. + static const int s_minLengthToShare = 10; + static const unsigned s_copyCharsInlineCutOff = 20; + static const uintptr_t s_bufferOwnershipMask = 3; + static const uintptr_t s_reportedCostBit = 4; + // We initialize and increment/decrement the refCount for all normal (non-static) strings by the value 2. + // We initialize static strings with an odd number (specifically, 1), such that the refCount cannot reach zero. + static const int s_refCountIncrement = 2; + static const int s_staticRefCountInitialValue = 1; + + UStringImpl* bufferOwnerString() { return (bufferOwnership() == BufferSubstring) ? m_dataBuffer.asPtr<UStringImpl*>() : this; } + const UStringImpl* bufferOwnerString() const { return (bufferOwnership() == BufferSubstring) ? m_dataBuffer.asPtr<UStringImpl*>() : this; } + SharedUChar* baseSharedBuffer(); + unsigned bufferOwnership() const { return m_dataBuffer & s_bufferOwnershipMask; } + bool isStatic() const { return m_refCount & 1; } + + // unshared data + UChar* m_data; + int m_length; + unsigned m_refCount; + mutable unsigned m_hash : 31; + mutable unsigned m_isIdentifier : 1; + UntypedPtrAndBitfield m_dataBuffer; + + JS_EXPORTDATA static UStringImpl* s_null; + JS_EXPORTDATA static UStringImpl* s_empty; + + friend class JIT; + friend class SmallStringsStorage; + friend void initializeUString(); +}; + +bool equal(const UStringImpl*, const UStringImpl*); + +} + +#endif diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/WeakGCMap.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/WeakGCMap.h new file mode 100644 index 0000000..39a91c5 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/WeakGCMap.h @@ -0,0 +1,122 @@ +/* + * 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. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS 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 WeakGCMap_h +#define WeakGCMap_h + +#include "Collector.h" +#include <wtf/HashMap.h> + +namespace JSC { + +class JSCell; + +// A HashMap whose get() function returns emptyValue() for cells awaiting destruction. +template<typename KeyType, typename MappedType> +class WeakGCMap : public FastAllocBase { + /* + Invariants: + * A value enters the WeakGCMap marked. (Guaranteed by set().) + * A value that becomes unmarked leaves the WeakGCMap before being recycled. (Guaranteed by the value's destructor removing it from the WeakGCMap.) + * A value that becomes unmarked leaves the WeakGCMap before becoming marked again. (Guaranteed by all destructors running before the mark phase begins.) + * During the mark phase, all values in the WeakGCMap are valid. (Guaranteed by all destructors running before the mark phase begins.) + */ + +public: + typedef typename HashMap<KeyType, MappedType>::iterator iterator; + typedef typename HashMap<KeyType, MappedType>::const_iterator const_iterator; + + bool isEmpty() { return m_map.isEmpty(); } + + MappedType get(const KeyType& key) const; + pair<iterator, bool> set(const KeyType&, const MappedType&); + MappedType take(const KeyType& key); + + // These unchecked functions provide access to a value even if the value's + // mark bit is not set. This is used, among other things, to retrieve values + // during the GC mark phase, which begins by clearing all mark bits. + + MappedType uncheckedGet(const KeyType& key) const { return m_map.get(key); } + bool uncheckedRemove(const KeyType&, const MappedType&); + + iterator uncheckedBegin() { return m_map.begin(); } + iterator uncheckedEnd() { return m_map.end(); } + + const_iterator uncheckedBegin() const { return m_map.begin(); } + const_iterator uncheckedEnd() const { return m_map.end(); } + +private: + HashMap<KeyType, MappedType> m_map; +}; + +template<typename KeyType, typename MappedType> +inline MappedType WeakGCMap<KeyType, MappedType>::get(const KeyType& key) const +{ + MappedType result = m_map.get(key); + if (result == HashTraits<MappedType>::emptyValue()) + return result; + if (!Heap::isCellMarked(result)) + return HashTraits<MappedType>::emptyValue(); + return result; +} + +template<typename KeyType, typename MappedType> +MappedType WeakGCMap<KeyType, MappedType>::take(const KeyType& key) +{ + MappedType result = m_map.take(key); + if (result == HashTraits<MappedType>::emptyValue()) + return result; + if (!Heap::isCellMarked(result)) + return HashTraits<MappedType>::emptyValue(); + return result; +} + +template<typename KeyType, typename MappedType> +pair<typename HashMap<KeyType, MappedType>::iterator, bool> WeakGCMap<KeyType, MappedType>::set(const KeyType& key, const MappedType& value) +{ + Heap::markCell(value); // If value is newly allocated, it's not marked, so mark it now. + pair<iterator, bool> result = m_map.add(key, value); + if (!result.second) { // pre-existing entry + result.second = !Heap::isCellMarked(result.first->second); + result.first->second = value; + } + return result; +} + +template<typename KeyType, typename MappedType> +bool WeakGCMap<KeyType, MappedType>::uncheckedRemove(const KeyType& key, const MappedType& value) +{ + iterator it = m_map.find(key); + if (it == m_map.end()) + return false; + if (it->second != value) + return false; + m_map.remove(it); + return true; +} + +} // namespace JSC + +#endif // WeakGCMap_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/WeakGCPtr.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/WeakGCPtr.h new file mode 100644 index 0000000..8653721 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/WeakGCPtr.h @@ -0,0 +1,128 @@ +/* + * 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. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS 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 WeakGCPtr_h +#define WeakGCPtr_h + +#include "Collector.h" +#include <wtf/Noncopyable.h> + +namespace JSC { + +// A smart pointer whose get() function returns 0 for cells awaiting destruction. +template <typename T> class WeakGCPtr : Noncopyable { +public: + WeakGCPtr() : m_ptr(0) { } + WeakGCPtr(T* ptr) { assign(ptr); } + + T* get() const + { + if (!m_ptr || !Heap::isCellMarked(m_ptr)) + return 0; + return m_ptr; + } + + void clear() { m_ptr = 0; } + + T& operator*() const { return *get(); } + T* operator->() const { return get(); } + + bool operator!() const { return !get(); } + + // This conversion operator allows implicit conversion to bool but not to other integer types. +#if COMPILER(WINSCW) + operator bool() const { return m_ptr; } +#else + typedef T* WeakGCPtr::*UnspecifiedBoolType; + operator UnspecifiedBoolType() const { return get() ? &WeakGCPtr::m_ptr : 0; } +#endif + + WeakGCPtr& operator=(T*); + +private: + void assign(T* ptr) + { + if (ptr) + Heap::markCell(ptr); + m_ptr = ptr; + } + + T* m_ptr; +}; + +template <typename T> inline WeakGCPtr<T>& WeakGCPtr<T>::operator=(T* optr) +{ + assign(optr); + return *this; +} + +template <typename T, typename U> inline bool operator==(const WeakGCPtr<T>& a, const WeakGCPtr<U>& b) +{ + return a.get() == b.get(); +} + +template <typename T, typename U> inline bool operator==(const WeakGCPtr<T>& a, U* b) +{ + return a.get() == b; +} + +template <typename T, typename U> inline bool operator==(T* a, const WeakGCPtr<U>& b) +{ + return a == b.get(); +} + +template <typename T, typename U> inline bool operator!=(const WeakGCPtr<T>& a, const WeakGCPtr<U>& b) +{ + return a.get() != b.get(); +} + +template <typename T, typename U> inline bool operator!=(const WeakGCPtr<T>& a, U* b) +{ + return a.get() != b; +} + +template <typename T, typename U> inline bool operator!=(T* a, const WeakGCPtr<U>& b) +{ + return a != b.get(); +} + +template <typename T, typename U> inline WeakGCPtr<T> static_pointer_cast(const WeakGCPtr<U>& p) +{ + return WeakGCPtr<T>(static_cast<T*>(p.get())); +} + +template <typename T, typename U> inline WeakGCPtr<T> const_pointer_cast(const WeakGCPtr<U>& p) +{ + return WeakGCPtr<T>(const_cast<T*>(p.get())); +} + +template <typename T> inline T* getPtr(const WeakGCPtr<T>& p) +{ + return p.get(); +} + +} // namespace JSC + +#endif // WeakGCPtr_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/WeakRandom.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/WeakRandom.h new file mode 100644 index 0000000..ff3995e --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/WeakRandom.h @@ -0,0 +1,86 @@ +/* + * 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. + * + * + * Copyright (c) 2009 Ian C. Bullard + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef WeakRandom_h +#define WeakRandom_h + +#include <limits.h> +#include <wtf/StdLibExtras.h> + +namespace JSC { + +class WeakRandom { +public: + WeakRandom(unsigned seed) + : m_low(seed ^ 0x49616E42) + , m_high(seed) + { + } + + double get() + { + return advance() / (UINT_MAX + 1.0); + } + +private: + unsigned advance() + { + m_high = (m_high << 16) + (m_high >> 16); + m_high += m_low; + m_low += m_high; + return m_high; + } + + unsigned m_low; + unsigned m_high; +}; + +} // namespace JSC + +#endif // WeakRandom_h |