diff options
Diffstat (limited to 'JavaScriptCore/runtime')
80 files changed, 1619 insertions, 1738 deletions
diff --git a/JavaScriptCore/runtime/ArrayPrototype.cpp b/JavaScriptCore/runtime/ArrayPrototype.cpp index b64abad..4c4eb48 100644 --- a/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -24,13 +24,13 @@ #include "config.h" #include "ArrayPrototype.h" -#include "CodeBlock.h" #include "CachedCall.h" +#include "CodeBlock.h" #include "Interpreter.h" #include "JIT.h" #include "JSStringBuilder.h" -#include "ObjectPrototype.h" #include "Lookup.h" +#include "ObjectPrototype.h" #include "Operations.h" #include <algorithm> #include <wtf/Assertions.h> @@ -156,9 +156,9 @@ JSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec, JSObject*, JSValue JSArray* thisObj = asArray(thisValue); HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements; - if (arrayVisitedElements.size() >= MaxSecondaryThreadReentryDepth) { - if (!isMainThread() || arrayVisitedElements.size() >= MaxMainThreadReentryDepth) - return throwError(exec, RangeError, "Maximum call stack size exceeded."); + if (arrayVisitedElements.size() >= MaxSmallThreadReentryDepth) { + if (arrayVisitedElements.size() >= exec->globalData().maxReentryDepth) + return throwError(exec, RangeError, "Maximum call stack size exceeded."); } bool alreadyVisited = !arrayVisitedElements.add(thisObj).second; @@ -201,7 +201,7 @@ JSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec, JSObject*, JSValue if (i) buffer.append(','); if (RefPtr<UString::Rep> rep = strBuffer[i]) - buffer.append(rep->data(), rep->size()); + buffer.append(rep->characters(), rep->length()); } ASSERT(buffer.size() == totalSize); return jsString(exec, UString::adopt(buffer)); @@ -214,9 +214,9 @@ JSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec, JSObject*, J JSObject* thisObj = asArray(thisValue); HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements; - if (arrayVisitedElements.size() >= MaxSecondaryThreadReentryDepth) { - if (!isMainThread() || arrayVisitedElements.size() >= MaxMainThreadReentryDepth) - return throwError(exec, RangeError, "Maximum call stack size exceeded."); + if (arrayVisitedElements.size() >= MaxSmallThreadReentryDepth) { + if (arrayVisitedElements.size() >= exec->globalData().maxReentryDepth) + return throwError(exec, RangeError, "Maximum call stack size exceeded."); } bool alreadyVisited = !arrayVisitedElements.add(thisObj).second; @@ -252,9 +252,9 @@ JSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec, JSObject*, JSValue thi JSObject* thisObj = thisValue.toThisObject(exec); HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements; - if (arrayVisitedElements.size() >= MaxSecondaryThreadReentryDepth) { - if (!isMainThread() || arrayVisitedElements.size() >= MaxMainThreadReentryDepth) - return throwError(exec, RangeError, "Maximum call stack size exceeded."); + if (arrayVisitedElements.size() >= MaxSmallThreadReentryDepth) { + if (arrayVisitedElements.size() >= exec->globalData().maxReentryDepth) + return throwError(exec, RangeError, "Maximum call stack size exceeded."); } bool alreadyVisited = !arrayVisitedElements.add(thisObj).second; @@ -268,7 +268,24 @@ JSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec, JSObject*, JSValue thi separator = args.at(0).toString(exec); unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - for (unsigned k = 0; k < length; k++) { + unsigned k = 0; + if (isJSArray(&exec->globalData(), thisObj)) { + JSArray* array = asArray(thisObj); + for (; k < length; k++) { + if (!array->canGetIndex(k)) + break; + if (k >= 1) { + if (separator.isNull()) + strBuffer.append(','); + else + strBuffer.append(separator); + } + JSValue element = array->getIndex(k); + if (!element.isUndefinedOrNull()) + strBuffer.append(element.toString(exec)); + } + } + for (; k < length; k++) { if (k >= 1) { if (separator.isNull()) strBuffer.append(','); @@ -506,14 +523,19 @@ JSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec, JSObject*, JSValue t // 15.4.4.12 JSArray* resObj = constructEmptyArray(exec); JSValue result = resObj; - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + + // FIXME: Firefox returns an empty array. if (!args.size()) return jsUndefined(); - int begin = args.at(0).toUInt32(exec); - if (begin < 0) - begin = std::max<int>(begin + length, 0); - else - begin = std::min<int>(begin, length); + + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + double relativeBegin = args.at(0).toInteger(exec); + unsigned begin; + if (relativeBegin < 0) { + relativeBegin += length; + begin = (relativeBegin < 0) ? 0 : static_cast<unsigned>(relativeBegin); + } else + begin = std::min<unsigned>(static_cast<unsigned>(relativeBegin), length); unsigned deleteCount; if (args.size() > 1) @@ -539,7 +561,7 @@ JSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec, JSObject*, JSValue t for (unsigned k = length; k > length - deleteCount + additionalArgs; --k) thisObj->deleteProperty(exec, k - 1); } else { - for (unsigned k = length - deleteCount; (int)k > begin; --k) { + for (unsigned k = length - deleteCount; k > begin; --k) { if (JSValue obj = getProperty(exec, thisObj, k + deleteCount - 1)) thisObj->put(exec, k + additionalArgs - 1, obj); else diff --git a/JavaScriptCore/runtime/CachedTranscendentalFunction.h b/JavaScriptCore/runtime/CachedTranscendentalFunction.h new file mode 100644 index 0000000..04f7f62 --- /dev/null +++ b/JavaScriptCore/runtime/CachedTranscendentalFunction.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2010 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 CachedTranscendentalFunction_h +#define CachedTranscendentalFunction_h + +#include "JSValue.h" + +namespace JSC { + +extern const double NaN; + +typedef double (*TranscendentalFunctionPtr)(double); + +// CachedTranscendentalFunction provides a generic mechanism to cache results +// for pure functions with the signature "double func(double)", and where NaN +// maps to NaN. +template<TranscendentalFunctionPtr orignalFunction> +class CachedTranscendentalFunction { + struct CacheEntry { + double operand; + double result; + }; + +public: + CachedTranscendentalFunction() + : m_cache(0) + { + } + + ~CachedTranscendentalFunction() + { + if (m_cache) + fastFree(m_cache); + } + + JSValue operator() (ExecState* exec, double operand) + { + if (UNLIKELY(!m_cache)) + initialize(); + CacheEntry* entry = &m_cache[hash(operand)]; + + if (entry->operand == operand) + return jsDoubleNumber(exec, entry->result); + double result = orignalFunction(operand); + entry->operand = operand; + entry->result = result; + return jsDoubleNumber(exec, result); + } + +private: + void initialize() + { + // Lazily allocate the table, populate with NaN->NaN mapping. + m_cache = static_cast<CacheEntry*>(fastMalloc(s_cacheSize * sizeof(CacheEntry))); + for (unsigned x = 0; x < s_cacheSize; ++x) { + m_cache[x].operand = NaN; + m_cache[x].result = NaN; + } + } + + static unsigned hash(double d) + { + union doubleAndUInt64 { + double d; + uint32_t is[2]; + } u; + u.d = d; + + unsigned x = u.is[0] ^ u.is[1]; + x = (x >> 20) ^ (x >> 8); + return x & (s_cacheSize - 1); + } + + static const unsigned s_cacheSize = 0x1000; + CacheEntry* m_cache; +}; + +} + +#endif // CachedTranscendentalFunction_h diff --git a/JavaScriptCore/runtime/Collector.cpp b/JavaScriptCore/runtime/Collector.cpp index 2873e0b..05f2bb5 100644 --- a/JavaScriptCore/runtime/Collector.cpp +++ b/JavaScriptCore/runtime/Collector.cpp @@ -53,11 +53,6 @@ #include <mach/thread_act.h> #include <mach/vm_map.h> -#elif OS(SYMBIAN) -#include <e32std.h> -#include <e32cmn.h> -#include <unistd.h> - #elif OS(WINDOWS) #include <windows.h> @@ -109,11 +104,6 @@ const size_t ALLOCATIONS_PER_COLLECTION = 3600; // a PIC branch in Mach-O binaries, see <rdar://problem/5971391>. #define MIN_ARRAY_SIZE (static_cast<size_t>(14)) -#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 OS(DARWIN) @@ -145,30 +135,12 @@ Heap::Heap(JSGlobalData* globalData) , m_registeredThreads(0) , m_currentThreadRegistrar(0) #endif +#if OS(SYMBIAN) + , m_blockallocator(JSCCOLLECTOR_VIRTUALMEM_RESERVATION, BLOCK_SIZE) +#endif , m_globalData(globalData) { ASSERT(globalData); - -#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. - // UserHeap::ChunkHeap allows allocation of continuous memory and specification - // of alignment value for (symbian) cells within that heap. - // - // Clarification and mapping of terminology: - // RHeap (created by UserHeap::ChunkHeap below) is continuos memory chunk, - // which can dynamically grow up to 8 MB, - // that holds all CollectorBlocks of this session (static). - // Each symbian cell within RHeap maps to a 64kb aligned CollectorBlock. - // JSCell objects are maintained as usual within CollectorBlocks. - if (!userChunk) { - userChunk = UserHeap::ChunkHeap(0, 0, MAX_NUM_BLOCKS * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); - if (!userChunk) - CRASH(); - } -#endif // OS(SYMBIAN) - memset(&m_heap, 0, sizeof(CollectorHeap)); allocateBlock(); } @@ -211,7 +183,9 @@ void Heap::destroy() t = next; } #endif - +#if OS(SYMBIAN) + m_blockallocator.destroy(); +#endif m_globalData = 0; } @@ -221,15 +195,13 @@ NEVER_INLINE CollectorBlock* Heap::allocateBlock() vm_address_t address = 0; 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 OS(SYMBIAN) - // Allocate a 64 kb aligned CollectorBlock - unsigned char* mask = reinterpret_cast<unsigned char*>(userChunk->Alloc(BLOCK_SIZE)); - if (!mask) + void* address = m_blockallocator.alloc(); + if (!address) CRASH(); - uintptr_t address = reinterpret_cast<uintptr_t>(mask); #elif OS(WINCE) void* address = VirtualAlloc(NULL, BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); #elif OS(WINDOWS) -#if COMPILER(MINGW) +#if COMPILER(MINGW) && !COMPILER(MINGW64) void* address = __mingw_aligned_malloc(BLOCK_SIZE, BLOCK_SIZE); #else void* address = _aligned_malloc(BLOCK_SIZE, BLOCK_SIZE); @@ -316,11 +288,11 @@ NEVER_INLINE void Heap::freeBlockPtr(CollectorBlock* block) #if OS(DARWIN) vm_deallocate(current_task(), reinterpret_cast<vm_address_t>(block), BLOCK_SIZE); #elif OS(SYMBIAN) - userChunk->Free(reinterpret_cast<TAny*>(block)); + m_blockallocator.free(reinterpret_cast<void*>(block)); #elif OS(WINCE) VirtualFree(block, 0, MEM_RELEASE); #elif OS(WINDOWS) -#if COMPILER(MINGW) +#if COMPILER(MINGW) && !COMPILER(MINGW64) __mingw_aligned_free(block); #else _aligned_free(block); @@ -477,7 +449,7 @@ void Heap::shrinkBlocks(size_t neededBlocks) } #if OS(WINCE) -void* g_stackBase = 0; +JS_EXPORTDATA void* g_stackBase = 0; inline bool isPageWritable(void* page) { @@ -574,10 +546,6 @@ static inline void* currentThreadStackBase() MOV pTib, EAX } return static_cast<void*>(pTib->StackBase); -#elif OS(WINDOWS) && CPU(X86_64) && COMPILER(MSVC) - // FIXME: why only for MSVC? - PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb()); - return reinterpret_cast<void*>(pTib->StackBase); #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 @@ -586,7 +554,12 @@ static inline void* currentThreadStackBase() : "=r" (pTib) ); return static_cast<void*>(pTib->StackBase); +#elif OS(WINDOWS) && CPU(X86_64) + PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb()); + return reinterpret_cast<void*>(pTib->StackBase); #elif OS(QNX) + AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); + MutexLocker locker(mutex); return currentThreadStackBaseQNX(); #elif OS(SOLARIS) stack_t s; @@ -598,19 +571,17 @@ static inline void* currentThreadStackBase() pthread_stackseg_np(thread, &stack); return stack.ss_sp; #elif OS(SYMBIAN) - static void* stackBase = 0; - if (stackBase == 0) { - TThreadStackInfo info; - RThread thread; - thread.StackInfo(info); - stackBase = (void*)info.iBase; - } - return (void*)stackBase; + TThreadStackInfo info; + RThread thread; + thread.StackInfo(info); + return (void*)info.iBase; #elif OS(HAIKU) thread_info threadInfo; get_thread_info(find_thread(NULL), &threadInfo); return threadInfo.stack_end; #elif OS(UNIX) + AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); + MutexLocker locker(mutex); static void* stackBase = 0; static size_t stackSize = 0; static pthread_t stackThread; @@ -633,6 +604,8 @@ static inline void* currentThreadStackBase() } return static_cast<char*>(stackBase) + stackSize; #elif OS(WINCE) + AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); + MutexLocker locker(mutex); if (g_stackBase) return g_stackBase; else { @@ -667,7 +640,7 @@ void Heap::makeUsableFromMultipleThreads() void Heap::registerThread() { - ASSERT(!m_globalData->mainThreadOnly || isMainThread()); + ASSERT(!m_globalData->exclusiveThread || m_globalData->exclusiveThread == currentThread()); if (!m_currentThreadRegistrar || pthread_getspecific(m_currentThreadRegistrar)) return; @@ -1001,7 +974,7 @@ void Heap::markStackObjectsConservatively(MarkStack& markStack) void Heap::protect(JSValue k) { ASSERT(k); - ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance); + ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance()); if (!k.isCell()) return; @@ -1009,15 +982,15 @@ void Heap::protect(JSValue k) m_protectedValues.add(k.asCell()); } -void Heap::unprotect(JSValue k) +bool Heap::unprotect(JSValue k) { ASSERT(k); - ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance); + ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance()); if (!k.isCell()) - return; + return false; - m_protectedValues.remove(k.asCell()); + return m_protectedValues.remove(k.asCell()); } void Heap::markProtectedObjects(MarkStack& markStack) @@ -1093,7 +1066,7 @@ void Heap::sweep() void Heap::markRoots() { #ifndef NDEBUG - if (m_globalData->isSharedInstance) { + if (m_globalData->isSharedInstance()) { ASSERT(JSLock::lockCount() > 0); ASSERT(JSLock::currentThreadIsHoldingLock()); } diff --git a/JavaScriptCore/runtime/Collector.h b/JavaScriptCore/runtime/Collector.h index 82aa8a1..3db3d7e 100644 --- a/JavaScriptCore/runtime/Collector.h +++ b/JavaScriptCore/runtime/Collector.h @@ -35,6 +35,10 @@ #include <pthread.h> #endif +#if OS(SYMBIAN) +#include <wtf/symbian/BlockAllocatorSymbian.h> +#endif + #define ASSERT_CLASS_FITS_IN_CELL(class) COMPILE_ASSERT(sizeof(class) <= CELL_SIZE, class_fits_in_cell) namespace JSC { @@ -91,7 +95,9 @@ namespace JSC { Statistics statistics() const; void protect(JSValue); - void unprotect(JSValue); + // Returns true if the value is no longer protected by any protect pointers + // (though it may still be alive due to heap/stack references). + bool unprotect(JSValue); static Heap* heap(JSValue); // 0 for immediate values static Heap* heap(JSCell*); @@ -168,6 +174,11 @@ namespace JSC { pthread_key_t m_currentThreadRegistrar; #endif +#if OS(SYMBIAN) + // Allocates collector blocks with correct alignment + WTF::AlignedBlockAllocator m_blockallocator; +#endif + JSGlobalData* m_globalData; }; diff --git a/JavaScriptCore/runtime/CommonIdentifiers.cpp b/JavaScriptCore/runtime/CommonIdentifiers.cpp index ed5e304..3837817 100644 --- a/JavaScriptCore/runtime/CommonIdentifiers.cpp +++ b/JavaScriptCore/runtime/CommonIdentifiers.cpp @@ -28,7 +28,8 @@ static const char* const nullCString = 0; #define INITIALIZE_PROPERTY_NAME(name) , name(globalData, #name) CommonIdentifiers::CommonIdentifiers(JSGlobalData* globalData) - : emptyIdentifier(globalData, "") + : nullIdentifier(globalData, nullCString) + , emptyIdentifier(globalData, "") , underscoreProto(globalData, "__proto__") , thisIdentifier(globalData, "this") JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PROPERTY_NAME) diff --git a/JavaScriptCore/runtime/CommonIdentifiers.h b/JavaScriptCore/runtime/CommonIdentifiers.h index 0a3d774..de24f4a 100644 --- a/JavaScriptCore/runtime/CommonIdentifiers.h +++ b/JavaScriptCore/runtime/CommonIdentifiers.h @@ -90,6 +90,7 @@ namespace JSC { friend class JSGlobalData; public: + const Identifier nullIdentifier; const Identifier emptyIdentifier; const Identifier underscoreProto; const Identifier thisIdentifier; diff --git a/JavaScriptCore/runtime/Completion.cpp b/JavaScriptCore/runtime/Completion.cpp index 2f88df9..9af5171 100644 --- a/JavaScriptCore/runtime/Completion.cpp +++ b/JavaScriptCore/runtime/Completion.cpp @@ -29,6 +29,7 @@ #include "Interpreter.h" #include "Parser.h" #include "Debugger.h" +#include "WTFThreadData.h" #include <stdio.h> namespace JSC { @@ -36,7 +37,7 @@ namespace JSC { Completion checkSyntax(ExecState* exec, const SourceCode& source) { JSLock lock(exec); - ASSERT(exec->globalData().identifierTable == currentIdentifierTable()); + ASSERT(exec->globalData().identifierTable == wtfThreadData().currentIdentifierTable()); RefPtr<ProgramExecutable> program = ProgramExecutable::create(exec, source); JSObject* error = program->checkSyntax(exec); @@ -49,7 +50,7 @@ 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()); + ASSERT(exec->globalData().identifierTable == wtfThreadData().currentIdentifierTable()); RefPtr<ProgramExecutable> program = ProgramExecutable::create(exec, source); JSObject* error = program->compile(exec, scopeChain.node()); @@ -62,9 +63,10 @@ Completion evaluate(ExecState* exec, ScopeChain& scopeChain, const SourceCode& s 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); + ComplType exceptionType = Throw; + if (exception.isObject()) + exceptionType = asObject(exception)->exceptionType(); + return Completion(exceptionType, exception); } return Completion(Normal, result); } diff --git a/JavaScriptCore/runtime/Completion.h b/JavaScriptCore/runtime/Completion.h index 41c9a64..63b315e 100644 --- a/JavaScriptCore/runtime/Completion.h +++ b/JavaScriptCore/runtime/Completion.h @@ -31,7 +31,7 @@ namespace JSC { class ScopeChain; class SourceCode; - enum ComplType { Normal, Break, Continue, ReturnValue, Throw, Interrupted }; + enum ComplType { Normal, Break, Continue, ReturnValue, Throw, Interrupted, Terminated }; /* * Completion objects are used to convey the return status and value diff --git a/JavaScriptCore/runtime/DateConversion.cpp b/JavaScriptCore/runtime/DateConversion.cpp index f129407..70dbaa0 100644 --- a/JavaScriptCore/runtime/DateConversion.cpp +++ b/JavaScriptCore/runtime/DateConversion.cpp @@ -56,7 +56,7 @@ double parseDate(ExecState* exec, const UString &date) { if (date == exec->globalData().cachedDateString) return exec->globalData().cachedDateStringValue; - double value = parseDateFromNullTerminatedCharacters(exec, date.UTF8String().c_str()); + double value = parseDateFromNullTerminatedCharacters(exec, date.UTF8String().data()); exec->globalData().cachedDateString = date; exec->globalData().cachedDateStringValue = value; return value; diff --git a/JavaScriptCore/runtime/DatePrototype.cpp b/JavaScriptCore/runtime/DatePrototype.cpp index 25b0ac4..d331409 100644 --- a/JavaScriptCore/runtime/DatePrototype.cpp +++ b/JavaScriptCore/runtime/DatePrototype.cpp @@ -24,11 +24,12 @@ #include "DatePrototype.h" #include "DateConversion.h" +#include "DateInstance.h" #include "Error.h" #include "JSString.h" #include "JSStringBuilder.h" +#include "Lookup.h" #include "ObjectPrototype.h" -#include "DateInstance.h" #if !PLATFORM(MAC) && HAVE(LANGINFO_H) #include <langinfo.h> diff --git a/JavaScriptCore/runtime/ExceptionHelpers.cpp b/JavaScriptCore/runtime/ExceptionHelpers.cpp index b9c6319..aee6f31 100644 --- a/JavaScriptCore/runtime/ExceptionHelpers.cpp +++ b/JavaScriptCore/runtime/ExceptionHelpers.cpp @@ -46,7 +46,7 @@ public: { } - virtual bool isWatchdogException() const { return true; } + virtual ComplType exceptionType() const { return Interrupted; } virtual UString toString(ExecState*) const { return "JavaScript execution exceeded timeout."; } }; @@ -56,6 +56,23 @@ JSValue createInterruptedExecutionException(JSGlobalData* globalData) return new (globalData) InterruptedExecutionError(globalData); } +class TerminatedExecutionError : public JSObject { +public: + TerminatedExecutionError(JSGlobalData* globalData) + : JSObject(globalData->terminatedExecutionErrorStructure) + { + } + + virtual ComplType exceptionType() const { return Terminated; } + + virtual UString toString(ExecState*) const { return "JavaScript execution terminated."; } +}; + +JSValue createTerminatedExecutionException(JSGlobalData* globalData) +{ + return new (globalData) TerminatedExecutionError(globalData); +} + static JSValue createError(ExecState* exec, ErrorType e, const char* msg) { return Error::create(exec, e, msg, -1, -1, UString()); diff --git a/JavaScriptCore/runtime/ExceptionHelpers.h b/JavaScriptCore/runtime/ExceptionHelpers.h index b6e7373..b152439 100644 --- a/JavaScriptCore/runtime/ExceptionHelpers.h +++ b/JavaScriptCore/runtime/ExceptionHelpers.h @@ -43,6 +43,7 @@ namespace JSC { struct Instruction; JSValue createInterruptedExecutionException(JSGlobalData*); + JSValue createTerminatedExecutionException(JSGlobalData*); JSValue createStackOverflowError(ExecState*); JSValue createTypeError(ExecState*, const char* message); JSValue createUndefinedVariableError(ExecState*, const Identifier&, unsigned bytecodeOffset, CodeBlock*); diff --git a/JavaScriptCore/runtime/Executable.h b/JavaScriptCore/runtime/Executable.h index f74abe9..ac691e4 100644 --- a/JavaScriptCore/runtime/Executable.h +++ b/JavaScriptCore/runtime/Executable.h @@ -85,7 +85,12 @@ namespace JSC { NativeExecutable(ExecState* exec) : ExecutableBase(NUM_PARAMETERS_IS_HOST) { - m_jitCode = JITCode(JITCode::HostFunction(exec->globalData().jitStubs.ctiNativeCallThunk())); + m_jitCode = exec->globalData().jitStubs.ctiNativeCallThunk()->m_jitCode; + } + NativeExecutable(JITCode thunk) + : ExecutableBase(NUM_PARAMETERS_IS_HOST) + { + m_jitCode = thunk; } ~NativeExecutable(); diff --git a/JavaScriptCore/runtime/FunctionPrototype.cpp b/JavaScriptCore/runtime/FunctionPrototype.cpp index 3475f08..a77b5b2 100644 --- a/JavaScriptCore/runtime/FunctionPrototype.cpp +++ b/JavaScriptCore/runtime/FunctionPrototype.cpp @@ -39,7 +39,7 @@ static JSValue JSC_HOST_CALL functionProtoFuncApply(ExecState*, JSObject*, JSVal static JSValue JSC_HOST_CALL functionProtoFuncCall(ExecState*, JSObject*, JSValue, const ArgList&); FunctionPrototype::FunctionPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure) - : InternalFunction(&exec->globalData(), structure, exec->propertyNames().emptyIdentifier) + : InternalFunction(&exec->globalData(), structure, exec->propertyNames().nullIdentifier) { putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 0), DontDelete | ReadOnly | DontEnum); } diff --git a/JavaScriptCore/runtime/GetterSetter.h b/JavaScriptCore/runtime/GetterSetter.h index 4e47361..27ffbe7 100644 --- a/JavaScriptCore/runtime/GetterSetter.h +++ b/JavaScriptCore/runtime/GetterSetter.h @@ -34,6 +34,7 @@ namespace JSC { // This is an internal value object which stores getter and setter functions // for a property. class GetterSetter : public JSCell { + friend class JIT; public: GetterSetter(ExecState* exec) : JSCell(exec->globalData().getterSetterStructure.get()) diff --git a/JavaScriptCore/runtime/Identifier.cpp b/JavaScriptCore/runtime/Identifier.cpp index 97929e2..f2642a9 100644 --- a/JavaScriptCore/runtime/Identifier.cpp +++ b/JavaScriptCore/runtime/Identifier.cpp @@ -22,50 +22,38 @@ #include "Identifier.h" #include "CallFrame.h" +#include "NumericStrings.h" #include <new> // for placement new #include <string.h> // for strlen #include <wtf/Assertions.h> #include <wtf/FastMalloc.h> #include <wtf/HashSet.h> +#include <wtf/WTFThreadData.h> +#include <wtf/text/StringHash.h> using WTF::ThreadSpecific; namespace JSC { -typedef HashMap<const char*, RefPtr<UString::Rep>, PtrHash<const char*> > LiteralIdentifierTable; - -class IdentifierTable : public FastAllocBase { -public: - ~IdentifierTable() - { - HashSet<UString::Rep*>::iterator end = m_table.end(); - for (HashSet<UString::Rep*>::iterator iter = m_table.begin(); iter != end; ++iter) - (*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)->setIsIdentifier(true); - return result; - } - - template<typename U, typename V> - 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)->setIsIdentifier(true); - return result; - } - - void remove(UString::Rep* r) { m_table.remove(r); } - - LiteralIdentifierTable& literalTable() { return m_literalTable; } - -private: - HashSet<UString::Rep*> m_table; - LiteralIdentifierTable m_literalTable; -}; +IdentifierTable::~IdentifierTable() +{ + HashSet<StringImpl*>::iterator end = m_table.end(); + for (HashSet<StringImpl*>::iterator iter = m_table.begin(); iter != end; ++iter) + (*iter)->setIsIdentifier(false); +} +std::pair<HashSet<StringImpl*>::iterator, bool> IdentifierTable::add(StringImpl* value) +{ + std::pair<HashSet<StringImpl*>::iterator, bool> result = m_table.add(value); + (*result.first)->setIsIdentifier(true); + return result; +} +template<typename U, typename V> +std::pair<HashSet<StringImpl*>::iterator, bool> IdentifierTable::add(U value) +{ + std::pair<HashSet<StringImpl*>::iterator, bool> result = m_table.add<U, V>(value); + (*result.first)->setIsIdentifier(true); + return result; +} IdentifierTable* createIdentifierTable() { @@ -79,26 +67,26 @@ void deleteIdentifierTable(IdentifierTable* table) bool Identifier::equal(const UString::Rep* r, const char* s) { - int length = r->size(); - const UChar* d = r->data(); + int length = r->length(); + const UChar* d = r->characters(); for (int i = 0; i != length; ++i) if (d[i] != (unsigned char)s[i]) return false; return s[length] == 0; } -bool Identifier::equal(const UString::Rep* r, const UChar* s, int length) +bool Identifier::equal(const UString::Rep* r, const UChar* s, unsigned length) { - if (r->size() != length) + if (r->length() != length) return false; - const UChar* d = r->data(); - for (int i = 0; i != length; ++i) + const UChar* d = r->characters(); + for (unsigned i = 0; i != length; ++i) if (d[i] != s[i]) return false; return true; } -struct CStringTranslator { +struct IdentifierCStringTranslator { static unsigned hash(const char* c) { return UString::Rep::computeHash(c); @@ -123,12 +111,10 @@ struct CStringTranslator { PassRefPtr<UString::Rep> Identifier::add(JSGlobalData* globalData, const char* c) { - ASSERT(c); - - if (!c[0]) { - UString::Rep::empty().hash(); - return &UString::Rep::empty(); - } + if (!c) + return UString::null().rep(); + if (!c[0]) + return UString::Rep::empty(); if (!c[1]) return add(globalData, globalData->smallStrings.singleCharacterStringRep(static_cast<unsigned char>(c[0]))); @@ -139,7 +125,7 @@ PassRefPtr<UString::Rep> Identifier::add(JSGlobalData* globalData, const char* c if (iter != literalIdentifierTable.end()) return iter->second; - pair<HashSet<UString::Rep*>::iterator, bool> addResult = identifierTable.add<const char*, CStringTranslator>(c); + pair<HashSet<UString::Rep*>::iterator, bool> addResult = identifierTable.add<const char*, IdentifierCStringTranslator>(c); // If the string is newly-translated, then we need to adopt it. // The boolean in the pair tells us if that is so. @@ -160,7 +146,7 @@ struct UCharBuffer { unsigned int length; }; -struct UCharBufferTranslator { +struct IdentifierUCharBufferTranslator { static unsigned hash(const UCharBuffer& buf) { return UString::Rep::computeHash(buf.s, buf.length); @@ -189,12 +175,10 @@ PassRefPtr<UString::Rep> Identifier::add(JSGlobalData* globalData, const UChar* if (c <= 0xFF) return add(globalData, globalData->smallStrings.singleCharacterStringRep(c)); } - if (!length) { - UString::Rep::empty().hash(); - return &UString::Rep::empty(); - } + if (!length) + return UString::Rep::empty(); UCharBuffer buf = {s, length}; - pair<HashSet<UString::Rep*>::iterator, bool> addResult = globalData->identifierTable->add<UCharBuffer, UCharBufferTranslator>(buf); + pair<HashSet<UString::Rep*>::iterator, bool> addResult = globalData->identifierTable->add<UCharBuffer, IdentifierUCharBufferTranslator>(buf); // If the string is newly-translated, then we need to adopt it. // The boolean in the pair tells us if that is so. @@ -209,21 +193,18 @@ PassRefPtr<UString::Rep> Identifier::add(ExecState* exec, const UChar* s, int le PassRefPtr<UString::Rep> Identifier::addSlowCase(JSGlobalData* globalData, UString::Rep* r) { ASSERT(!r->isIdentifier()); - if (r->size() == 1) { - UChar c = r->data()[0]; + // The empty & null strings are static singletons, and static strings are handled + // in ::add() in the header, so we should never get here with a zero length string. + ASSERT(r->length()); + + if (r->length() == 1) { + UChar c = r->characters()[0]; if (c <= 0xFF) r = globalData->smallStrings.singleCharacterStringRep(c); - if (r->isIdentifier()) { -#ifndef NDEBUG - checkSameIdentifierTable(globalData, r); -#endif + if (r->isIdentifier()) return r; - } - } - if (!r->size()) { - UString::Rep::empty().hash(); - return &UString::Rep::empty(); } + return *globalData->identifierTable->add(r).first; } @@ -232,58 +213,41 @@ PassRefPtr<UString::Rep> Identifier::addSlowCase(ExecState* exec, UString::Rep* return addSlowCase(&exec->globalData(), r); } -void Identifier::remove(UString::Rep* r) +Identifier Identifier::from(ExecState* exec, unsigned value) { - currentIdentifierTable()->remove(r); + return Identifier(exec, exec->globalData().numericStrings.add(value)); } -#ifndef NDEBUG - -void Identifier::checkSameIdentifierTable(ExecState* exec, UString::Rep*) +Identifier Identifier::from(ExecState* exec, int value) { - ASSERT_UNUSED(exec, exec->globalData().identifierTable == currentIdentifierTable()); + return Identifier(exec, exec->globalData().numericStrings.add(value)); } -void Identifier::checkSameIdentifierTable(JSGlobalData* globalData, UString::Rep*) +Identifier Identifier::from(ExecState* exec, double value) { - ASSERT_UNUSED(globalData, globalData->identifierTable == currentIdentifierTable()); + return Identifier(exec, exec->globalData().numericStrings.add(value)); } -#else - -void Identifier::checkSameIdentifierTable(ExecState*, UString::Rep*) -{ -} +#ifndef NDEBUG -void Identifier::checkSameIdentifierTable(JSGlobalData*, UString::Rep*) +void Identifier::checkCurrentIdentifierTable(JSGlobalData* globalData) { + // Check the identifier table accessible through the threadspecific matches the + // globalData's identifier table. + ASSERT_UNUSED(globalData, globalData->identifierTable == wtfThreadData().currentIdentifierTable()); } -#endif - -ThreadSpecific<ThreadIdentifierTableData>* g_identifierTableSpecific = 0; - -#if ENABLE(JSC_MULTIPLE_THREADS) - -pthread_once_t createIdentifierTableSpecificOnce = PTHREAD_ONCE_INIT; -static void createIdentifierTableSpecificCallback() +void Identifier::checkCurrentIdentifierTable(ExecState* exec) { - ASSERT(!g_identifierTableSpecific); - g_identifierTableSpecific = new ThreadSpecific<ThreadIdentifierTableData>(); -} -void createIdentifierTableSpecific() -{ - pthread_once(&createIdentifierTableSpecificOnce, createIdentifierTableSpecificCallback); - ASSERT(g_identifierTableSpecific); + checkCurrentIdentifierTable(&exec->globalData()); } -#else +#else -void createIdentifierTableSpecific() -{ - ASSERT(!g_identifierTableSpecific); - g_identifierTableSpecific = new ThreadSpecific<ThreadIdentifierTableData>(); -} +// These only exists so that our exports are the same for debug and release builds. +// This would be an ASSERT_NOT_REACHED(), but we're in NDEBUG only code here! +void Identifier::checkCurrentIdentifierTable(JSGlobalData*) { CRASH(); } +void Identifier::checkCurrentIdentifierTable(ExecState*) { CRASH(); } #endif diff --git a/JavaScriptCore/runtime/Identifier.h b/JavaScriptCore/runtime/Identifier.h index 1d1bd18..2f16bbf 100644 --- a/JavaScriptCore/runtime/Identifier.h +++ b/JavaScriptCore/runtime/Identifier.h @@ -54,9 +54,9 @@ namespace JSC { const char* ascii() const { return _ustring.ascii(); } - static Identifier from(ExecState* exec, unsigned y) { return Identifier(exec, UString::from(y)); } - static Identifier from(ExecState* exec, int y) { return Identifier(exec, UString::from(y)); } - static Identifier from(ExecState* exec, double y) { return Identifier(exec, UString::from(y)); } + static Identifier from(ExecState* exec, unsigned y); + static Identifier from(ExecState* exec, int y); + static Identifier from(ExecState* exec, double y); bool isNull() const { return _ustring.isNull(); } bool isEmpty() const { return _ustring.isEmpty(); } @@ -73,11 +73,9 @@ namespace JSC { friend bool operator==(const Identifier&, const char*); friend bool operator!=(const Identifier&, const char*); - static void remove(UString::Rep*); - static bool equal(const UString::Rep*, const char*); - static bool equal(const UString::Rep*, const UChar*, int length); - static bool equal(const UString::Rep* a, const UString::Rep* b) { return JSC::equal(a, b); } + static bool equal(const UString::Rep*, const UChar*, unsigned length); + static bool equal(const UString::Rep* a, const UString::Rep* b) { return ::equal(a, b); } static PassRefPtr<UString::Rep> add(ExecState*, const char*); // Only to be used with string literals. static PassRefPtr<UString::Rep> add(JSGlobalData*, const char*); // Only to be used with string literals. @@ -93,30 +91,28 @@ namespace JSC { static PassRefPtr<UString::Rep> add(ExecState* exec, UString::Rep* r) { - if (r->isIdentifier()) { #ifndef NDEBUG - checkSameIdentifierTable(exec, r); + checkCurrentIdentifierTable(exec); #endif + if (r->isIdentifier()) return r; - } return addSlowCase(exec, r); } static PassRefPtr<UString::Rep> add(JSGlobalData* globalData, UString::Rep* r) { - if (r->isIdentifier()) { #ifndef NDEBUG - checkSameIdentifierTable(globalData, r); + checkCurrentIdentifierTable(globalData); #endif + if (r->isIdentifier()) return r; - } return addSlowCase(globalData, r); } static PassRefPtr<UString::Rep> addSlowCase(ExecState*, UString::Rep* r); static PassRefPtr<UString::Rep> addSlowCase(JSGlobalData*, UString::Rep* r); - static void checkSameIdentifierTable(ExecState*, UString::Rep*); - static void checkSameIdentifierTable(JSGlobalData*, UString::Rep*); + static void checkCurrentIdentifierTable(ExecState*); + static void checkCurrentIdentifierTable(JSGlobalData*); }; inline bool operator==(const Identifier& a, const Identifier& b) @@ -142,67 +138,6 @@ 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/JavaScriptCore/runtime/InitializeThreading.cpp b/JavaScriptCore/runtime/InitializeThreading.cpp index 2605a9a..51d43ee 100644 --- a/JavaScriptCore/runtime/InitializeThreading.cpp +++ b/JavaScriptCore/runtime/InitializeThreading.cpp @@ -36,6 +36,7 @@ #include "UString.h" #include <wtf/DateMath.h> #include <wtf/Threading.h> +#include <wtf/WTFThreadData.h> using namespace WTF; @@ -48,6 +49,7 @@ static pthread_once_t initializeThreadingKeyOnce = PTHREAD_ONCE_INIT; static void initializeThreadingOnce() { WTF::initializeThreading(); + wtfThreadData(); initializeUString(); JSGlobalData::storeVPtrs(); #if ENABLE(JSC_MULTIPLE_THREADS) diff --git a/JavaScriptCore/runtime/InternalFunction.cpp b/JavaScriptCore/runtime/InternalFunction.cpp index c48d628..717b5ff 100644 --- a/JavaScriptCore/runtime/InternalFunction.cpp +++ b/JavaScriptCore/runtime/InternalFunction.cpp @@ -40,7 +40,7 @@ const ClassInfo* InternalFunction::classInfo() const InternalFunction::InternalFunction(JSGlobalData* globalData, NonNullPassRefPtr<Structure> structure, const Identifier& name) : JSObject(structure) { - putDirect(globalData->propertyNames->name, jsString(globalData, name.ustring()), DontDelete | ReadOnly | DontEnum); + putDirect(globalData->propertyNames->name, jsString(globalData, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum); } const UString& InternalFunction::name(ExecState* exec) diff --git a/JavaScriptCore/runtime/JSAPIValueWrapper.h b/JavaScriptCore/runtime/JSAPIValueWrapper.h index b5016c2..10ded4c 100644 --- a/JavaScriptCore/runtime/JSAPIValueWrapper.h +++ b/JavaScriptCore/runtime/JSAPIValueWrapper.h @@ -23,8 +23,6 @@ #ifndef JSAPIValueWrapper_h #define JSAPIValueWrapper_h -#include <wtf/Platform.h> - #include "JSCell.h" #include "CallFrame.h" diff --git a/JavaScriptCore/runtime/JSActivation.cpp b/JavaScriptCore/runtime/JSActivation.cpp index 22fdaaf..85e8bba 100644 --- a/JavaScriptCore/runtime/JSActivation.cpp +++ b/JavaScriptCore/runtime/JSActivation.cpp @@ -139,9 +139,9 @@ bool JSActivation::isDynamicScope() const return d()->functionExecutable->usesEval(); } -JSValue JSActivation::argumentsGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue JSActivation::argumentsGetter(ExecState* exec, JSValue slotBase, const Identifier&) { - JSActivation* activation = asActivation(slot.slotBase()); + JSActivation* activation = asActivation(slotBase); if (activation->d()->functionExecutable->usesArguments()) { PropertySlot slot; diff --git a/JavaScriptCore/runtime/JSActivation.h b/JavaScriptCore/runtime/JSActivation.h index 761bee4..ece8753 100644 --- a/JavaScriptCore/runtime/JSActivation.h +++ b/JavaScriptCore/runtime/JSActivation.h @@ -31,7 +31,6 @@ #include "CodeBlock.h" #include "JSVariableObject.h" -#include "RegisterFile.h" #include "SymbolTable.h" #include "Nodes.h" @@ -89,7 +88,7 @@ namespace JSC { RefPtr<FunctionExecutable> functionExecutable; }; - static JSValue argumentsGetter(ExecState*, const Identifier&, const PropertySlot&); + static JSValue argumentsGetter(ExecState*, JSValue, const Identifier&); NEVER_INLINE PropertySlot::GetValueFunc getArgumentsGetter(); JSActivationData* d() const { return static_cast<JSActivationData*>(JSVariableObject::d); } diff --git a/JavaScriptCore/runtime/JSArray.cpp b/JavaScriptCore/runtime/JSArray.cpp index 2be7371..d3ef44c 100644 --- a/JavaScriptCore/runtime/JSArray.cpp +++ b/JavaScriptCore/runtime/JSArray.cpp @@ -151,7 +151,7 @@ JSArray::JSArray(NonNullPassRefPtr<Structure> structure, unsigned initialLength) m_vectorLength = initialCapacity; m_storage->m_numValuesInVector = 0; m_storage->m_sparseValueMap = 0; - m_storage->lazyCreationData = 0; + m_storage->subclassData = 0; m_storage->reportedMapCapacity = 0; JSValue* vector = m_storage->m_vector; @@ -173,7 +173,7 @@ JSArray::JSArray(NonNullPassRefPtr<Structure> structure, const ArgList& list) m_vectorLength = initialCapacity; m_storage->m_numValuesInVector = initialCapacity; m_storage->m_sparseValueMap = 0; - m_storage->lazyCreationData = 0; + m_storage->subclassData = 0; m_storage->reportedMapCapacity = 0; size_t i = 0; @@ -1022,14 +1022,14 @@ unsigned JSArray::compactForSorting() return numDefined; } -void* JSArray::lazyCreationData() +void* JSArray::subclassData() const { - return m_storage->lazyCreationData; + return m_storage->subclassData; } -void JSArray::setLazyCreationData(void* d) +void JSArray::setSubclassData(void* d) { - m_storage->lazyCreationData = d; + m_storage->subclassData = d; } #if CHECK_ARRAY_CONSISTENCY diff --git a/JavaScriptCore/runtime/JSArray.h b/JavaScriptCore/runtime/JSArray.h index ad6ee88..f65f2bc 100644 --- a/JavaScriptCore/runtime/JSArray.h +++ b/JavaScriptCore/runtime/JSArray.h @@ -31,7 +31,7 @@ namespace JSC { unsigned m_length; unsigned m_numValuesInVector; SparseArrayValueMap* m_sparseValueMap; - void* lazyCreationData; // A JSArray subclass can use this to fill the vector lazily. + void* subclassData; // A JSArray subclass can use this to fill the vector lazily. size_t reportedMapCapacity; JSValue m_vector[1]; }; @@ -101,8 +101,8 @@ namespace JSC { virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); virtual void markChildren(MarkStack&); - void* lazyCreationData(); - void setLazyCreationData(void*); + void* subclassData() const; + void setSubclassData(void*); private: virtual const ClassInfo* classInfo() const { return &info; } diff --git a/JavaScriptCore/runtime/JSCell.cpp b/JavaScriptCore/runtime/JSCell.cpp index 869fbfc..0cc1ab1 100644 --- a/JavaScriptCore/runtime/JSCell.cpp +++ b/JavaScriptCore/runtime/JSCell.cpp @@ -163,16 +163,6 @@ JSObject* JSCell::toThisObject(ExecState* exec) const return toObject(exec); } -UString JSCell::toThisString(ExecState* exec) const -{ - return toThisObject(exec)->toString(exec); -} - -JSString* JSCell::toThisJSString(ExecState* exec) -{ - return jsString(exec, toThisString(exec)); -} - const ClassInfo* JSCell::classInfo() const { return 0; diff --git a/JavaScriptCore/runtime/JSCell.h b/JavaScriptCore/runtime/JSCell.h index 3c8c829..772708f 100644 --- a/JavaScriptCore/runtime/JSCell.h +++ b/JavaScriptCore/runtime/JSCell.h @@ -107,8 +107,6 @@ namespace JSC { 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; } @@ -301,11 +299,6 @@ namespace JSC { return asCell()->structure()->typeInfo().needsThisConversion(); } - inline UString JSValue::toThisString(ExecState* exec) const - { - return isCell() ? asCell()->toThisString(exec) : toString(exec); - } - inline JSValue JSValue::getJSNumber() { if (isInt32() || isDouble()) diff --git a/JavaScriptCore/runtime/JSFunction.cpp b/JavaScriptCore/runtime/JSFunction.cpp index d213b4a..5b73642 100644 --- a/JavaScriptCore/runtime/JSFunction.cpp +++ b/JavaScriptCore/runtime/JSFunction.cpp @@ -56,10 +56,27 @@ JSFunction::JSFunction(NonNullPassRefPtr<Structure> structure) { } +JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<Structure> structure, int length, const Identifier& name, NativeExecutable* thunk, NativeFunction func) + : Base(&exec->globalData(), structure, name) +#if ENABLE(JIT) + , m_executable(thunk) +#endif +{ +#if ENABLE(JIT) + setNativeFunction(func); + putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum); +#else + UNUSED_PARAM(thunk); + UNUSED_PARAM(length); + UNUSED_PARAM(func); + ASSERT_NOT_REACHED(); +#endif +} + 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))) + , m_executable(exec->globalData().jitStubs.ctiNativeCallThunk()) #endif { #if ENABLE(JIT) @@ -122,23 +139,23 @@ JSValue JSFunction::call(ExecState* exec, JSValue thisValue, const ArgList& args return exec->interpreter()->execute(jsExecutable(), exec, this, thisValue.toThisObject(exec), args, scopeChain().node(), exec->exceptionSlot()); } -JSValue JSFunction::argumentsGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue JSFunction::argumentsGetter(ExecState* exec, JSValue slotBase, const Identifier&) { - JSFunction* thisObj = asFunction(slot.slotBase()); + JSFunction* thisObj = asFunction(slotBase); ASSERT(!thisObj->isHostFunction()); return exec->interpreter()->retrieveArguments(exec, thisObj); } -JSValue JSFunction::callerGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue JSFunction::callerGetter(ExecState* exec, JSValue slotBase, const Identifier&) { - JSFunction* thisObj = asFunction(slot.slotBase()); + JSFunction* thisObj = asFunction(slotBase); ASSERT(!thisObj->isHostFunction()); return exec->interpreter()->retrieveCaller(exec, thisObj); } -JSValue JSFunction::lengthGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue JSFunction::lengthGetter(ExecState* exec, JSValue slotBase, const Identifier&) { - JSFunction* thisObj = asFunction(slot.slotBase()); + JSFunction* thisObj = asFunction(slotBase); ASSERT(!thisObj->isHostFunction()); return jsNumber(exec, thisObj->jsExecutable()->parameterCount()); } @@ -162,17 +179,17 @@ bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyN } if (propertyName == exec->propertyNames().arguments) { - slot.setCustom(this, argumentsGetter); + slot.setCacheableCustom(this, argumentsGetter); return true; } if (propertyName == exec->propertyNames().length) { - slot.setCustom(this, lengthGetter); + slot.setCacheableCustom(this, lengthGetter); return true; } if (propertyName == exec->propertyNames().caller) { - slot.setCustom(this, callerGetter); + slot.setCacheableCustom(this, callerGetter); return true; } diff --git a/JavaScriptCore/runtime/JSFunction.h b/JavaScriptCore/runtime/JSFunction.h index 8cd4b51..301b908 100644 --- a/JavaScriptCore/runtime/JSFunction.h +++ b/JavaScriptCore/runtime/JSFunction.h @@ -33,6 +33,7 @@ namespace JSC { class FunctionPrototype; class JSActivation; class JSGlobalObject; + class NativeExecutable; class JSFunction : public InternalFunction { friend class JIT; @@ -42,6 +43,7 @@ namespace JSC { public: JSFunction(ExecState*, NonNullPassRefPtr<Structure>, int length, const Identifier&, NativeFunction); + JSFunction(ExecState*, NonNullPassRefPtr<Structure>, int length, const Identifier&, NativeExecutable*, NativeFunction); JSFunction(ExecState*, NonNullPassRefPtr<FunctionExecutable>, ScopeChainNode*); virtual ~JSFunction(); @@ -90,9 +92,9 @@ namespace JSC { virtual const ClassInfo* classInfo() const { return &info; } - static JSValue argumentsGetter(ExecState*, const Identifier&, const PropertySlot&); - static JSValue callerGetter(ExecState*, const Identifier&, const PropertySlot&); - static JSValue lengthGetter(ExecState*, const Identifier&, const PropertySlot&); + static JSValue argumentsGetter(ExecState*, JSValue, const Identifier&); + static JSValue callerGetter(ExecState*, JSValue, const Identifier&); + static JSValue lengthGetter(ExecState*, JSValue, const Identifier&); RefPtr<ExecutableBase> m_executable; ScopeChain& scopeChain() diff --git a/JavaScriptCore/runtime/JSGlobalData.cpp b/JavaScriptCore/runtime/JSGlobalData.cpp index 45abc86..12fa2be 100644 --- a/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/JavaScriptCore/runtime/JSGlobalData.cpp @@ -49,6 +49,7 @@ #include "Lookup.h" #include "Nodes.h" #include "Parser.h" +#include <wtf/WTFThreadData.h> #if ENABLE(JSC_MULTIPLE_THREADS) #include <wtf/Threading.h> @@ -102,8 +103,8 @@ void JSGlobalData::storeVPtrs() jsFunction->~JSCell(); } -JSGlobalData::JSGlobalData(bool isShared) - : isSharedInstance(isShared) +JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType) + : globalDataType(globalDataType) , clientData(0) , arrayTable(fastNew<HashTable>(JSC::arrayTable)) , dateTable(fastNew<HashTable>(JSC::dateTable)) @@ -115,6 +116,7 @@ JSGlobalData::JSGlobalData(bool isShared) , stringTable(fastNew<HashTable>(JSC::stringTable)) , activationStructure(JSActivation::createStructure(jsNull())) , interruptedExecutionErrorStructure(JSObject::createStructure(jsNull())) + , terminatedExecutionErrorStructure(JSObject::createStructure(jsNull())) , staticScopeStructure(JSStaticScopeObject::createStructure(jsNull())) , stringStructure(JSString::createStructure(jsNull())) , notAnObjectErrorStubStructure(JSNotAnObjectErrorStub::createStructure(jsNull())) @@ -126,7 +128,7 @@ JSGlobalData::JSGlobalData(bool isShared) #if USE(JSVALUE32) , numberStructure(JSNumberCell::createStructure(jsNull())) #endif - , identifierTable(createIdentifierTable()) + , identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable()) , propertyNames(new CommonIdentifiers(this)) , emptyList(new MarkedArgumentBuffer) , lexer(new Lexer(this)) @@ -144,8 +146,9 @@ JSGlobalData::JSGlobalData(bool isShared) , markStack(jsArrayVPtr) , cachedUTCOffset(NaN) , weakRandom(static_cast<int>(currentTime())) + , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth) #ifndef NDEBUG - , mainThreadOnly(false) + , exclusiveThread(0) #endif { #if PLATFORM(MAC) @@ -189,28 +192,26 @@ JSGlobalData::~JSGlobalData() delete emptyList; delete propertyNames; - deleteIdentifierTable(identifierTable); + if (globalDataType != Default) + deleteIdentifierTable(identifierTable); delete clientData; } -PassRefPtr<JSGlobalData> JSGlobalData::createNonDefault() +PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type) { - return adoptRef(new JSGlobalData(false)); + return adoptRef(new JSGlobalData(APIContextGroup, type)); } -PassRefPtr<JSGlobalData> JSGlobalData::create() +PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type) { - JSGlobalData* globalData = new JSGlobalData(false); - setDefaultIdentifierTable(globalData->identifierTable); - setCurrentIdentifierTable(globalData->identifierTable); - return adoptRef(globalData); + return adoptRef(new JSGlobalData(Default, type)); } -PassRefPtr<JSGlobalData> JSGlobalData::createLeaked() +PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type) { Structure::startIgnoringLeaks(); - RefPtr<JSGlobalData> data = create(); + RefPtr<JSGlobalData> data = create(type); Structure::stopIgnoringLeaks(); return data.release(); } @@ -224,7 +225,7 @@ JSGlobalData& JSGlobalData::sharedInstance() { JSGlobalData*& instance = sharedInstanceInternal(); if (!instance) { - instance = new JSGlobalData(true); + instance = new JSGlobalData(APIShared, ThreadStackTypeSmall); #if ENABLE(JSC_MULTIPLE_THREADS) instance->makeUsableFromMultipleThreads(); #endif diff --git a/JavaScriptCore/runtime/JSGlobalData.h b/JavaScriptCore/runtime/JSGlobalData.h index 0f1f3c6..711e148 100644 --- a/JavaScriptCore/runtime/JSGlobalData.h +++ b/JavaScriptCore/runtime/JSGlobalData.h @@ -29,6 +29,7 @@ #ifndef JSGlobalData_h #define JSGlobalData_h +#include "CachedTranscendentalFunction.h" #include "Collector.h" #include "DateInstanceCache.h" #include "ExecutableAllocator.h" @@ -37,6 +38,7 @@ #include "MarkStack.h" #include "NumericStrings.h" #include "SmallStrings.h" +#include "Terminator.h" #include "TimeoutChecker.h" #include "WeakRandom.h" #include <wtf/Forward.h> @@ -83,18 +85,34 @@ namespace JSC { double increment; }; + enum ThreadStackType { + ThreadStackTypeLarge, + ThreadStackTypeSmall + }; + class JSGlobalData : public RefCounted<JSGlobalData> { public: + // WebCore has a one-to-one mapping of threads to JSGlobalDatas; + // either create() or createLeaked() should only be called once + // on a thread, this is the 'default' JSGlobalData (it uses the + // thread's default string uniquing table from wtfThreadData). + // API contexts created using the new context group aware interface + // create APIContextGroup objects which require less locking of JSC + // than the old singleton APIShared JSGlobalData created for use by + // the original API. + enum GlobalDataType { Default, APIContextGroup, APIShared }; + struct ClientData { virtual ~ClientData() = 0; }; + bool isSharedInstance() { return globalDataType == APIShared; } static bool sharedInstanceExists(); static JSGlobalData& sharedInstance(); - static PassRefPtr<JSGlobalData> create(); - static PassRefPtr<JSGlobalData> createLeaked(); - static PassRefPtr<JSGlobalData> createNonDefault(); + static PassRefPtr<JSGlobalData> create(ThreadStackType); + static PassRefPtr<JSGlobalData> createLeaked(ThreadStackType); + static PassRefPtr<JSGlobalData> createContextGroup(ThreadStackType); ~JSGlobalData(); #if ENABLE(JSC_MULTIPLE_THREADS) @@ -102,7 +120,7 @@ namespace JSC { void makeUsableFromMultipleThreads() { heap.makeUsableFromMultipleThreads(); } #endif - bool isSharedInstance; + GlobalDataType globalDataType; ClientData* clientData; const HashTable* arrayTable; @@ -116,6 +134,7 @@ namespace JSC { RefPtr<Structure> activationStructure; RefPtr<Structure> interruptedExecutionErrorStructure; + RefPtr<Structure> terminatedExecutionErrorStructure; RefPtr<Structure> staticScopeStructure; RefPtr<Structure> stringStructure; RefPtr<Structure> notAnObjectErrorStubStructure; @@ -151,8 +170,13 @@ namespace JSC { Interpreter* interpreter; #if ENABLE(JIT) JITThunks jitStubs; + NativeExecutable* getThunk(ThunkGenerator generator) + { + return jitStubs.specializedThunk(this, generator); + } #endif TimeoutChecker timeoutChecker; + Terminator terminator; Heap heap; JSValue exception; @@ -184,21 +208,24 @@ namespace JSC { WeakRandom weakRandom; + int maxReentryDepth; #ifndef NDEBUG - bool mainThreadOnly; + ThreadIdentifier exclusiveThread; #endif + CachedTranscendentalFunction<sin> cachedSin; + void resetDateCache(); void startSampling(); void stopSampling(); void dumpSampleData(ExecState* exec); private: - JSGlobalData(bool isShared); + JSGlobalData(GlobalDataType, ThreadStackType); static JSGlobalData*& sharedInstanceInternal(); void createNativeThunk(); }; - + } // namespace JSC #endif // JSGlobalData_h diff --git a/JavaScriptCore/runtime/JSGlobalObject.cpp b/JavaScriptCore/runtime/JSGlobalObject.cpp index 4bf0a69..7568ffd 100644 --- a/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -117,10 +117,8 @@ JSGlobalObject::~JSGlobalObject() (*it)->clearGlobalObject(); RegisterFile& registerFile = globalData()->interpreter->registerFile(); - if (registerFile.globalObject() == this) { - registerFile.setGlobalObject(0); + if (registerFile.clearGlobalObject(this)) registerFile.setNumGlobals(0); - } d()->destructor(d()); } @@ -319,9 +317,9 @@ void JSGlobalObject::reset(JSValue prototype) // Set global values. GlobalPropertyInfo staticGlobals[] = { GlobalPropertyInfo(Identifier(exec, "Math"), new (exec) MathObject(exec, MathObject::createStructure(d()->objectPrototype)), DontEnum | DontDelete), - GlobalPropertyInfo(Identifier(exec, "NaN"), jsNaN(exec), DontEnum | DontDelete), - GlobalPropertyInfo(Identifier(exec, "Infinity"), jsNumber(exec, Inf), DontEnum | DontDelete), - GlobalPropertyInfo(Identifier(exec, "undefined"), jsUndefined(), DontEnum | DontDelete), + GlobalPropertyInfo(Identifier(exec, "NaN"), jsNaN(exec), DontEnum | DontDelete | ReadOnly), + GlobalPropertyInfo(Identifier(exec, "Infinity"), jsNumber(exec, Inf), DontEnum | DontDelete | ReadOnly), + GlobalPropertyInfo(Identifier(exec, "undefined"), jsUndefined(), DontEnum | DontDelete | ReadOnly), GlobalPropertyInfo(Identifier(exec, "JSON"), new (exec) JSONObject(JSONObject::createStructure(d()->objectPrototype)), DontEnum | DontDelete) }; diff --git a/JavaScriptCore/runtime/JSGlobalObject.h b/JavaScriptCore/runtime/JSGlobalObject.h index bbb6d5e..df942cf 100644 --- a/JavaScriptCore/runtime/JSGlobalObject.h +++ b/JavaScriptCore/runtime/JSGlobalObject.h @@ -25,6 +25,7 @@ #include "JSArray.h" #include "JSGlobalData.h" #include "JSVariableObject.h" +#include "JSWeakObjectMapRefInternal.h" #include "NativeFunctionWrapper.h" #include "NumberPrototype.h" #include "StringPrototype.h" @@ -56,6 +57,7 @@ namespace JSC { class JSGlobalObject : public JSVariableObject { protected: using JSVariableObject::JSVariableObjectData; + typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet; struct JSGlobalObjectData : public JSVariableObjectData { // We use an explicit destructor function pointer instead of a @@ -153,6 +155,7 @@ namespace JSC { RefPtr<JSGlobalData> globalData; HashSet<GlobalCodeBlock*> codeBlocks; + WeakMapSet weakMaps; }; public: @@ -270,6 +273,16 @@ namespace JSC { return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); } + void registerWeakMap(OpaqueJSWeakObjectMap* map) + { + d()->weakMaps.add(map); + } + + void deregisterWeakMap(OpaqueJSWeakObjectMap* map) + { + d()->weakMaps.remove(map); + } + protected: static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags; diff --git a/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp index 3ddac7c..5da5194 100644 --- a/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp +++ b/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp @@ -35,6 +35,7 @@ #include "LiteralParser.h" #include "Nodes.h" #include "Parser.h" +#include "StringBuilder.h" #include "StringExtras.h" #include "dtoa.h" #include <stdio.h> @@ -54,12 +55,12 @@ static JSValue encode(ExecState* exec, const ArgList& args, const char* doNotEsc { UString str = args.at(0).toString(exec); CString cstr = str.UTF8String(true); - if (!cstr.c_str()) + if (!cstr.data()) return throwError(exec, URIError, "String contained an illegal UTF-16 sequence."); JSStringBuilder builder; - const char* p = cstr.c_str(); - for (size_t k = 0; k < cstr.size(); k++, p++) { + const char* p = cstr.data(); + for (size_t k = 0; k < cstr.length(); k++, p++) { char c = *p; if (c && strchr(doNotEscape, c)) builder.append(c); @@ -240,6 +241,7 @@ static double parseInt(const UString& s, int radix) } if (number >= mantissaOverflowLowerBound) { + // FIXME: It is incorrect to use UString::ascii() here because it's not thread-safe. if (radix == 10) number = WTF::strtod(s.substr(firstDigitPosition, p - firstDigitPosition).ascii(), 0); else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32) @@ -268,6 +270,8 @@ static double parseFloat(const UString& s) if (length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X')) return 0; + // FIXME: UString::toDouble will ignore leading ASCII spaces, but we need to ignore + // other StrWhiteSpaceChar values as well. return s.toDouble(true /*tolerant*/, false /* NaN for empty string */); } @@ -381,7 +385,7 @@ JSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec, JSObject*, JSValue, cons JSStringBuilder builder; UString str = args.at(0).toString(exec); const UChar* c = str.data(); - for (int k = 0; k < str.size(); k++, c++) { + for (unsigned k = 0; k < str.size(); k++, c++) { int u = c[0]; if (u > 255) { char tmp[7]; @@ -429,8 +433,7 @@ JSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec, JSObject*, JSValue, co #ifndef NDEBUG JSValue JSC_HOST_CALL globalFuncJSCPrint(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - CStringBuffer string; - args.at(0).toString(exec).getCString(string); + CString string = args.at(0).toString(exec).UTF8String(); puts(string.data()); return jsUndefined(); } diff --git a/JavaScriptCore/runtime/JSImmediate.h b/JavaScriptCore/runtime/JSImmediate.h index 4ed35fc..9127b6a 100644 --- a/JavaScriptCore/runtime/JSImmediate.h +++ b/JavaScriptCore/runtime/JSImmediate.h @@ -22,8 +22,6 @@ #ifndef JSImmediate_h #define JSImmediate_h -#include <wtf/Platform.h> - #if !USE(JSVALUE32_64) #include <wtf/Assertions.h> @@ -138,6 +136,8 @@ namespace JSC { friend class JIT; friend class JSValue; friend class JSFastMath; + friend class JSInterfaceJIT; + friend class SpecializedThunkJIT; friend JSValue jsNumber(ExecState* exec, double d); friend JSValue jsNumber(ExecState*, char i); friend JSValue jsNumber(ExecState*, unsigned char i); @@ -166,7 +166,7 @@ namespace JSC { // This value is 2^48, used to encode doubles such that the encoded value will begin // with a 16-bit pattern within the range 0x0001..0xFFFE. static const intptr_t DoubleEncodeOffset = 0x1000000000000ll; -#else +#elif USE(JSVALUE32) static const intptr_t TagTypeNumber = 0x1; // bottom bit set indicates integer, this dominates the following bit #endif static const intptr_t TagBitTypeOther = 0x2; // second bit set indicates immediate other than an integer diff --git a/JavaScriptCore/runtime/JSLock.cpp b/JavaScriptCore/runtime/JSLock.cpp index 8f056c8..a1cffbd 100644 --- a/JavaScriptCore/runtime/JSLock.cpp +++ b/JavaScriptCore/runtime/JSLock.cpp @@ -60,7 +60,7 @@ static void setLockCount(intptr_t count) } JSLock::JSLock(ExecState* exec) - : m_lockBehavior(exec->globalData().isSharedInstance ? LockForReal : SilenceAssertionsOnly) + : m_lockBehavior(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly) { lock(m_lockBehavior); } @@ -105,12 +105,12 @@ void JSLock::unlock(JSLockBehavior lockBehavior) void JSLock::lock(ExecState* exec) { - lock(exec->globalData().isSharedInstance ? LockForReal : SilenceAssertionsOnly); + lock(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly); } void JSLock::unlock(ExecState* exec) { - unlock(exec->globalData().isSharedInstance ? LockForReal : SilenceAssertionsOnly); + unlock(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly); } bool JSLock::currentThreadIsHoldingLock() @@ -162,7 +162,7 @@ bool JSLock::currentThreadIsHoldingLock() static unsigned lockDropDepth = 0; JSLock::DropAllLocks::DropAllLocks(ExecState* exec) - : m_lockBehavior(exec->globalData().isSharedInstance ? LockForReal : SilenceAssertionsOnly) + : m_lockBehavior(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly) { pthread_once(&createJSLockCountOnce, createJSLockCount); diff --git a/JavaScriptCore/runtime/JSNumberCell.cpp b/JavaScriptCore/runtime/JSNumberCell.cpp index f1009b9..a61c751 100644 --- a/JavaScriptCore/runtime/JSNumberCell.cpp +++ b/JavaScriptCore/runtime/JSNumberCell.cpp @@ -57,11 +57,6 @@ UString JSNumberCell::toString(ExecState*) const return UString::from(m_value); } -UString JSNumberCell::toThisString(ExecState*) const -{ - return UString::from(m_value); -} - JSObject* JSNumberCell::toObject(ExecState* exec) const { return constructNumber(exec, const_cast<JSNumberCell*>(this)); diff --git a/JavaScriptCore/runtime/JSNumberCell.h b/JavaScriptCore/runtime/JSNumberCell.h index bcb506b..cdd2d8c 100644 --- a/JavaScriptCore/runtime/JSNumberCell.h +++ b/JavaScriptCore/runtime/JSNumberCell.h @@ -62,7 +62,6 @@ namespace JSC { virtual UString toString(ExecState*) const; virtual JSObject* toObject(ExecState*) const; - virtual UString toThisString(ExecState*) const; virtual JSObject* toThisObject(ExecState*) const; virtual JSValue getJSNumber(); diff --git a/JavaScriptCore/runtime/JSONObject.cpp b/JavaScriptCore/runtime/JSONObject.cpp index acd9280..f6c6b5f 100644 --- a/JavaScriptCore/runtime/JSONObject.cpp +++ b/JavaScriptCore/runtime/JSONObject.cpp @@ -31,6 +31,7 @@ #include "ExceptionHelpers.h" #include "JSArray.h" #include "LiteralParser.h" +#include "Lookup.h" #include "PropertyNameArray.h" #include "StringBuilder.h" #include <wtf/MathExtras.h> @@ -135,7 +136,7 @@ static inline JSValue unwrapBoxedPrimitive(ExecState* exec, JSValue value) static inline UString gap(ExecState* exec, JSValue space) { - const int maxGapLength = 10; + const unsigned maxGapLength = 10; space = unwrapBoxedPrimitive(exec, space); // If the space value is a number, create a gap string with that number of spaces. @@ -456,7 +457,7 @@ inline bool Stringifier::willIndent() const 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(); + unsigned newSize = m_indent.size() + m_gap.size(); if (newSize > m_repeatedGap.size()) m_repeatedGap = makeString(m_repeatedGap, m_gap); ASSERT(newSize <= m_repeatedGap.size()); @@ -868,4 +869,12 @@ JSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState* exec, JSObject*, JSValue return Stringifier(exec, replacer, space).stringify(value); } +UString JSONStringify(ExecState* exec, JSValue value, unsigned indent) +{ + JSValue result = Stringifier(exec, jsNull(), jsNumber(exec, indent)).stringify(value); + if (result.isUndefinedOrNull()) + return UString(); + return result.getString(exec); +} + } // namespace JSC diff --git a/JavaScriptCore/runtime/JSONObject.h b/JavaScriptCore/runtime/JSONObject.h index 905e4bc..7a9e0a4 100644 --- a/JavaScriptCore/runtime/JSONObject.h +++ b/JavaScriptCore/runtime/JSONObject.h @@ -57,6 +57,8 @@ namespace JSC { static const ClassInfo info; }; + UString JSONStringify(ExecState* exec, JSValue value, unsigned indent); + } // namespace JSC #endif // JSONObject_h diff --git a/JavaScriptCore/runtime/JSObject.cpp b/JavaScriptCore/runtime/JSObject.cpp index d9500aa..61d3bb1 100644 --- a/JavaScriptCore/runtime/JSObject.cpp +++ b/JavaScriptCore/runtime/JSObject.cpp @@ -516,9 +516,12 @@ void JSObject::putDirectFunctionWithoutTransition(ExecState* exec, InternalFunct NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue* location) { - if (JSObject* getterFunction = asGetterSetter(*location)->getter()) - slot.setGetterSlot(getterFunction); - else + if (JSObject* getterFunction = asGetterSetter(*location)->getter()) { + if (!structure()->isDictionary()) + slot.setCacheableGetterSlot(this, getterFunction, offsetForLocation(location)); + else + slot.setGetterSlot(getterFunction); + } else slot.setUndefined(); } diff --git a/JavaScriptCore/runtime/JSObject.h b/JavaScriptCore/runtime/JSObject.h index 2b31a65..64a1118 100644 --- a/JavaScriptCore/runtime/JSObject.h +++ b/JavaScriptCore/runtime/JSObject.h @@ -26,6 +26,7 @@ #include "ArgList.h" #include "ClassInfo.h" #include "CommonIdentifiers.h" +#include "Completion.h" #include "CallFrame.h" #include "JSCell.h" #include "JSNumberCell.h" @@ -35,6 +36,7 @@ #include "ScopeChain.h" #include "Structure.h" #include "JSGlobalData.h" +#include "JSString.h" #include <wtf/StdLibExtras.h> namespace JSC { @@ -194,9 +196,10 @@ namespace JSC { virtual bool isGlobalObject() const { return false; } virtual bool isVariableObject() const { return false; } virtual bool isActivationObject() const { return false; } - virtual bool isWatchdogException() const { return false; } virtual bool isNotAnObjectErrorStub() const { return false; } + virtual ComplType exceptionType() const { return Throw; } + void allocatePropertyStorage(size_t oldSize, size_t newSize); void allocatePropertyStorageInline(size_t oldSize, size_t newSize); bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); } @@ -436,12 +439,20 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue JSCell* currentSpecificFunction; size_t offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction); if (offset != WTF::notFound) { + // If there is currently a specific function, and there now either isn't, + // or the new value is different, then despecify. if (currentSpecificFunction && (specificFunction != currentSpecificFunction)) m_structure->despecifyDictionaryFunction(propertyName); if (checkReadOnly && currentAttributes & ReadOnly) return; putDirectOffset(offset, value); - if (!specificFunction && !currentSpecificFunction) + // At this point, the objects structure only has a specific value set if previously there + // had been one set, and if the new value being specified is the same (otherwise we would + // have despecified, above). So, if currentSpecificFunction is not set, or if the new + // value is different (or there is no new value), then the slot now has no value - and + // as such it is cachable. + // If there was previously a value, and the new value is the same, then we cannot cache. + if (!currentSpecificFunction || (specificFunction != currentSpecificFunction)) slot.setExistingProperty(this, offset); return; } @@ -468,7 +479,8 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue ASSERT(offset < structure->propertyStorageCapacity()); setStructure(structure.release()); putDirectOffset(offset, value); - // See comment on setNewProperty call below. + // This is a new property; transitions with specific values are not currently cachable, + // so leave the slot in an uncachable state. if (!specificFunction) slot.setNewProperty(this, offset); return; @@ -481,14 +493,28 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue if (checkReadOnly && currentAttributes & ReadOnly) return; - if (currentSpecificFunction && (specificFunction != currentSpecificFunction)) { + // There are three possibilities here: + // (1) There is an existing specific value set, and we're overwriting with *the same value*. + // * Do nothing - no need to despecify, but that means we can't cache (a cached + // put could write a different value). Leave the slot in an uncachable state. + // (2) There is a specific value currently set, but we're writing a different value. + // * First, we have to despecify. Having done so, this is now a regular slot + // with no specific value, so go ahead & cache like normal. + // (3) Normal case, there is no specific value set. + // * Go ahead & cache like normal. + if (currentSpecificFunction) { + // case (1) Do the put, then return leaving the slot uncachable. + if (specificFunction == currentSpecificFunction) { + putDirectOffset(offset, value); + return; + } + // case (2) Despecify, fall through to (3). setStructure(Structure::despecifyFunctionTransition(m_structure, propertyName)); - putDirectOffset(offset, value); - // Function transitions are not currently cachable, so leave the slot in an uncachable state. - return; } - putDirectOffset(offset, value); + + // case (3) set the slot, do the put, return. slot.setExistingProperty(this, offset); + putDirectOffset(offset, value); return; } @@ -510,7 +536,8 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue ASSERT(offset < structure->propertyStorageCapacity()); setStructure(structure.release()); putDirectOffset(offset, value); - // Function transitions are not currently cachable, so leave the slot in an uncachable state. + // This is a new property; transitions with specific values are not currently cachable, + // so leave the slot in an uncachable state. if (!specificFunction) slot.setNewProperty(this, offset); } @@ -685,6 +712,18 @@ ALWAYS_INLINE void JSObject::markChildrenDirect(MarkStack& markStack) markStack.appendValues(reinterpret_cast<JSValue*>(storage), storageSize); } +// --- JSValue inlines ---------------------------- + +ALWAYS_INLINE UString JSValue::toThisString(ExecState* exec) const +{ + return isString() ? static_cast<JSString*>(asCell())->value(exec) : toThisObject(exec)->toString(exec); +} + +inline JSString* JSValue::toThisJSString(ExecState* exec) const +{ + return isString() ? static_cast<JSString*>(asCell()) : jsString(exec, toThisObject(exec)->toString(exec)); +} + } // namespace JSC #endif // JSObject_h diff --git a/JavaScriptCore/runtime/JSPropertyNameIterator.h b/JavaScriptCore/runtime/JSPropertyNameIterator.h index 3f533a0..01700ac 100644 --- a/JavaScriptCore/runtime/JSPropertyNameIterator.h +++ b/JavaScriptCore/runtime/JSPropertyNameIterator.h @@ -67,8 +67,13 @@ namespace JSC { 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 setCachedStructure(Structure* structure) + { + ASSERT(!m_cachedStructure); + ASSERT(structure); + m_cachedStructure = structure; + } + Structure* cachedStructure() { return m_cachedStructure.get(); } void setCachedPrototypeChain(NonNullPassRefPtr<StructureChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; } StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); } @@ -76,7 +81,7 @@ namespace JSC { private: JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlot); - Structure* m_cachedStructure; + RefPtr<Structure> m_cachedStructure; RefPtr<StructureChain> m_cachedPrototypeChain; uint32_t m_numCacheableSlots; uint32_t m_jsStringsSize; diff --git a/JavaScriptCore/runtime/JSString.cpp b/JavaScriptCore/runtime/JSString.cpp index 1e23a15..fbc7d72 100644 --- a/JavaScriptCore/runtime/JSString.cpp +++ b/JavaScriptCore/runtime/JSString.cpp @@ -31,48 +31,13 @@ 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 +// we would likely have to place all of the constituent UStringImpls 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.) @@ -82,51 +47,51 @@ void JSString::resolveRope(ExecState* exec) const // 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)) + if (PassRefPtr<UStringImpl> newImpl = UStringImpl::tryCreateUninitialized(m_length, buffer)) m_value = newImpl; else { - for (unsigned i = 0; i < m_ropeLength; ++i) { - m_fibers[i].deref(); - m_fibers[i] = static_cast<void*>(0); + for (unsigned i = 0; i < m_fiberCount; ++i) { + RopeImpl::deref(m_other.m_fibers[i]); + m_other.m_fibers[i] = 0; } - m_ropeLength = 0; + m_fiberCount = 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]; + UChar* position = buffer + m_length; + + // Start with the current RopeImpl. + Vector<RopeImpl::Fiber, 32> workQueue; + RopeImpl::Fiber currentFiber; + for (unsigned i = 0; i < (m_fiberCount - 1); ++i) + workQueue.append(m_other.m_fibers[i]); + currentFiber = m_other.m_fibers[m_fiberCount - 1]; while (true) { - if (currentFiber.isRope()) { - Rope* rope = currentFiber.rope(); + if (RopeImpl::isRope(currentFiber)) { + RopeImpl* rope = static_cast<RopeImpl*>(currentFiber); // 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) + unsigned fiberCountMinusOne = rope->fiberCount() - 1; + for (unsigned i = 0; i < fiberCountMinusOne; ++i) workQueue.append(rope->fibers(i)); - currentFiber = rope->fibers(ropeLengthMinusOne); + currentFiber = rope->fibers(fiberCountMinusOne); } else { - UString::Rep* string = currentFiber.string(); - unsigned length = string->size(); + UStringImpl* string = static_cast<UStringImpl*>(currentFiber); + unsigned length = string->length(); position -= length; - UStringImpl::copyChars(position, string->data(), length); + UStringImpl::copyChars(position, string->characters(), 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); + for (unsigned i = 0; i < m_fiberCount; ++i) { + RopeImpl::deref(m_other.m_fibers[i]); + m_other.m_fibers[i] = 0; } - m_ropeLength = 0; + m_fiberCount = 0; ASSERT(!isRope()); return; @@ -139,6 +104,18 @@ void JSString::resolveRope(ExecState* exec) const } } +JSString* JSString::getIndexSlowCase(ExecState* exec, unsigned i) +{ + ASSERT(isRope()); + resolveRope(exec); + // Return a safe no-value result, this should never be used, since the excetion will be thrown. + if (exec->exception()) + return jsString(exec, ""); + ASSERT(!isRope()); + ASSERT(i < m_value.size()); + return jsSingleCharacterSubstring(exec, m_value, i); +} + JSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const { return const_cast<JSString*>(this); @@ -153,7 +130,7 @@ bool JSString::getPrimitiveNumber(ExecState* exec, double& number, JSValue& resu bool JSString::toBoolean(ExecState*) const { - return m_stringLength; + return m_length; } double JSString::toNumber(ExecState* exec) const @@ -166,16 +143,6 @@ UString JSString::toString(ExecState* exec) const return value(exec); } -UString JSString::toThisString(ExecState* exec) const -{ - return value(exec); -} - -JSString* JSString::toThisJSString(ExecState*) -{ - return this; -} - inline StringObject* StringObject::create(ExecState* exec, JSString* string) { return new (exec) StringObject(exec->lexicalGlobalObject()->stringObjectStructure(), string); @@ -215,14 +182,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_stringLength), DontEnum | DontDelete | ReadOnly); + descriptor.setDescriptor(jsNumber(exec, m_length), DontEnum | DontDelete | ReadOnly); return true; } bool isStrictUInt32; unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); - if (isStrictUInt32 && i < m_stringLength) { - descriptor.setDescriptor(jsSingleCharacterSubstring(exec, value(exec), i), DontDelete | ReadOnly); + if (isStrictUInt32 && i < m_length) { + descriptor.setDescriptor(getIndex(exec, i), DontDelete | ReadOnly); return true; } diff --git a/JavaScriptCore/runtime/JSString.h b/JavaScriptCore/runtime/JSString.h index cff8e3a..85d3c8e 100644 --- a/JavaScriptCore/runtime/JSString.h +++ b/JavaScriptCore/runtime/JSString.h @@ -29,6 +29,7 @@ #include "JSNumberCell.h" #include "PropertyDescriptor.h" #include "PropertySlot.h" +#include "RopeImpl.h" namespace JSC { @@ -41,7 +42,6 @@ namespace JSC { JSString* jsSingleCharacterString(JSGlobalData*, UChar); JSString* jsSingleCharacterString(ExecState*, UChar); - JSString* jsSingleCharacterSubstring(JSGlobalData*, const UString&, unsigned offset); JSString* jsSingleCharacterSubstring(ExecState*, const UString&, unsigned offset); JSString* jsSubstring(JSGlobalData*, const UString&, unsigned offset, unsigned length); JSString* jsSubstring(ExecState*, const UString&, unsigned offset, unsigned length); @@ -66,183 +66,132 @@ namespace JSC { public: friend class JIT; friend class JSGlobalData; + friend class SpecializedThunkJIT; + friend struct ThunkHelpers; - // A Rope is a string composed of a set of substrings. - class Rope : public RefCounted<Rope> { + class RopeBuilder { 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) + RopeBuilder(unsigned fiberCount) + : m_index(0) + , m_rope(RopeImpl::tryCreateUninitialized(fiberCount)) { - void* allocation; - if (tryFastMalloc(sizeof(Rope) + (ropeLength - 1) * sizeof(Fiber)).getValue(allocation)) - return adoptRef(new (allocation) Rope(ropeLength)); - return 0; } - ~Rope(); - void destructNonRecursive(); + bool isOutOfMemory() { return !m_rope; } - void append(unsigned &index, Fiber& fiber) + void append(RopeImpl::Fiber& fiber) { - m_fibers[index++] = fiber; - m_stringLength += fiber.refAndGetLength(); + ASSERT(m_rope); + m_rope->initializeFiber(m_index, fiber); } - void append(unsigned &index, const UString& string) + void append(const UString& string) { - UString::Rep* rep = string.rep(); - m_fibers[index++] = Fiber(rep); - m_stringLength += rep->ref()->size(); + ASSERT(m_rope); + m_rope->initializeFiber(m_index, string.rep()); } - void append(unsigned& index, JSString* jsString) + void append(JSString* jsString) { if (jsString->isRope()) { - for (unsigned i = 0; i < jsString->m_ropeLength; ++i) - append(index, jsString->m_fibers[i]); + for (unsigned i = 0; i < jsString->m_fiberCount; ++i) + append(jsString->m_other.m_fibers[i]); } else - append(index, jsString->string()); + append(jsString->string()); } - unsigned ropeLength() { return m_ropeLength; } - unsigned stringLength() { return m_stringLength; } - Fiber& fibers(unsigned index) { return m_fibers[index]; } + PassRefPtr<RopeImpl> release() + { + ASSERT(m_index == m_rope->fiberCount()); + return m_rope.release(); + } + + unsigned length() { return m_rope->length(); } 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]; + unsigned m_index; + RefPtr<RopeImpl> m_rope; }; ALWAYS_INLINE JSString(JSGlobalData* globalData, const UString& value) : JSCell(globalData->stringStructure.get()) - , m_stringLength(value.size()) + , m_length(value.size()) , m_value(value) - , m_ropeLength(0) + , m_fiberCount(0) { + ASSERT(!m_value.isNull()); Heap::heap(this)->reportExtraMemoryCost(value.cost()); } enum HasOtherOwnerType { HasOtherOwner }; JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType) : JSCell(globalData->stringStructure.get()) - , m_stringLength(value.size()) + , m_length(value.size()) , m_value(value) - , m_ropeLength(0) + , m_fiberCount(0) { + ASSERT(!m_value.isNull()); } JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType) : JSCell(globalData->stringStructure.get()) - , m_stringLength(value->size()) + , m_length(value->length()) , m_value(value) - , m_ropeLength(0) + , m_fiberCount(0) { + ASSERT(!m_value.isNull()); } - JSString(JSGlobalData* globalData, PassRefPtr<JSString::Rope> rope) + JSString(JSGlobalData* globalData, PassRefPtr<RopeImpl> rope) : JSCell(globalData->stringStructure.get()) - , m_stringLength(rope->stringLength()) - , m_ropeLength(1) + , m_length(rope->length()) + , m_fiberCount(1) { - m_fibers[0] = rope.releaseRef(); + m_other.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) + // This should only be called with fiberCount <= 3. + JSString(JSGlobalData* globalData, unsigned fiberCount, JSString* s1, JSString* s2) : JSCell(globalData->stringStructure.get()) - , m_stringLength(s1->length() + s2->length()) - , m_ropeLength(ropeLength) + , m_length(s1->length() + s2->length()) + , m_fiberCount(fiberCount) { - ASSERT(ropeLength <= s_maxInternalRopeLength); + ASSERT(fiberCount <= s_maxInternalRopeLength); unsigned index = 0; appendStringInConstruct(index, s1); appendStringInConstruct(index, s2); - ASSERT(ropeLength == index); + ASSERT(fiberCount == 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) + // This should only be called with fiberCount <= 3. + JSString(JSGlobalData* globalData, unsigned fiberCount, JSString* s1, const UString& u2) : JSCell(globalData->stringStructure.get()) - , m_stringLength(s1->length() + u2.size()) - , m_ropeLength(ropeLength) + , m_length(s1->length() + u2.size()) + , m_fiberCount(fiberCount) { - ASSERT(ropeLength <= s_maxInternalRopeLength); + ASSERT(fiberCount <= s_maxInternalRopeLength); unsigned index = 0; appendStringInConstruct(index, s1); appendStringInConstruct(index, u2); - ASSERT(ropeLength == index); + ASSERT(fiberCount == 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) + // This should only be called with fiberCount <= 3. + JSString(JSGlobalData* globalData, unsigned fiberCount, const UString& u1, JSString* s2) : JSCell(globalData->stringStructure.get()) - , m_stringLength(u1.size() + s2->length()) - , m_ropeLength(ropeLength) + , m_length(u1.size() + s2->length()) + , m_fiberCount(fiberCount) { - ASSERT(ropeLength <= s_maxInternalRopeLength); + ASSERT(fiberCount <= s_maxInternalRopeLength); unsigned index = 0; appendStringInConstruct(index, u1); appendStringInConstruct(index, s2); - ASSERT(ropeLength == index); + ASSERT(fiberCount == 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 + // This should only be called with fiberCount <= 3 ... which since every + // value must require a fiberCount 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) + , m_length(0) + , m_fiberCount(s_maxInternalRopeLength) { unsigned index = 0; appendValueInConstructAndIncrementLength(exec, index, v1); @@ -253,26 +202,25 @@ namespace JSC { JSString(JSGlobalData* globalData, const UString& value, JSStringFinalizerCallback finalizer, void* context) : JSCell(globalData->stringStructure.get()) - , m_stringLength(value.size()) + , m_length(value.size()) , m_value(value) - , m_ropeLength(0) + , m_fiberCount(0) { + ASSERT(!m_value.isNull()); // 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; + m_other.m_finalizerCallback = finalizer; + m_other.m_finalizerContext = context; Heap::heap(this)->reportExtraMemoryCost(value.cost()); } ~JSString() { ASSERT(vptr() == JSGlobalData::jsStringVPtr); - for (unsigned i = 0; i < m_ropeLength; ++i) - m_fibers[i].deref(); + for (unsigned i = 0; i < m_fiberCount; ++i) + RopeImpl::deref(m_other.m_fibers[i]); - if (!m_ropeLength && m_fibers[0].nonFiber()) { - JSStringFinalizerCallback finalizer = reinterpret_cast<JSStringFinalizerCallback>(m_fibers[0].nonFiber()); - finalizer(this, m_fibers[1].nonFiber()); - } + if (!m_fiberCount && m_other.m_finalizerCallback) + m_other.m_finalizerCallback(this, m_other.m_finalizerContext); } const UString& value(ExecState* exec) const @@ -288,14 +236,15 @@ namespace JSC { ASSERT(isRope() == m_value.isNull()); return m_value; } - unsigned length() { return m_stringLength; } + unsigned length() { return m_length; } bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); bool getStringPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&); - bool canGetIndex(unsigned i) { return i < m_stringLength; } + bool canGetIndex(unsigned i) { return i < m_length; } JSString* getIndex(ExecState*, unsigned); + JSString* getIndexSlowCase(ExecState*, unsigned); static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount); } @@ -303,7 +252,7 @@ namespace JSC { enum VPtrStealingHackType { VPtrStealingHack }; JSString(VPtrStealingHackType) : JSCell(0) - , m_ropeLength(0) + , m_fiberCount(0) { } @@ -311,14 +260,19 @@ namespace JSC { void appendStringInConstruct(unsigned& index, const UString& string) { - m_fibers[index++] = Rope::Fiber(string.rep()->ref()); + UStringImpl* impl = string.rep(); + impl->ref(); + m_other.m_fibers[index++] = impl; } 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(); + for (unsigned i = 0; i < jsString->m_fiberCount; ++i) { + RopeImpl::Fiber fiber = jsString->m_other.m_fibers[i]; + fiber->ref(); + m_other.m_fibers[index++] = fiber; + } } else appendStringInConstruct(index, jsString->string()); } @@ -328,13 +282,15 @@ namespace JSC { if (v.isString()) { ASSERT(asCell(v)->isString()); JSString* s = static_cast<JSString*>(asCell(v)); - ASSERT(s->ropeLength() == 1); + ASSERT(s->fiberCount() == 1); appendStringInConstruct(index, s); - m_stringLength += s->length(); + m_length += s->length(); } else { UString u(v.toString(exec)); - m_fibers[index++] = Rope::Fiber(u.rep()->ref()); - m_stringLength += u.size(); + UStringImpl* impl = u.rep(); + impl->ref(); + m_other.m_fibers[index++] = impl; + m_length += u.size(); } } @@ -346,8 +302,6 @@ namespace JSC { virtual UString toString(ExecState*) const; virtual JSObject* toThisObject(ExecState*) const; - virtual UString toThisString(ExecState*) const; - virtual JSString* toThisJSString(ExecState*); // Actually getPropertySlot, not getOwnPropertySlot (see JSCell). virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); @@ -356,15 +310,25 @@ namespace JSC { static const unsigned s_maxInternalRopeLength = 3; - // A string is represented either by a UString or a Rope. - unsigned m_stringLength; + // A string is represented either by a UString or a RopeImpl. + unsigned m_length; mutable UString m_value; - mutable unsigned m_ropeLength; - mutable Rope::Fiber m_fibers[s_maxInternalRopeLength]; + mutable unsigned m_fiberCount; + // This structure exists to support a temporary workaround for a GC issue. + struct JSStringFinalizerStruct { + JSStringFinalizerStruct() : m_finalizerCallback(0) {} + union { + mutable RopeImpl::Fiber m_fibers[s_maxInternalRopeLength]; + struct { + JSStringFinalizerCallback m_finalizerCallback; + void* m_finalizerContext; + }; + }; + } m_other; - bool isRope() const { return m_ropeLength; } + bool isRope() const { return m_fiberCount; } UString& string() { ASSERT(!isRope()); return m_value; } - unsigned ropeLength() { return m_ropeLength ? m_ropeLength : 1; } + unsigned fiberCount() { return m_fiberCount ? m_fiberCount : 1; } friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2); friend JSValue jsString(ExecState* exec, const UString& u1, JSString* s2); @@ -404,8 +368,9 @@ namespace JSC { return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(&c, 1))); } - inline JSString* jsSingleCharacterSubstring(JSGlobalData* globalData, const UString& s, unsigned offset) + inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset) { + JSGlobalData* globalData = &exec->globalData(); ASSERT(offset < static_cast<unsigned>(s.size())); UChar c = s.data()[offset]; if (c <= 0xFF) @@ -430,7 +395,10 @@ namespace JSC { inline JSString* JSString::getIndex(ExecState* exec, unsigned i) { ASSERT(canGetIndex(i)); - return jsSingleCharacterSubstring(&exec->globalData(), value(exec), i); + if (isRope()) + return getIndexSlowCase(exec, i); + ASSERT(i < m_value.size()); + return jsSingleCharacterSubstring(exec, value(exec), i); } inline JSString* jsString(JSGlobalData* globalData, const UString& s) @@ -484,7 +452,6 @@ namespace JSC { inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); } inline JSString* jsString(ExecState* exec, const UString& s) { return jsString(&exec->globalData(), s); } inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->globalData(), c); } - inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset) { return jsSingleCharacterSubstring(&exec->globalData(), s, offset); } inline JSString* jsSubstring(ExecState* exec, const UString& s, unsigned offset, unsigned length) { return jsSubstring(&exec->globalData(), s, offset, length); } inline JSString* jsNontrivialString(ExecState* exec, const UString& s) { return jsNontrivialString(&exec->globalData(), s); } inline JSString* jsNontrivialString(ExecState* exec, const char* s) { return jsNontrivialString(&exec->globalData(), s); } @@ -493,14 +460,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_stringLength)); + slot.setValue(jsNumber(exec, m_length)); return true; } bool isStrictUInt32; unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); - if (isStrictUInt32 && i < m_stringLength) { - slot.setValue(jsSingleCharacterSubstring(exec, value(exec), i)); + if (isStrictUInt32 && i < m_length) { + slot.setValue(getIndex(exec, i)); return true; } @@ -509,8 +476,8 @@ namespace JSC { ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) { - if (propertyName < m_stringLength) { - slot.setValue(jsSingleCharacterSubstring(exec, value(exec), propertyName)); + if (propertyName < m_length) { + slot.setValue(getIndex(exec, propertyName)); return true; } @@ -521,11 +488,6 @@ namespace JSC { // --- JSValue inlines ---------------------------- - inline JSString* JSValue::toThisJSString(ExecState* exec) - { - return isCell() ? asCell()->toThisJSString(exec) : jsString(exec, toString(exec)); - } - inline UString JSValue::toString(ExecState* exec) const { if (isString()) diff --git a/JavaScriptCore/runtime/JSStringBuilder.h b/JavaScriptCore/runtime/JSStringBuilder.h index 2b11736..8f208a1 100644 --- a/JavaScriptCore/runtime/JSStringBuilder.h +++ b/JavaScriptCore/runtime/JSStringBuilder.h @@ -28,31 +28,59 @@ #include "ExceptionHelpers.h" #include "JSString.h" -#include "StringBuilder.h" +#include "Vector.h" namespace JSC { -class JSStringBuilder : public StringBuilder { +class JSStringBuilder { public: + JSStringBuilder() + : m_okay(true) + { + } + + void append(const UChar u) + { + m_okay &= buffer.tryAppend(&u, 1); + } + + void append(const char* str) + { + append(str, strlen(str)); + } + + void append(const char* str, size_t len) + { + m_okay &= buffer.tryReserveCapacity(buffer.size() + len); + for (size_t i = 0; i < len; i++) { + UChar u = static_cast<unsigned char>(str[i]); + m_okay &= buffer.tryAppend(&u, 1); + } + } + + void append(const UChar* str, size_t len) + { + m_okay &= buffer.tryAppend(str, len); + } + + void append(const UString& str) + { + m_okay &= buffer.tryAppend(str.data(), str.size()); + } + JSValue build(ExecState* exec) { + if (!m_okay) + return throwOutOfMemoryError(exec); buffer.shrinkToFit(); if (!buffer.data()) return throwOutOfMemoryError(exec); return jsString(exec, UString::adopt(buffer)); } -private: - // Make attempts to call this compile error - if you only wanted a UString, - // Why didn't you just use a StringBuilder?! (This may change, maybe at some - // point in the future we'll need to start building a string not knowing whether - // we'll want a UString or a JSValue - but until we have this requirement, - // block this). - UString build() - { - ASSERT_NOT_REACHED(); - return StringBuilder::build(); - } +protected: + Vector<UChar, 64> buffer; + bool m_okay; }; template<typename StringType1, typename StringType2> diff --git a/JavaScriptCore/runtime/JSTypeInfo.h b/JavaScriptCore/runtime/JSTypeInfo.h index 7c89600..e225bc7 100644 --- a/JavaScriptCore/runtime/JSTypeInfo.h +++ b/JavaScriptCore/runtime/JSTypeInfo.h @@ -50,6 +50,8 @@ namespace JSC { TypeInfo(JSType type, unsigned flags = 0) : m_type(type) { + ASSERT(flags <= 0xFF); + ASSERT(type <= 0xFF); // ImplementsDefaultHasInstance means (ImplementsHasInstance & !OverridesHasInstance) if ((flags & (ImplementsHasInstance | OverridesHasInstance)) == ImplementsHasInstance) m_flags = flags | ImplementsDefaultHasInstance; @@ -57,7 +59,7 @@ namespace JSC { m_flags = flags; } - JSType type() const { return m_type; } + JSType type() const { return (JSType)m_type; } bool masqueradesAsUndefined() const { return m_flags & MasqueradesAsUndefined; } bool implementsHasInstance() const { return m_flags & ImplementsHasInstance; } @@ -69,8 +71,8 @@ namespace JSC { unsigned flags() const { return m_flags; } private: - JSType m_type; - unsigned m_flags; + unsigned char m_type; + unsigned char m_flags; }; } diff --git a/JavaScriptCore/runtime/JSValue.h b/JavaScriptCore/runtime/JSValue.h index 6da921f..bcf82ee 100644 --- a/JavaScriptCore/runtime/JSValue.h +++ b/JavaScriptCore/runtime/JSValue.h @@ -66,6 +66,8 @@ namespace JSC { friend class JIT; friend class JITStubs; friend class JITStubCall; + friend class JSInterfaceJIT; + friend class SpecializedThunkJIT; public: static EncodedJSValue encode(JSValue value); @@ -188,7 +190,7 @@ namespace JSC { bool needsThisConversion() const; JSObject* toThisObject(ExecState*) const; UString toThisString(ExecState*) const; - JSString* toThisJSString(ExecState*); + JSString* toThisJSString(ExecState*) const; static bool equal(ExecState* exec, JSValue v1, JSValue v2); static bool equalSlowCase(ExecState* exec, JSValue v1, JSValue v2); @@ -214,6 +216,10 @@ namespace JSC { JSObject* toObjectSlowCase(ExecState*) const; JSObject* toThisObjectSlowCase(ExecState*) const; + JSObject* synthesizePrototype(ExecState*) const; + JSObject* synthesizeObject(ExecState*) const; + +#if USE(JSVALUE32_64) enum { Int32Tag = 0xffffffff }; enum { CellTag = 0xfffffffe }; enum { TrueTag = 0xfffffffd }; @@ -222,16 +228,12 @@ namespace JSC { enum { UndefinedTag = 0xfffffffa }; enum { EmptyValueTag = 0xfffffff9 }; enum { DeletedValueTag = 0xfffffff8 }; - + enum { LowestTag = DeletedValueTag }; - + uint32_t tag() const; int32_t payload() const; - JSObject* synthesizePrototype(ExecState*) const; - JSObject* synthesizeObject(ExecState*) const; - -#if USE(JSVALUE32_64) union { EncodedJSValue asEncodedJSValue; double asDouble; diff --git a/JavaScriptCore/runtime/JSZombie.h b/JavaScriptCore/runtime/JSZombie.h index 8b33ea6..711f673 100644 --- a/JavaScriptCore/runtime/JSZombie.h +++ b/JavaScriptCore/runtime/JSZombie.h @@ -60,8 +60,6 @@ public: 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; } diff --git a/JavaScriptCore/runtime/Lookup.cpp b/JavaScriptCore/runtime/Lookup.cpp index 4e9e086..0042e4d 100644 --- a/JavaScriptCore/runtime/Lookup.cpp +++ b/JavaScriptCore/runtime/Lookup.cpp @@ -46,7 +46,11 @@ void HashTable::createTable(JSGlobalData* globalData) const entry = entry->next(); } - entry->initialize(identifier, values[i].attributes, values[i].value1, values[i].value2); + entry->initialize(identifier, values[i].attributes, values[i].value1, values[i].value2 +#if ENABLE(JIT) + , values[i].generator +#endif + ); } table = entries; } @@ -70,7 +74,13 @@ void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* JSValue* location = thisObj->getDirectLocation(propertyName); if (!location) { - InternalFunction* function = new (exec) NativeFunctionWrapper(exec, exec->lexicalGlobalObject()->prototypeFunctionStructure(), entry->functionLength(), propertyName, entry->function()); + InternalFunction* function; +#if ENABLE(JIT) + if (entry->generator()) + function = new (exec) NativeFunctionWrapper(exec, exec->lexicalGlobalObject()->prototypeFunctionStructure(), entry->functionLength(), propertyName, exec->globalData().getThunk(entry->generator()), entry->function()); + else +#endif + function = new (exec) NativeFunctionWrapper(exec, exec->lexicalGlobalObject()->prototypeFunctionStructure(), entry->functionLength(), propertyName, entry->function()); thisObj->putDirectFunction(propertyName, function, entry->attributes()); location = thisObj->getDirectLocation(propertyName); diff --git a/JavaScriptCore/runtime/Lookup.h b/JavaScriptCore/runtime/Lookup.h index e673c09..dd36400 100644 --- a/JavaScriptCore/runtime/Lookup.h +++ b/JavaScriptCore/runtime/Lookup.h @@ -37,13 +37,15 @@ #endif namespace JSC { - // Hash table generated by the create_hash_table script. struct HashTableValue { const char* key; // property name unsigned char attributes; // JSObject attributes intptr_t value1; intptr_t value2; +#if ENABLE(JIT) + ThunkGenerator generator; +#endif }; // FIXME: There is no reason this get function can't be simpler. @@ -53,12 +55,19 @@ namespace JSC { class HashEntry : public FastAllocBase { public: - void initialize(UString::Rep* key, unsigned char attributes, intptr_t v1, intptr_t v2) + void initialize(UString::Rep* key, unsigned char attributes, intptr_t v1, intptr_t v2 +#if ENABLE(JIT) + , ThunkGenerator generator = 0 +#endif + ) { m_key = key; m_attributes = attributes; m_u.store.value1 = v1; m_u.store.value2 = v2; +#if ENABLE(JIT) + m_u.function.generator = generator; +#endif m_next = 0; } @@ -67,6 +76,9 @@ namespace JSC { unsigned char attributes() const { return m_attributes; } +#if ENABLE(JIT) + ThunkGenerator generator() const { ASSERT(m_attributes & Function); return m_u.function.generator; } +#endif NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; } unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); } @@ -90,6 +102,9 @@ namespace JSC { struct { NativeFunction functionValue; intptr_t length; // number of arguments for function +#if ENABLE(JIT) + ThunkGenerator generator; +#endif } function; struct { GetFunction get; @@ -181,7 +196,7 @@ namespace JSC { if (entry->attributes() & Function) setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot); else - slot.setCustom(thisObj, entry->propertyGetter()); + slot.setCacheableCustom(thisObj, entry->propertyGetter()); return true; } @@ -258,7 +273,7 @@ namespace JSC { ASSERT(!(entry->attributes() & Function)); - slot.setCustom(thisObj, entry->propertyGetter()); + slot.setCacheableCustom(thisObj, entry->propertyGetter()); return true; } diff --git a/JavaScriptCore/runtime/MathObject.cpp b/JavaScriptCore/runtime/MathObject.cpp index 8f22fba..1e28dfa 100644 --- a/JavaScriptCore/runtime/MathObject.cpp +++ b/JavaScriptCore/runtime/MathObject.cpp @@ -21,6 +21,7 @@ #include "config.h" #include "MathObject.h" +#include "Lookup.h" #include "ObjectPrototype.h" #include "Operations.h" #include <time.h> @@ -216,15 +217,13 @@ JSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState* exec, JSObject*, JSValue, c JSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec, JSObject*, JSValue, const ArgList& args) { double arg = args.at(0).toNumber(exec); - if (signbit(arg) && arg >= -0.5) - return jsNumber(exec, -0.0); double integer = ceil(arg); return jsNumber(exec, integer - (integer - arg > 0.5)); } JSValue JSC_HOST_CALL mathProtoFuncSin(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsDoubleNumber(exec, sin(args.at(0).toNumber(exec))); + return exec->globalData().cachedSin(exec, args.at(0).toNumber(exec)); } JSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState* exec, JSObject*, JSValue, const ArgList& args) diff --git a/JavaScriptCore/runtime/NumberConstructor.cpp b/JavaScriptCore/runtime/NumberConstructor.cpp index cc6c51d..0b7e821 100644 --- a/JavaScriptCore/runtime/NumberConstructor.cpp +++ b/JavaScriptCore/runtime/NumberConstructor.cpp @@ -22,6 +22,7 @@ #include "config.h" #include "NumberConstructor.h" +#include "Lookup.h" #include "NumberObject.h" #include "NumberPrototype.h" @@ -29,11 +30,11 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(NumberConstructor); -static JSValue numberConstructorNaNValue(ExecState*, const Identifier&, const PropertySlot&); -static JSValue numberConstructorNegInfinity(ExecState*, const Identifier&, const PropertySlot&); -static JSValue numberConstructorPosInfinity(ExecState*, const Identifier&, const PropertySlot&); -static JSValue numberConstructorMaxValue(ExecState*, const Identifier&, const PropertySlot&); -static JSValue numberConstructorMinValue(ExecState*, const Identifier&, const PropertySlot&); +static JSValue numberConstructorNaNValue(ExecState*, JSValue, const Identifier&); +static JSValue numberConstructorNegInfinity(ExecState*, JSValue, const Identifier&); +static JSValue numberConstructorPosInfinity(ExecState*, JSValue, const Identifier&); +static JSValue numberConstructorMaxValue(ExecState*, JSValue, const Identifier&); +static JSValue numberConstructorMinValue(ExecState*, JSValue, const Identifier&); } // namespace JSC @@ -73,27 +74,27 @@ bool NumberConstructor::getOwnPropertyDescriptor(ExecState* exec, const Identifi return getStaticValueDescriptor<NumberConstructor, InternalFunction>(exec, ExecState::numberTable(exec), this, propertyName, descriptor); } -static JSValue numberConstructorNaNValue(ExecState* exec, const Identifier&, const PropertySlot&) +static JSValue numberConstructorNaNValue(ExecState* exec, JSValue, const Identifier&) { return jsNaN(exec); } -static JSValue numberConstructorNegInfinity(ExecState* exec, const Identifier&, const PropertySlot&) +static JSValue numberConstructorNegInfinity(ExecState* exec, JSValue, const Identifier&) { return jsNumber(exec, -Inf); } -static JSValue numberConstructorPosInfinity(ExecState* exec, const Identifier&, const PropertySlot&) +static JSValue numberConstructorPosInfinity(ExecState* exec, JSValue, const Identifier&) { return jsNumber(exec, Inf); } -static JSValue numberConstructorMaxValue(ExecState* exec, const Identifier&, const PropertySlot&) +static JSValue numberConstructorMaxValue(ExecState* exec, JSValue, const Identifier&) { return jsNumber(exec, 1.7976931348623157E+308); } -static JSValue numberConstructorMinValue(ExecState* exec, const Identifier&, const PropertySlot&) +static JSValue numberConstructorMinValue(ExecState* exec, JSValue, const Identifier&) { return jsNumber(exec, 5E-324); } diff --git a/JavaScriptCore/runtime/NumberPrototype.cpp b/JavaScriptCore/runtime/NumberPrototype.cpp index fa32b86..5680eb1 100644 --- a/JavaScriptCore/runtime/NumberPrototype.cpp +++ b/JavaScriptCore/runtime/NumberPrototype.cpp @@ -265,11 +265,11 @@ JSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec, JSObject*, JSValue z.append(m); m = z.build(); k = f + 1; - ASSERT(k == m.size()); + ASSERT(k == static_cast<int>(m.size())); } int kMinusf = k - f; - if (kMinusf < m.size()) + if (kMinusf < static_cast<int>(m.size())) return jsString(exec, makeString(s, m.substr(0, kMinusf), ".", m.substr(kMinusf))); return jsString(exec, makeString(s, m.substr(0, kMinusf))); } @@ -444,7 +444,7 @@ JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSV if (e == precision - 1) return jsString(exec, makeString(s, m)); if (e >= 0) { - if (e + 1 < m.size()) + if (e + 1 < static_cast<int>(m.size())) return jsString(exec, makeString(s, m.substr(0, e + 1), ".", m.substr(e + 1))); return jsString(exec, makeString(s, m)); } diff --git a/JavaScriptCore/runtime/NumericStrings.h b/JavaScriptCore/runtime/NumericStrings.h index c0696a4..89235af 100644 --- a/JavaScriptCore/runtime/NumericStrings.h +++ b/JavaScriptCore/runtime/NumericStrings.h @@ -45,6 +45,8 @@ namespace JSC { UString add(int i) { + if (static_cast<unsigned>(i) < cacheSize) + return lookupSmallString(static_cast<unsigned>(i)); CacheEntry<int>& entry = lookup(i); if (i == entry.key && !entry.value.isNull()) return entry.value; @@ -53,6 +55,17 @@ namespace JSC { return entry.value; } + UString add(unsigned i) + { + if (i < cacheSize) + return lookupSmallString(static_cast<unsigned>(i)); + CacheEntry<unsigned>& entry = lookup(i); + if (i == entry.key && !entry.value.isNull()) + return entry.value; + entry.key = i; + entry.value = UString::from(i); + return entry.value; + } private: static const size_t cacheSize = 64; @@ -64,9 +77,19 @@ namespace JSC { CacheEntry<double>& lookup(double d) { return doubleCache[WTF::FloatHash<double>::hash(d) & (cacheSize - 1)]; } CacheEntry<int>& lookup(int i) { return intCache[WTF::IntHash<int>::hash(i) & (cacheSize - 1)]; } + CacheEntry<unsigned>& lookup(unsigned i) { return unsignedCache[WTF::IntHash<unsigned>::hash(i) & (cacheSize - 1)]; } + const UString& lookupSmallString(unsigned i) + { + ASSERT(i < cacheSize); + if (smallIntCache[i].isNull()) + smallIntCache[i] = UString::from(i); + return smallIntCache[i]; + } CacheEntry<double> doubleCache[cacheSize]; CacheEntry<int> intCache[cacheSize]; + CacheEntry<unsigned> unsignedCache[cacheSize]; + UString smallIntCache[cacheSize]; }; } // namespace JSC diff --git a/JavaScriptCore/runtime/Operations.h b/JavaScriptCore/runtime/Operations.h index 9b27074..cc0d603 100644 --- a/JavaScriptCore/runtime/Operations.h +++ b/JavaScriptCore/runtime/Operations.h @@ -37,132 +37,167 @@ namespace JSC { ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2) { - if (!s1->length()) + unsigned length1 = s1->length(); + if (!length1) return s2; - if (!s2->length()) + unsigned length2 = s2->length(); + if (!length2) return s1; + if ((length1 + length2) < length1) + return throwOutOfMemoryError(exec); - unsigned ropeLength = s1->ropeLength() + s2->ropeLength(); + unsigned fiberCount = s1->fiberCount() + s2->fiberCount(); JSGlobalData* globalData = &exec->globalData(); - if (ropeLength <= JSString::s_maxInternalRopeLength) - return new (globalData) JSString(globalData, ropeLength, s1, s2); + if (fiberCount <= JSString::s_maxInternalRopeLength) + return new (globalData) JSString(globalData, fiberCount, s1, s2); - unsigned index = 0; - RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); - if (UNLIKELY(!rope)) + JSString::RopeBuilder ropeBuilder(fiberCount); + if (UNLIKELY(ropeBuilder.isOutOfMemory())) return throwOutOfMemoryError(exec); - rope->append(index, s1); - rope->append(index, s2); - ASSERT(index == ropeLength); - return new (globalData) JSString(globalData, rope.release()); + ropeBuilder.append(s1); + ropeBuilder.append(s2); + return new (globalData) JSString(globalData, ropeBuilder.release()); } ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, JSString* s2) { - unsigned ropeLength = 1 + s2->ropeLength(); + unsigned length1 = u1.size(); + if (!length1) + return s2; + unsigned length2 = s2->length(); + if (!length2) + return jsString(exec, u1); + if ((length1 + length2) < length1) + return throwOutOfMemoryError(exec); + + unsigned fiberCount = 1 + s2->fiberCount(); JSGlobalData* globalData = &exec->globalData(); - if (ropeLength <= JSString::s_maxInternalRopeLength) - return new (globalData) JSString(globalData, ropeLength, u1, s2); + if (fiberCount <= JSString::s_maxInternalRopeLength) + return new (globalData) JSString(globalData, fiberCount, u1, s2); - unsigned index = 0; - RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); - if (UNLIKELY(!rope)) + JSString::RopeBuilder ropeBuilder(fiberCount); + if (UNLIKELY(ropeBuilder.isOutOfMemory())) return throwOutOfMemoryError(exec); - rope->append(index, u1); - rope->append(index, s2); - ASSERT(index == ropeLength); - return new (globalData) JSString(globalData, rope.release()); + ropeBuilder.append(u1); + ropeBuilder.append(s2); + return new (globalData) JSString(globalData, ropeBuilder.release()); } ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, const UString& u2) { - unsigned ropeLength = s1->ropeLength() + 1; + unsigned length1 = s1->length(); + if (!length1) + return jsString(exec, u2); + unsigned length2 = u2.size(); + if (!length2) + return s1; + if ((length1 + length2) < length1) + return throwOutOfMemoryError(exec); + + unsigned fiberCount = s1->fiberCount() + 1; JSGlobalData* globalData = &exec->globalData(); - if (ropeLength <= JSString::s_maxInternalRopeLength) - return new (globalData) JSString(globalData, ropeLength, s1, u2); + if (fiberCount <= JSString::s_maxInternalRopeLength) + return new (globalData) JSString(globalData, fiberCount, s1, u2); - unsigned index = 0; - RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); - if (UNLIKELY(!rope)) + JSString::RopeBuilder ropeBuilder(fiberCount); + if (UNLIKELY(ropeBuilder.isOutOfMemory())) return throwOutOfMemoryError(exec); - rope->append(index, s1); - rope->append(index, u2); - ASSERT(index == ropeLength); - return new (globalData) JSString(globalData, rope.release()); + ropeBuilder.append(s1); + ropeBuilder.append(u2); + return new (globalData) JSString(globalData, ropeBuilder.release()); } ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count) { ASSERT(count >= 3); - unsigned ropeLength = 0; + unsigned fiberCount = 0; for (unsigned i = 0; i < count; ++i) { JSValue v = strings[i].jsValue(); if (LIKELY(v.isString())) - ropeLength += asString(v)->ropeLength(); + fiberCount += asString(v)->fiberCount(); else - ++ropeLength; + ++fiberCount; } JSGlobalData* globalData = &exec->globalData(); - if (ropeLength == 3) + if (fiberCount == 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)) + JSString::RopeBuilder ropeBuilder(fiberCount); + if (UNLIKELY(ropeBuilder.isOutOfMemory())) return throwOutOfMemoryError(exec); - unsigned index = 0; + unsigned length = 0; + bool overflow = false; + for (unsigned i = 0; i < count; ++i) { JSValue v = strings[i].jsValue(); if (LIKELY(v.isString())) - rope->append(index, asString(v)); + ropeBuilder.append(asString(v)); else - rope->append(index, v.toString(exec)); + ropeBuilder.append(v.toString(exec)); + + unsigned newLength = ropeBuilder.length(); + if (newLength < length) + overflow = true; + length = newLength; } - ASSERT(index == ropeLength); - return new (globalData) JSString(globalData, rope.release()); + if (overflow) + return throwOutOfMemoryError(exec); + + return new (globalData) JSString(globalData, ropeBuilder.release()); } ALWAYS_INLINE JSValue jsString(ExecState* exec, JSValue thisValue, const ArgList& args) { - unsigned ropeLength = 0; + unsigned fiberCount = 0; if (LIKELY(thisValue.isString())) - ropeLength += asString(thisValue)->ropeLength(); + fiberCount += asString(thisValue)->fiberCount(); else - ++ropeLength; + ++fiberCount; for (unsigned i = 0; i < args.size(); ++i) { JSValue v = args.at(i); if (LIKELY(v.isString())) - ropeLength += asString(v)->ropeLength(); + fiberCount += asString(v)->fiberCount(); else - ++ropeLength; + ++fiberCount; } - RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); - if (UNLIKELY(!rope)) + JSString::RopeBuilder ropeBuilder(fiberCount); + if (UNLIKELY(ropeBuilder.isOutOfMemory())) return throwOutOfMemoryError(exec); - unsigned index = 0; if (LIKELY(thisValue.isString())) - rope->append(index, asString(thisValue)); + ropeBuilder.append(asString(thisValue)); else - rope->append(index, thisValue.toString(exec)); + ropeBuilder.append(thisValue.toString(exec)); + + unsigned length = 0; + bool overflow = false; + for (unsigned i = 0; i < args.size(); ++i) { JSValue v = args.at(i); if (LIKELY(v.isString())) - rope->append(index, asString(v)); + ropeBuilder.append(asString(v)); else - rope->append(index, v.toString(exec)); + ropeBuilder.append(v.toString(exec)); + + unsigned newLength = ropeBuilder.length(); + if (newLength < length) + overflow = true; + length = newLength; } - ASSERT(index == ropeLength); + + if (overflow) + return throwOutOfMemoryError(exec); JSGlobalData* globalData = &exec->globalData(); - return new (globalData) JSString(globalData, rope.release()); + return new (globalData) JSString(globalData, ropeBuilder.release()); } // ECMA 11.9.3 diff --git a/JavaScriptCore/runtime/PropertyNameArray.cpp b/JavaScriptCore/runtime/PropertyNameArray.cpp index 4937b7c..6b24669 100644 --- a/JavaScriptCore/runtime/PropertyNameArray.cpp +++ b/JavaScriptCore/runtime/PropertyNameArray.cpp @@ -30,7 +30,7 @@ static const size_t setThreshold = 20; void PropertyNameArray::add(UString::Rep* identifier) { - ASSERT(identifier == &UString::Rep::empty() || identifier->isIdentifier()); + ASSERT(identifier == UString::null().rep() || identifier == UString::Rep::empty() || identifier->isIdentifier()); size_t size = m_data->propertyNameVector().size(); if (size < setThreshold) { diff --git a/JavaScriptCore/runtime/PropertySlot.cpp b/JavaScriptCore/runtime/PropertySlot.cpp index a0a2f48..2306a11 100644 --- a/JavaScriptCore/runtime/PropertySlot.cpp +++ b/JavaScriptCore/runtime/PropertySlot.cpp @@ -26,19 +26,19 @@ namespace JSC { -JSValue PropertySlot::functionGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue PropertySlot::functionGetter(ExecState* exec) const { // Prevent getter functions from observing execution if an exception is pending. if (exec->hadException()) return exec->exception(); CallData callData; - CallType callType = slot.m_data.getterFunc->getCallData(callData); + CallType callType = m_data.getterFunc->getCallData(callData); if (callType == CallTypeHost) - return callData.native.function(exec, slot.m_data.getterFunc, slot.slotBase(), exec->emptyList()); + return callData.native.function(exec, m_data.getterFunc, thisValue(), exec->emptyList()); ASSERT(callType == CallTypeJS); // FIXME: Can this be done more efficiently using the callData? - return asFunction(slot.m_data.getterFunc)->call(exec, slot.slotBase(), exec->emptyList()); + return asFunction(m_data.getterFunc)->call(exec, thisValue(), exec->emptyList()); } } // namespace JSC diff --git a/JavaScriptCore/runtime/PropertySlot.h b/JavaScriptCore/runtime/PropertySlot.h index 15d9034..de9ddc9 100644 --- a/JavaScriptCore/runtime/PropertySlot.h +++ b/JavaScriptCore/runtime/PropertySlot.h @@ -34,10 +34,20 @@ namespace JSC { #define JSC_VALUE_SLOT_MARKER 0 #define JSC_REGISTER_SLOT_MARKER reinterpret_cast<GetValueFunc>(1) +#define INDEX_GETTER_MARKER reinterpret_cast<GetValueFunc>(2) +#define GETTER_FUNCTION_MARKER reinterpret_cast<GetValueFunc>(3) class PropertySlot { public: + enum CachedPropertyType { + Uncacheable, + Getter, + Custom, + Value + }; + PropertySlot() + : m_cachedPropertyType(Uncacheable) { clearBase(); clearOffset(); @@ -46,12 +56,14 @@ namespace JSC { explicit PropertySlot(const JSValue base) : m_slotBase(base) + , m_cachedPropertyType(Uncacheable) { clearOffset(); clearValue(); } - typedef JSValue (*GetValueFunc)(ExecState*, const Identifier&, const PropertySlot&); + typedef JSValue (*GetValueFunc)(ExecState*, JSValue slotBase, const Identifier&); + typedef JSValue (*GetIndexValueFunc)(ExecState*, JSValue slotBase, unsigned); JSValue getValue(ExecState* exec, const Identifier& propertyName) const { @@ -59,7 +71,11 @@ namespace JSC { return *m_data.valueSlot; if (m_getValue == JSC_REGISTER_SLOT_MARKER) return (*m_data.registerSlot).jsValue(); - return m_getValue(exec, propertyName, *this); + if (m_getValue == INDEX_GETTER_MARKER) + return m_getIndexValue(exec, slotBase(), index()); + if (m_getValue == GETTER_FUNCTION_MARKER) + return functionGetter(exec); + return m_getValue(exec, slotBase(), propertyName); } JSValue getValue(ExecState* exec, unsigned propertyName) const @@ -68,10 +84,16 @@ namespace JSC { return *m_data.valueSlot; if (m_getValue == JSC_REGISTER_SLOT_MARKER) return (*m_data.registerSlot).jsValue(); - return m_getValue(exec, Identifier::from(exec, propertyName), *this); + if (m_getValue == INDEX_GETTER_MARKER) + return m_getIndexValue(exec, m_slotBase, m_data.index); + if (m_getValue == GETTER_FUNCTION_MARKER) + return functionGetter(exec); + return m_getValue(exec, slotBase(), Identifier::from(exec, propertyName)); } - bool isCacheable() const { return m_offset != WTF::notFound; } + CachedPropertyType cachedPropertyType() const { return m_cachedPropertyType; } + bool isCacheable() const { return m_cachedPropertyType != Uncacheable; } + bool isCacheableValue() const { return m_cachedPropertyType == Value; } size_t cachedOffset() const { ASSERT(isCacheable()); @@ -102,6 +124,7 @@ namespace JSC { m_slotBase = slotBase; m_data.valueSlot = valueSlot; m_offset = offset; + m_cachedPropertyType = Value; } void setValue(JSValue value) @@ -128,25 +151,49 @@ namespace JSC { ASSERT(slotBase); ASSERT(getValue); m_getValue = getValue; + m_getIndexValue = 0; m_slotBase = slotBase; } - - void setCustomIndex(JSValue slotBase, unsigned index, GetValueFunc getValue) + + void setCacheableCustom(JSValue slotBase, GetValueFunc getValue) { ASSERT(slotBase); ASSERT(getValue); m_getValue = getValue; + m_getIndexValue = 0; + m_slotBase = slotBase; + m_cachedPropertyType = Custom; + } + + void setCustomIndex(JSValue slotBase, unsigned index, GetIndexValueFunc getIndexValue) + { + ASSERT(slotBase); + ASSERT(getIndexValue); + m_getValue = INDEX_GETTER_MARKER; + m_getIndexValue = getIndexValue; m_slotBase = slotBase; m_data.index = index; } - + void setGetterSlot(JSObject* getterFunc) { ASSERT(getterFunc); - m_getValue = functionGetter; + m_thisValue = m_slotBase; + m_getValue = GETTER_FUNCTION_MARKER; m_data.getterFunc = getterFunc; } - + + void setCacheableGetterSlot(JSValue slotBase, JSObject* getterFunc, unsigned offset) + { + ASSERT(getterFunc); + m_getValue = GETTER_FUNCTION_MARKER; + m_thisValue = m_slotBase; + m_slotBase = slotBase; + m_data.getterFunc = getterFunc; + m_offset = offset; + m_cachedPropertyType = Getter; + } + void setUndefined() { setValue(jsUndefined()); @@ -182,15 +229,24 @@ namespace JSC { { // Clear offset even in release builds, in case this PropertySlot has been used before. // (For other data members, we don't need to clear anything because reuse would meaningfully overwrite them.) - m_offset = WTF::notFound; + m_offset = 0; + m_cachedPropertyType = Uncacheable; } unsigned index() const { return m_data.index; } + JSValue thisValue() const { return m_thisValue; } + + GetValueFunc customGetter() const + { + ASSERT(m_cachedPropertyType == Custom); + return m_getValue; + } private: - static JSValue functionGetter(ExecState*, const Identifier&, const PropertySlot&); + JSValue functionGetter(ExecState*) const; GetValueFunc m_getValue; + GetIndexValueFunc m_getIndexValue; JSValue m_slotBase; union { @@ -201,8 +257,10 @@ namespace JSC { } m_data; JSValue m_value; + JSValue m_thisValue; size_t m_offset; + CachedPropertyType m_cachedPropertyType; }; } // namespace JSC diff --git a/JavaScriptCore/runtime/RegExp.cpp b/JavaScriptCore/runtime/RegExp.cpp index 4e958f4..f097943 100644 --- a/JavaScriptCore/runtime/RegExp.cpp +++ b/JavaScriptCore/runtime/RegExp.cpp @@ -40,20 +40,12 @@ #else -#if ENABLE(WREC) -#include "JIT.h" -#include "WRECGenerator.h" -#endif #include <pcre/pcre.h> #endif namespace JSC { -#if ENABLE(WREC) -using namespace WREC; -#endif - inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern) : m_pattern(pattern) , m_flagBits(0) @@ -71,11 +63,11 @@ inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern, const US { // NOTE: The global flag is handled on a case-by-case basis by functions like // String::match and RegExpObject::match. - if (flags.find('g') != -1) + if (flags.find('g') != UString::NotFound) m_flagBits |= Global; - if (flags.find('i') != -1) + if (flags.find('i') != UString::NotFound) m_flagBits |= IgnoreCase; - if (flags.find('m') != -1) + if (flags.find('m') != UString::NotFound) m_flagBits |= Multiline; compile(globalData); @@ -117,7 +109,7 @@ int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector) if (ovector) ovector->clear(); - if (startOffset > s.size() || s.isNull()) + if (static_cast<unsigned>(startOffset) > s.size() || s.isNull()) return -1; #if ENABLE(YARR_JIT) @@ -164,18 +156,9 @@ int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector) #else -void RegExp::compile(JSGlobalData* globalData) +void RegExp::compile(JSGlobalData*) { m_regExp = 0; -#if ENABLE(WREC) - m_wrecFunction = Generator::compileRegExp(globalData, m_pattern, &m_numSubpatterns, &m_constructionError, m_executablePool, ignoreCase(), multiline()); - if (m_wrecFunction || m_constructionError) - return; - // Fall through to non-WREC case. -#else - UNUSED_PARAM(globalData); -#endif - JSRegExpIgnoreCaseOption ignoreCaseOption = ignoreCase() ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase; JSRegExpMultilineOption multilineOption = multiline() ? JSRegExpMultiline : JSRegExpSingleLine; m_regExp = jsRegExpCompile(reinterpret_cast<const UChar*>(m_pattern.data()), m_pattern.size(), ignoreCaseOption, multilineOption, &m_numSubpatterns, &m_constructionError); @@ -188,39 +171,9 @@ int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector) if (ovector) ovector->clear(); - if (startOffset > s.size() || s.isNull()) + if (static_cast<unsigned>(startOffset) > s.size() || s.isNull()) return -1; -#if ENABLE(WREC) - if (m_wrecFunction) { - int offsetVectorSize = (m_numSubpatterns + 1) * 2; - int* offsetVector; - Vector<int, 32> nonReturnedOvector; - if (ovector) { - ovector->resize(offsetVectorSize); - offsetVector = ovector->data(); - } else { - nonReturnedOvector.resize(offsetVectorSize); - offsetVector = nonReturnedOvector.data(); - } - ASSERT(offsetVector); - for (int j = 0; j < offsetVectorSize; ++j) - offsetVector[j] = -1; - - int result = m_wrecFunction(s.data(), startOffset, s.size(), offsetVector); - - if (result < 0) { -#ifndef NDEBUG - // TODO: define up a symbol, rather than magic -1 - if (result != -1) - fprintf(stderr, "jsRegExpExecute failed with result %d\n", result); -#endif - if (ovector) - ovector->clear(); - } - return result; - } else -#endif if (m_regExp) { // Set up the offset vector for the result. // First 2/3 used for result, the last third used by PCRE. diff --git a/JavaScriptCore/runtime/RegExp.h b/JavaScriptCore/runtime/RegExp.h index 61ab0bc..695b688 100644 --- a/JavaScriptCore/runtime/RegExp.h +++ b/JavaScriptCore/runtime/RegExp.h @@ -23,7 +23,6 @@ #define RegExp_h #include "UString.h" -#include "WREC.h" #include "ExecutableAllocator.h" #include <wtf/Forward.h> #include <wtf/RefCounted.h> @@ -74,10 +73,6 @@ namespace JSC { #elif ENABLE(YARR) OwnPtr<Yarr::BytecodePattern> m_regExpBytecode; #else -#if ENABLE(WREC) - WREC::CompiledRegExp m_wrecFunction; - RefPtr<ExecutablePool> m_executablePool; -#endif JSRegExp* m_regExp; #endif }; diff --git a/JavaScriptCore/runtime/RegExpConstructor.cpp b/JavaScriptCore/runtime/RegExpConstructor.cpp index 6f00142..3a67ae6 100644 --- a/JavaScriptCore/runtime/RegExpConstructor.cpp +++ b/JavaScriptCore/runtime/RegExpConstructor.cpp @@ -27,6 +27,7 @@ #include "JSArray.h" #include "JSFunction.h" #include "JSString.h" +#include "Lookup.h" #include "ObjectPrototype.h" #include "RegExpMatchesArray.h" #include "RegExpObject.h" @@ -35,21 +36,21 @@ namespace JSC { -static JSValue regExpConstructorInput(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpConstructorMultiline(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpConstructorLastMatch(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpConstructorLastParen(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpConstructorLeftContext(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpConstructorRightContext(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpConstructorDollar1(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpConstructorDollar2(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpConstructorDollar3(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpConstructorDollar4(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpConstructorDollar5(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpConstructorDollar6(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpConstructorDollar7(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpConstructorDollar8(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpConstructorDollar9(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpConstructorInput(ExecState*, JSValue, const Identifier&); +static JSValue regExpConstructorMultiline(ExecState*, JSValue, const Identifier&); +static JSValue regExpConstructorLastMatch(ExecState*, JSValue, const Identifier&); +static JSValue regExpConstructorLastParen(ExecState*, JSValue, const Identifier&); +static JSValue regExpConstructorLeftContext(ExecState*, JSValue, const Identifier&); +static JSValue regExpConstructorRightContext(ExecState*, JSValue, const Identifier&); +static JSValue regExpConstructorDollar1(ExecState*, JSValue, const Identifier&); +static JSValue regExpConstructorDollar2(ExecState*, JSValue, const Identifier&); +static JSValue regExpConstructorDollar3(ExecState*, JSValue, const Identifier&); +static JSValue regExpConstructorDollar4(ExecState*, JSValue, const Identifier&); +static JSValue regExpConstructorDollar5(ExecState*, JSValue, const Identifier&); +static JSValue regExpConstructorDollar6(ExecState*, JSValue, const Identifier&); +static JSValue regExpConstructorDollar7(ExecState*, JSValue, const Identifier&); +static JSValue regExpConstructorDollar8(ExecState*, JSValue, const Identifier&); +static JSValue regExpConstructorDollar9(ExecState*, JSValue, const Identifier&); static void setRegExpConstructorInput(ExecState*, JSObject*, JSValue); static void setRegExpConstructorMultiline(ExecState*, JSObject*, JSValue); @@ -113,17 +114,17 @@ RegExpMatchesArray::RegExpMatchesArray(ExecState* exec, RegExpConstructorPrivate memcpy(d->lastOvector().data(), data->lastOvector().data(), offsetVectorSize * sizeof(int)); // d->multiline is not needed, and remains uninitialized - setLazyCreationData(d); + setSubclassData(d); } RegExpMatchesArray::~RegExpMatchesArray() { - delete static_cast<RegExpConstructorPrivate*>(lazyCreationData()); + delete static_cast<RegExpConstructorPrivate*>(subclassData()); } void RegExpMatchesArray::fillArrayInstance(ExecState* exec) { - RegExpConstructorPrivate* d = static_cast<RegExpConstructorPrivate*>(lazyCreationData()); + RegExpConstructorPrivate* d = static_cast<RegExpConstructorPrivate*>(subclassData()); ASSERT(d); unsigned lastNumSubpatterns = d->lastNumSubPatterns; @@ -141,7 +142,7 @@ void RegExpMatchesArray::fillArrayInstance(ExecState* exec) JSArray::put(exec, exec->propertyNames().input, jsString(exec, d->input), slot); delete d; - setLazyCreationData(0); + setSubclassData(0); } JSObject* RegExpConstructor::arrayOfMatches(ExecState* exec) const @@ -195,79 +196,79 @@ bool RegExpConstructor::getOwnPropertyDescriptor(ExecState* exec, const Identifi return getStaticValueDescriptor<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), this, propertyName, descriptor); } -JSValue regExpConstructorDollar1(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue regExpConstructorDollar1(ExecState* exec, JSValue slotBase, const Identifier&) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 1); + return asRegExpConstructor(slotBase)->getBackref(exec, 1); } -JSValue regExpConstructorDollar2(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue regExpConstructorDollar2(ExecState* exec, JSValue slotBase, const Identifier&) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 2); + return asRegExpConstructor(slotBase)->getBackref(exec, 2); } -JSValue regExpConstructorDollar3(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue regExpConstructorDollar3(ExecState* exec, JSValue slotBase, const Identifier&) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 3); + return asRegExpConstructor(slotBase)->getBackref(exec, 3); } -JSValue regExpConstructorDollar4(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue regExpConstructorDollar4(ExecState* exec, JSValue slotBase, const Identifier&) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 4); + return asRegExpConstructor(slotBase)->getBackref(exec, 4); } -JSValue regExpConstructorDollar5(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue regExpConstructorDollar5(ExecState* exec, JSValue slotBase, const Identifier&) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 5); + return asRegExpConstructor(slotBase)->getBackref(exec, 5); } -JSValue regExpConstructorDollar6(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue regExpConstructorDollar6(ExecState* exec, JSValue slotBase, const Identifier&) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 6); + return asRegExpConstructor(slotBase)->getBackref(exec, 6); } -JSValue regExpConstructorDollar7(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue regExpConstructorDollar7(ExecState* exec, JSValue slotBase, const Identifier&) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 7); + return asRegExpConstructor(slotBase)->getBackref(exec, 7); } -JSValue regExpConstructorDollar8(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue regExpConstructorDollar8(ExecState* exec, JSValue slotBase, const Identifier&) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 8); + return asRegExpConstructor(slotBase)->getBackref(exec, 8); } -JSValue regExpConstructorDollar9(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue regExpConstructorDollar9(ExecState* exec, JSValue slotBase, const Identifier&) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 9); + return asRegExpConstructor(slotBase)->getBackref(exec, 9); } -JSValue regExpConstructorInput(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue regExpConstructorInput(ExecState* exec, JSValue slotBase, const Identifier&) { - return jsString(exec, asRegExpConstructor(slot.slotBase())->input()); + return jsString(exec, asRegExpConstructor(slotBase)->input()); } -JSValue regExpConstructorMultiline(ExecState*, const Identifier&, const PropertySlot& slot) +JSValue regExpConstructorMultiline(ExecState*, JSValue slotBase, const Identifier&) { - return jsBoolean(asRegExpConstructor(slot.slotBase())->multiline()); + return jsBoolean(asRegExpConstructor(slotBase)->multiline()); } -JSValue regExpConstructorLastMatch(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue regExpConstructorLastMatch(ExecState* exec, JSValue slotBase, const Identifier&) { - return asRegExpConstructor(slot.slotBase())->getBackref(exec, 0); + return asRegExpConstructor(slotBase)->getBackref(exec, 0); } -JSValue regExpConstructorLastParen(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue regExpConstructorLastParen(ExecState* exec, JSValue slotBase, const Identifier&) { - return asRegExpConstructor(slot.slotBase())->getLastParen(exec); + return asRegExpConstructor(slotBase)->getLastParen(exec); } -JSValue regExpConstructorLeftContext(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue regExpConstructorLeftContext(ExecState* exec, JSValue slotBase, const Identifier&) { - return asRegExpConstructor(slot.slotBase())->getLeftContext(exec); + return asRegExpConstructor(slotBase)->getLeftContext(exec); } -JSValue regExpConstructorRightContext(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue regExpConstructorRightContext(ExecState* exec, JSValue slotBase, const Identifier&) { - return asRegExpConstructor(slot.slotBase())->getRightContext(exec); + return asRegExpConstructor(slotBase)->getRightContext(exec); } void RegExpConstructor::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) diff --git a/JavaScriptCore/runtime/RegExpMatchesArray.h b/JavaScriptCore/runtime/RegExpMatchesArray.h index 38d3cb4..b823621 100644 --- a/JavaScriptCore/runtime/RegExpMatchesArray.h +++ b/JavaScriptCore/runtime/RegExpMatchesArray.h @@ -32,56 +32,56 @@ namespace JSC { private: virtual bool getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { - if (lazyCreationData()) + if (subclassData()) fillArrayInstance(exec); return JSArray::getOwnPropertySlot(exec, propertyName, slot); } virtual bool getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) { - if (lazyCreationData()) + if (subclassData()) fillArrayInstance(exec); return JSArray::getOwnPropertySlot(exec, propertyName, slot); } virtual bool getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) { - if (lazyCreationData()) + if (subclassData()) fillArrayInstance(exec); return JSArray::getOwnPropertyDescriptor(exec, propertyName, descriptor); } virtual void put(ExecState* exec, const Identifier& propertyName, JSValue v, PutPropertySlot& slot) { - if (lazyCreationData()) + if (subclassData()) fillArrayInstance(exec); JSArray::put(exec, propertyName, v, slot); } virtual void put(ExecState* exec, unsigned propertyName, JSValue v) { - if (lazyCreationData()) + if (subclassData()) fillArrayInstance(exec); JSArray::put(exec, propertyName, v); } virtual bool deleteProperty(ExecState* exec, const Identifier& propertyName) { - if (lazyCreationData()) + if (subclassData()) fillArrayInstance(exec); return JSArray::deleteProperty(exec, propertyName); } virtual bool deleteProperty(ExecState* exec, unsigned propertyName) { - if (lazyCreationData()) + if (subclassData()) fillArrayInstance(exec); return JSArray::deleteProperty(exec, propertyName); } virtual void getOwnPropertyNames(ExecState* exec, PropertyNameArray& arr, EnumerationMode mode = ExcludeDontEnumProperties) { - if (lazyCreationData()) + if (subclassData()) fillArrayInstance(exec); JSArray::getOwnPropertyNames(exec, arr, mode); } diff --git a/JavaScriptCore/runtime/RegExpObject.cpp b/JavaScriptCore/runtime/RegExpObject.cpp index 42bfcef..bc74924 100644 --- a/JavaScriptCore/runtime/RegExpObject.cpp +++ b/JavaScriptCore/runtime/RegExpObject.cpp @@ -25,16 +25,17 @@ #include "JSArray.h" #include "JSGlobalObject.h" #include "JSString.h" +#include "Lookup.h" #include "RegExpConstructor.h" #include "RegExpPrototype.h" namespace JSC { -static JSValue regExpObjectGlobal(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpObjectIgnoreCase(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpObjectMultiline(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpObjectSource(ExecState*, const Identifier&, const PropertySlot&); -static JSValue regExpObjectLastIndex(ExecState*, const Identifier&, const PropertySlot&); +static JSValue regExpObjectGlobal(ExecState*, JSValue, const Identifier&); +static JSValue regExpObjectIgnoreCase(ExecState*, JSValue, const Identifier&); +static JSValue regExpObjectMultiline(ExecState*, JSValue, const Identifier&); +static JSValue regExpObjectSource(ExecState*, JSValue, const Identifier&); +static JSValue regExpObjectLastIndex(ExecState*, JSValue, const Identifier&); static void setRegExpObjectLastIndex(ExecState*, JSObject*, JSValue); } // namespace JSC @@ -77,29 +78,29 @@ bool RegExpObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& p return getStaticValueDescriptor<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), this, propertyName, descriptor); } -JSValue regExpObjectGlobal(ExecState*, const Identifier&, const PropertySlot& slot) +JSValue regExpObjectGlobal(ExecState*, JSValue slotBase, const Identifier&) { - return jsBoolean(asRegExpObject(slot.slotBase())->regExp()->global()); + return jsBoolean(asRegExpObject(slotBase)->regExp()->global()); } -JSValue regExpObjectIgnoreCase(ExecState*, const Identifier&, const PropertySlot& slot) +JSValue regExpObjectIgnoreCase(ExecState*, JSValue slotBase, const Identifier&) { - return jsBoolean(asRegExpObject(slot.slotBase())->regExp()->ignoreCase()); + return jsBoolean(asRegExpObject(slotBase)->regExp()->ignoreCase()); } -JSValue regExpObjectMultiline(ExecState*, const Identifier&, const PropertySlot& slot) +JSValue regExpObjectMultiline(ExecState*, JSValue slotBase, const Identifier&) { - return jsBoolean(asRegExpObject(slot.slotBase())->regExp()->multiline()); + return jsBoolean(asRegExpObject(slotBase)->regExp()->multiline()); } -JSValue regExpObjectSource(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, const Identifier&) { - return jsString(exec, asRegExpObject(slot.slotBase())->regExp()->pattern()); + return jsString(exec, asRegExpObject(slotBase)->regExp()->pattern()); } -JSValue regExpObjectLastIndex(ExecState* exec, const Identifier&, const PropertySlot& slot) +JSValue regExpObjectLastIndex(ExecState* exec, JSValue slotBase, const Identifier&) { - return jsNumber(exec, asRegExpObject(slot.slotBase())->lastIndex()); + return jsNumber(exec, asRegExpObject(slotBase)->lastIndex()); } void RegExpObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) diff --git a/JavaScriptCore/runtime/RopeImpl.cpp b/JavaScriptCore/runtime/RopeImpl.cpp new file mode 100644 index 0000000..a3760e6 --- /dev/null +++ b/JavaScriptCore/runtime/RopeImpl.cpp @@ -0,0 +1,62 @@ +/* + * 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 "RopeImpl.h" + +namespace JSC { + +void RopeImpl::derefFibersNonRecursive(Vector<RopeImpl*, 32>& workQueue) +{ + unsigned length = fiberCount(); + for (unsigned i = 0; i < length; ++i) { + Fiber& fiber = fibers(i); + if (isRope(fiber)) { + RopeImpl* nextRope = static_cast<RopeImpl*>(fiber); + if (nextRope->hasOneRef()) + workQueue.append(nextRope); + else + nextRope->deref(); + } else + static_cast<UStringImpl*>(fiber)->deref(); + } +} + +void RopeImpl::destructNonRecursive() +{ + Vector<RopeImpl*, 32> workQueue; + + derefFibersNonRecursive(workQueue); + delete this; + + while (!workQueue.isEmpty()) { + RopeImpl* rope = workQueue.last(); + workQueue.removeLast(); + rope->derefFibersNonRecursive(workQueue); + delete rope; + } +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/RopeImpl.h b/JavaScriptCore/runtime/RopeImpl.h new file mode 100644 index 0000000..6fbc595 --- /dev/null +++ b/JavaScriptCore/runtime/RopeImpl.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2009, 2010 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 RopeImpl_h +#define RopeImpl_h + +#include "UStringImpl.h" + +namespace JSC { + +class RopeImpl : public StringImplBase { +public: + // A RopeImpl is composed from a set of smaller strings called Fibers. + // Each Fiber in a rope is either UStringImpl or another RopeImpl. + typedef StringImplBase* Fiber; + + // Creates a RopeImpl comprising of 'fiberCount' Fibers. + // The RopeImpl is constructed in an uninitialized state - initialize must be called for each Fiber in the RopeImpl. + static PassRefPtr<RopeImpl> tryCreateUninitialized(unsigned fiberCount) + { + void* allocation; + if (tryFastMalloc(sizeof(RopeImpl) + (fiberCount - 1) * sizeof(Fiber)).getValue(allocation)) + return adoptRef(new (allocation) RopeImpl(fiberCount)); + return 0; + } + + void initializeFiber(unsigned &index, Fiber fiber) + { + m_fibers[index++] = fiber; + fiber->ref(); + m_length += fiber->length(); + } + + unsigned fiberCount() { return m_fiberCount; } + Fiber& fibers(unsigned index) { return m_fibers[index]; } + + ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & s_refCountMask)) destructNonRecursive(); } + + static bool isRope(Fiber fiber) + { + return !fiber->isStringImpl(); + } + + static void deref(Fiber fiber) + { + if (isRope(fiber)) + static_cast<RopeImpl*>(fiber)->deref(); + else + static_cast<UStringImpl*>(fiber)->deref(); + } + +private: + RopeImpl(unsigned fiberCount) : StringImplBase(ConstructNonStringImpl), m_fiberCount(fiberCount) {} + + void destructNonRecursive(); + void derefFibersNonRecursive(Vector<RopeImpl*, 32>& workQueue); + + bool hasOneRef() { return (m_refCountAndFlags & s_refCountMask) == s_refCountIncrement; } + + unsigned m_fiberCount; + Fiber m_fibers[1]; +}; + +} + +#endif diff --git a/JavaScriptCore/runtime/SmallStrings.cpp b/JavaScriptCore/runtime/SmallStrings.cpp index d9d4377..0f5df4a 100644 --- a/JavaScriptCore/runtime/SmallStrings.cpp +++ b/JavaScriptCore/runtime/SmallStrings.cpp @@ -43,10 +43,10 @@ class SmallStringsStorage : public Noncopyable { public: SmallStringsStorage(); - UString::Rep* rep(unsigned char character) { return &m_reps[character]; } + UString::Rep* rep(unsigned char character) { return m_reps[character].get(); } private: - UString::Rep m_reps[numCharactersToStore]; + RefPtr<UString::Rep> m_reps[numCharactersToStore]; }; SmallStringsStorage::SmallStringsStorage() @@ -55,7 +55,7 @@ SmallStringsStorage::SmallStringsStorage() RefPtr<UStringImpl> baseString = UStringImpl::createUninitialized(numCharactersToStore, characterBuffer); for (unsigned i = 0; i < numCharactersToStore; ++i) { characterBuffer[i] = i; - new (&m_reps[i]) UString::Rep(&characterBuffer[i], 1, PassRefPtr<UStringImpl>(baseString)); + m_reps[i] = UStringImpl::create(baseString, i, 1); } } @@ -83,7 +83,7 @@ void SmallStrings::markChildren(MarkStack& markStack) bool isAnyStringMarked = isMarked(m_emptyString); for (unsigned i = 0; i < numCharactersToStore && !isAnyStringMarked; ++i) - isAnyStringMarked |= isMarked(m_singleCharacterStrings[i]); + isAnyStringMarked = isMarked(m_singleCharacterStrings[i]); if (!isAnyStringMarked) { clear(); diff --git a/JavaScriptCore/runtime/SmallStrings.h b/JavaScriptCore/runtime/SmallStrings.h index cc11d0a..bc337c9 100644 --- a/JavaScriptCore/runtime/SmallStrings.h +++ b/JavaScriptCore/runtime/SmallStrings.h @@ -60,7 +60,9 @@ namespace JSC { void clear(); unsigned count() const; - +#if ENABLE(JIT) + JSString** singleCharacterStrings() { return m_singleCharacterStrings; } +#endif private: void createEmptyString(JSGlobalData*); void createSingleCharacterString(JSGlobalData*, unsigned char); diff --git a/JavaScriptCore/runtime/StringBuilder.h b/JavaScriptCore/runtime/StringBuilder.h index 27dbbd7..59b01e0 100644 --- a/JavaScriptCore/runtime/StringBuilder.h +++ b/JavaScriptCore/runtime/StringBuilder.h @@ -69,8 +69,7 @@ public: UString build() { buffer.shrinkToFit(); - if (buffer.size() && !buffer.data()) - CRASH(); + ASSERT(buffer.data() || !buffer.size()); return UString::adopt(buffer); } diff --git a/JavaScriptCore/runtime/StringConstructor.cpp b/JavaScriptCore/runtime/StringConstructor.cpp index c7b62bf..42f98c3 100644 --- a/JavaScriptCore/runtime/StringConstructor.cpp +++ b/JavaScriptCore/runtime/StringConstructor.cpp @@ -54,8 +54,11 @@ StringConstructor::StringConstructor(ExecState* exec, NonNullPassRefPtr<Structur putDirectWithoutTransition(exec->propertyNames().prototype, stringPrototype, ReadOnly | DontEnum | DontDelete); // ECMA 15.5.3.2 fromCharCode() +#if ENABLE(JIT) + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().fromCharCode, exec->globalData().getThunk(fromCharCodeThunkGenerator), stringFromCharCode), DontEnum); +#else putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().fromCharCode, stringFromCharCode), DontEnum); - +#endif // no. of arguments for constructor putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontEnum | DontDelete); } diff --git a/JavaScriptCore/runtime/StringPrototype.cpp b/JavaScriptCore/runtime/StringPrototype.cpp index 8c014ec..345378e 100644 --- a/JavaScriptCore/runtime/StringPrototype.cpp +++ b/JavaScriptCore/runtime/StringPrototype.cpp @@ -29,6 +29,7 @@ #include "JSArray.h" #include "JSFunction.h" #include "JSStringBuilder.h" +#include "Lookup.h" #include "ObjectPrototype.h" #include "Operations.h" #include "PropertyNameArray.h" @@ -150,7 +151,7 @@ bool StringPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier // ------------------------------ Functions -------------------------- -static NEVER_INLINE UString substituteBackreferencesSlow(const UString& replacement, const UString& source, const int* ovector, RegExp* reg, int i) +static NEVER_INLINE UString substituteBackreferencesSlow(const UString& replacement, const UString& source, const int* ovector, RegExp* reg, unsigned i) { Vector<UChar> substitutedReplacement; int offset = 0; @@ -206,7 +207,7 @@ static NEVER_INLINE UString substituteBackreferencesSlow(const UString& replacem i += 1 + advance; offset = i + 1; substitutedReplacement.append(source.data() + backrefStart, backrefLength); - } while ((i = replacement.find('$', i + 1)) != -1); + } while ((i = replacement.find('$', i + 1)) != UString::NotFound); if (replacement.size() - offset) substitutedReplacement.append(replacement.data() + offset, replacement.size() - offset); @@ -217,8 +218,8 @@ static NEVER_INLINE UString substituteBackreferencesSlow(const UString& replacem static inline UString substituteBackreferences(const UString& replacement, const UString& source, const int* ovector, RegExp* reg) { - int i = replacement.find('$', 0); - if (UNLIKELY(i != -1)) + unsigned i = replacement.find('$', 0); + if (UNLIKELY(i != UString::NotFound)) return substituteBackreferencesSlow(replacement, source, ovector, reg, i); return replacement; } @@ -329,7 +330,7 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); int lastIndex = 0; - int startPosition = 0; + unsigned startPosition = 0; Vector<StringRange, 16> sourceRanges; Vector<UString, 16> replacements; @@ -432,7 +433,7 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue if (!lastIndex && replacements.isEmpty()) return sourceVal; - if (lastIndex < source.size()) + if (static_cast<unsigned>(lastIndex) < source.size()) sourceRanges.append(StringRange(lastIndex, source.size() - lastIndex)); return jsSpliceSubstringsWithSeparators(exec, sourceVal, source, sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size()); @@ -441,9 +442,9 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue // Not a regular expression, so treat the pattern as a string. UString patternString = pattern.toString(exec); - int matchPos = source.find(patternString); + unsigned matchPos = source.find(patternString); - if (matchPos == -1) + if (matchPos == UString::NotFound) return sourceVal; int matchLen = patternString.size(); @@ -541,7 +542,10 @@ JSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec, JSObject*, JSValue pos = static_cast<int>(dpos); } - return jsNumber(exec, s.find(u2, pos)); + unsigned result = s.find(u2, pos); + if (result == UString::NotFound) + return jsNumber(exec, -1); + return jsNumber(exec, result); } JSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) @@ -563,7 +567,11 @@ JSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec, JSObject*, JSV else if (isnan(dpos)) dpos = len; #endif - return jsNumber(exec, s.rfind(u2, static_cast<int>(dpos))); + + unsigned result = s.rfind(u2, static_cast<unsigned>(dpos)); + if (result == UString::NotFound) + return jsNumber(exec, -1); + return jsNumber(exec, result); } JSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) @@ -675,7 +683,7 @@ JSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec, JSObject*, JSValue t JSArray* result = constructEmptyArray(exec); unsigned i = 0; - int p0 = 0; + unsigned p0 = 0; unsigned limit = a1.isUndefined() ? 0xFFFFFFFFU : a1.toUInt32(exec); if (a0.inherits(&RegExpObject::info)) { RegExp* reg = asRegExpObject(a0)->regExp(); @@ -683,7 +691,7 @@ JSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec, JSObject*, JSValue t // empty string matched by regexp -> empty array return result; } - int pos = 0; + unsigned pos = 0; while (i != limit && pos < s.size()) { Vector<int, 32> ovector; int mpos = reg->match(s, pos, &ovector); @@ -691,7 +699,7 @@ JSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec, JSObject*, JSValue t break; int mlen = ovector[1] - ovector[0]; pos = mpos + (mlen == 0 ? 1 : mlen); - if (mpos != p0 || mlen) { + if (static_cast<unsigned>(mpos) != p0 || mlen) { result->put(exec, i++, jsSubstring(exec, s, p0, mpos - p0)); p0 = mpos + mlen; } @@ -713,8 +721,9 @@ JSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec, JSObject*, JSValue t while (i != limit && p0 < s.size() - 1) result->put(exec, i++, jsSingleCharacterSubstring(exec, s, p0++)); } else { - int pos; - while (i != limit && (pos = s.find(u2, p0)) >= 0) { + unsigned pos; + + while (i != limit && (pos = s.find(u2, p0)) != UString::NotFound) { result->put(exec, i++, jsSubstring(exec, s, p0, pos - p0)); p0 = pos + u2.size(); } @@ -1022,12 +1031,12 @@ static inline bool isTrimWhitespace(UChar c) static inline JSValue trimString(ExecState* exec, JSValue thisValue, int trimKind) { UString str = thisValue.toThisString(exec); - int left = 0; + unsigned left = 0; if (trimKind & TrimLeft) { while (left < str.size() && isTrimWhitespace(str[left])) left++; } - int right = str.size(); + unsigned right = str.size(); if (trimKind & TrimRight) { while (right > left && isTrimWhitespace(str[right - 1])) right--; diff --git a/JavaScriptCore/runtime/Structure.cpp b/JavaScriptCore/runtime/Structure.cpp index 546e2bf..6d13f4b 100644 --- a/JavaScriptCore/runtime/Structure.cpp +++ b/JavaScriptCore/runtime/Structure.cpp @@ -79,6 +79,106 @@ static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>); static int comparePropertyMapEntryIndices(const void* a, const void* b); +inline void Structure::setTransitionTable(TransitionTable* table) +{ + ASSERT(m_isUsingSingleSlot); +#ifndef NDEBUG + setSingleTransition(0); +#endif + m_isUsingSingleSlot = false; + m_transitions.m_table = table; + // This implicitly clears the flag that indicates we're using a single transition + ASSERT(!m_isUsingSingleSlot); +} + +// The contains and get methods accept imprecise matches, so if an unspecialised transition exists +// for the given key they will consider that transition to be a match. If a specialised transition +// exists and it matches the provided specificValue, get will return the specific transition. +inline bool Structure::transitionTableContains(const StructureTransitionTableHash::Key& key, JSCell* specificValue) +{ + if (m_isUsingSingleSlot) { + Structure* existingTransition = singleTransition(); + return existingTransition && existingTransition->m_nameInPrevious.get() == key.first + && existingTransition->m_attributesInPrevious == key.second + && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0); + } + TransitionTable::iterator find = transitionTable()->find(key); + if (find == transitionTable()->end()) + return false; + + return find->second.first || find->second.second->transitionedFor(specificValue); +} + +inline Structure* Structure::transitionTableGet(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const +{ + if (m_isUsingSingleSlot) { + Structure* existingTransition = singleTransition(); + if (existingTransition && existingTransition->m_nameInPrevious.get() == key.first + && existingTransition->m_attributesInPrevious == key.second + && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0)) + return existingTransition; + return 0; + } + + Transition transition = transitionTable()->get(key); + if (transition.second && transition.second->transitionedFor(specificValue)) + return transition.second; + return transition.first; +} + +inline bool Structure::transitionTableHasTransition(const StructureTransitionTableHash::Key& key) const +{ + if (m_isUsingSingleSlot) { + Structure* transition = singleTransition(); + return transition && transition->m_nameInPrevious == key.first + && transition->m_attributesInPrevious == key.second; + } + return transitionTable()->contains(key); +} + +inline void Structure::transitionTableRemove(const StructureTransitionTableHash::Key& key, JSCell* specificValue) +{ + if (m_isUsingSingleSlot) { + ASSERT(transitionTableContains(key, specificValue)); + setSingleTransition(0); + return; + } + TransitionTable::iterator find = transitionTable()->find(key); + if (!specificValue) + find->second.first = 0; + else + find->second.second = 0; + if (!find->second.first && !find->second.second) + transitionTable()->remove(find); +} + +inline void Structure::transitionTableAdd(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue) +{ + if (m_isUsingSingleSlot) { + if (!singleTransition()) { + setSingleTransition(structure); + return; + } + Structure* existingTransition = singleTransition(); + TransitionTable* transitionTable = new TransitionTable; + setTransitionTable(transitionTable); + if (existingTransition) + transitionTableAdd(std::make_pair(existingTransition->m_nameInPrevious.get(), existingTransition->m_attributesInPrevious), existingTransition, existingTransition->m_specificValueInPrevious); + } + if (!specificValue) { + TransitionTable::iterator find = transitionTable()->find(key); + if (find == transitionTable()->end()) + transitionTable()->add(key, Transition(structure, static_cast<Structure*>(0))); + else + find->second.first = structure; + } else { + // If we're adding a transition to a specific value, then there cannot be + // an existing transition + ASSERT(!transitionTable()->contains(key)); + transitionTable()->add(key, Transition(static_cast<Structure*>(0), structure)); + } +} + void Structure::dumpStatistics() { #if DUMP_STRUCTURE_ID_STATISTICS @@ -136,7 +236,10 @@ Structure::Structure(JSValue prototype, const TypeInfo& typeInfo, unsigned anony , m_attributesInPrevious(0) , m_specificFunctionThrashCount(0) , m_anonymousSlotCount(anonymousSlotCount) + , m_isUsingSingleSlot(true) { + m_transitions.m_singleTransition = 0; + ASSERT(m_prototype); ASSERT(m_prototype.isObject() || m_prototype.isNull()); @@ -159,12 +262,10 @@ Structure::~Structure() { if (m_previous) { ASSERT(m_nameInPrevious); - m_previous->table.remove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious); + m_previous->transitionTableRemove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious); } - - if (m_enumerationCache) - m_enumerationCache->setCachedStructure(0); + ASSERT(!m_enumerationCache.hasDeadObject()); if (m_propertyTable) { unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; @@ -177,6 +278,9 @@ Structure::~Structure() fastFree(m_propertyTable); } + if (!m_isUsingSingleSlot) + delete transitionTable(); + #ifndef NDEBUG #if ENABLE(JSC_MULTIPLE_THREADS) MutexLocker protect(ignoreSetMutex); @@ -340,7 +444,7 @@ PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Struct ASSERT(!structure->isDictionary()); ASSERT(structure->typeInfo().type() == ObjectType); - if (Structure* existingTransition = structure->table.get(make_pair(propertyName.ustring().rep(), attributes), specificValue)) { + if (Structure* existingTransition = structure->transitionTableGet(make_pair(propertyName.ustring().rep(), attributes), specificValue)) { ASSERT(existingTransition->m_offset != noOffset); offset = existingTransition->m_offset + existingTransition->m_anonymousSlotCount; ASSERT(offset >= structure->m_anonymousSlotCount); @@ -405,7 +509,7 @@ PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, con transition->m_offset = offset - structure->m_anonymousSlotCount; ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount()); - structure->table.add(make_pair(propertyName.ustring().rep(), attributes), transition.get(), specificValue); + structure->transitionTableAdd(make_pair(propertyName.ustring().rep(), attributes), transition.get(), specificValue); return transition.release(); } @@ -852,7 +956,7 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel bool Structure::hasTransition(UString::Rep* rep, unsigned attributes) { - return table.hasTransition(make_pair(rep, attributes)); + return transitionTableHasTransition(make_pair(rep, attributes)); } size_t Structure::remove(const Identifier& propertyName) diff --git a/JavaScriptCore/runtime/Structure.h b/JavaScriptCore/runtime/Structure.h index 95cf94c..968443a 100644 --- a/JavaScriptCore/runtime/Structure.h +++ b/JavaScriptCore/runtime/Structure.h @@ -179,6 +179,20 @@ namespace JSC { // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both. return m_offset == noOffset ? 0 : m_offset + 1; } + + typedef std::pair<Structure*, Structure*> Transition; + typedef HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> TransitionTable; + + inline bool transitionTableContains(const StructureTransitionTableHash::Key& key, JSCell* specificValue); + inline void transitionTableRemove(const StructureTransitionTableHash::Key& key, JSCell* specificValue); + inline void transitionTableAdd(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue); + inline bool transitionTableHasTransition(const StructureTransitionTableHash::Key& key) const; + inline Structure* transitionTableGet(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const; + + TransitionTable* transitionTable() const { ASSERT(!m_isUsingSingleSlot); return m_transitions.m_table; } + inline void setTransitionTable(TransitionTable* table); + Structure* singleTransition() const { ASSERT(m_isUsingSingleSlot); return m_transitions.m_singleTransition; } + void setSingleTransition(Structure* structure) { ASSERT(m_isUsingSingleSlot); m_transitions.m_singleTransition = structure; } bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const; @@ -199,7 +213,11 @@ namespace JSC { RefPtr<UString::Rep> m_nameInPrevious; JSCell* m_specificValueInPrevious; - StructureTransitionTable table; + // 'm_isUsingSingleSlot' indicates whether we are using the single transition optimisation. + union { + TransitionTable* m_table; + Structure* m_singleTransition; + } m_transitions; WeakGCPtr<JSPropertyNameIterator> m_enumerationCache; @@ -224,7 +242,8 @@ namespace JSC { #endif unsigned m_specificFunctionThrashCount : 2; unsigned m_anonymousSlotCount : 5; - // 5 free bits + unsigned m_isUsingSingleSlot : 1; + // 4 free bits }; inline size_t Structure::get(const Identifier& propertyName) @@ -271,58 +290,7 @@ namespace JSC { return m_propertyTable->entries()[entryIndex - 1].offset; } } - - bool StructureTransitionTable::contains(const StructureTransitionTableHash::Key& key, JSCell* specificValue) - { - if (usingSingleTransitionSlot()) { - Structure* existingTransition = singleTransition(); - return existingTransition && existingTransition->m_nameInPrevious.get() == key.first - && existingTransition->m_attributesInPrevious == key.second - && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0); - } - TransitionTable::iterator find = table()->find(key); - if (find == table()->end()) - return false; - - return find->second.first || find->second.second->transitionedFor(specificValue); - } - Structure* StructureTransitionTable::get(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const - { - if (usingSingleTransitionSlot()) { - Structure* existingTransition = singleTransition(); - if (existingTransition && existingTransition->m_nameInPrevious.get() == key.first - && existingTransition->m_attributesInPrevious == key.second - && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0)) - return existingTransition; - return 0; - } - - Transition transition = table()->get(key); - if (transition.second && transition.second->transitionedFor(specificValue)) - return transition.second; - return transition.first; - } - - bool StructureTransitionTable::hasTransition(const StructureTransitionTableHash::Key& key) const - { - if (usingSingleTransitionSlot()) { - Structure* transition = singleTransition(); - return transition && transition->m_nameInPrevious == key.first - && transition->m_attributesInPrevious == key.second; - } - return table()->contains(key); - } - - void StructureTransitionTable::reifySingleTransition() - { - ASSERT(usingSingleTransitionSlot()); - Structure* existingTransition = singleTransition(); - TransitionTable* transitionTable = new TransitionTable; - setTransitionTable(transitionTable); - if (existingTransition) - add(std::make_pair(existingTransition->m_nameInPrevious.get(), existingTransition->m_attributesInPrevious), existingTransition, existingTransition->m_specificValueInPrevious); - } } // namespace JSC #endif // Structure_h diff --git a/JavaScriptCore/runtime/StructureTransitionTable.h b/JavaScriptCore/runtime/StructureTransitionTable.h index 320dbdd..d1dc2d9 100644 --- a/JavaScriptCore/runtime/StructureTransitionTable.h +++ b/JavaScriptCore/runtime/StructureTransitionTable.h @@ -30,7 +30,6 @@ #include <wtf/HashFunctions.h> #include <wtf/HashMap.h> #include <wtf/HashTraits.h> -#include <wtf/PtrAndFlags.h> #include <wtf/OwnPtr.h> #include <wtf/RefPtr.h> @@ -67,99 +66,6 @@ namespace JSC { static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); } }; - class StructureTransitionTable { - typedef std::pair<Structure*, Structure*> Transition; - typedef HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> TransitionTable; - public: - StructureTransitionTable() { - m_transitions.m_singleTransition.set(0); - m_transitions.m_singleTransition.setFlag(usingSingleSlot); - } - - ~StructureTransitionTable() { - if (!usingSingleTransitionSlot()) - delete table(); - } - - // The contains and get methods accept imprecise matches, so if an unspecialised transition exists - // for the given key they will consider that transition to be a match. If a specialised transition - // exists and it matches the provided specificValue, get will return the specific transition. - inline bool contains(const StructureTransitionTableHash::Key&, JSCell* specificValue); - inline Structure* get(const StructureTransitionTableHash::Key&, JSCell* specificValue) const; - inline bool hasTransition(const StructureTransitionTableHash::Key& key) const; - void remove(const StructureTransitionTableHash::Key& key, JSCell* specificValue) - { - if (usingSingleTransitionSlot()) { - ASSERT(contains(key, specificValue)); - setSingleTransition(0); - return; - } - TransitionTable::iterator find = table()->find(key); - if (!specificValue) - find->second.first = 0; - else - find->second.second = 0; - if (!find->second.first && !find->second.second) - table()->remove(find); - } - void add(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue) - { - if (usingSingleTransitionSlot()) { - if (!singleTransition()) { - setSingleTransition(structure); - return; - } - reifySingleTransition(); - } - if (!specificValue) { - TransitionTable::iterator find = table()->find(key); - if (find == table()->end()) - table()->add(key, Transition(structure, 0)); - else - find->second.first = structure; - } else { - // If we're adding a transition to a specific value, then there cannot be - // an existing transition - ASSERT(!table()->contains(key)); - table()->add(key, Transition(0, structure)); - } - } - - private: - TransitionTable* table() const { ASSERT(!usingSingleTransitionSlot()); return m_transitions.m_table; } - Structure* singleTransition() const { - ASSERT(usingSingleTransitionSlot()); - return m_transitions.m_singleTransition.get(); - } - bool usingSingleTransitionSlot() const { return m_transitions.m_singleTransition.isFlagSet(usingSingleSlot); } - void setSingleTransition(Structure* structure) - { - ASSERT(usingSingleTransitionSlot()); - m_transitions.m_singleTransition.set(structure); - } - - void setTransitionTable(TransitionTable* table) - { - ASSERT(usingSingleTransitionSlot()); -#ifndef NDEBUG - setSingleTransition(0); -#endif - m_transitions.m_table = table; - // This implicitly clears the flag that indicates we're using a single transition - ASSERT(!usingSingleTransitionSlot()); - } - inline void reifySingleTransition(); - - enum UsingSingleSlot { - usingSingleSlot - }; - // Last bit indicates whether we are using the single transition optimisation - union { - TransitionTable* m_table; - PtrAndFlagsBase<Structure, UsingSingleSlot> m_singleTransition; - } m_transitions; - }; - } // namespace JSC #endif // StructureTransitionTable_h diff --git a/JavaScriptCore/runtime/Terminator.h b/JavaScriptCore/runtime/Terminator.h new file mode 100644 index 0000000..6b0f236 --- /dev/null +++ b/JavaScriptCore/runtime/Terminator.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010 Google 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. + * 3. Neither the name of Google Inc. ("Google") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 Terminator_h +#define Terminator_h + +namespace JSC { + +class Terminator { +public: + Terminator() : m_shouldTerminate(false) { } + + void terminateSoon() { m_shouldTerminate = true; } + bool shouldTerminate() const { return m_shouldTerminate; } + +private: + bool m_shouldTerminate; +}; + +} // namespace JSC + +#endif // Terminator_h diff --git a/JavaScriptCore/runtime/TimeoutChecker.cpp b/JavaScriptCore/runtime/TimeoutChecker.cpp index 250fdaf..2dc1028 100644 --- a/JavaScriptCore/runtime/TimeoutChecker.cpp +++ b/JavaScriptCore/runtime/TimeoutChecker.cpp @@ -84,6 +84,13 @@ static inline unsigned getCPUTime() GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime); return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000; +#elif OS(SYMBIAN) + RThread current; + TTimeIntervalMicroSeconds cpuTime; + + TInt err = current.GetCpuTime(cpuTime); + ASSERT_WITH_MESSAGE(err == KErrNone, "GetCpuTime failed with %d", err); + return cpuTime.Int64() / 1000; #elif PLATFORM(BREWMP) // This function returns a continuously and linearly increasing millisecond // timer from the time the device was powered on. diff --git a/JavaScriptCore/runtime/UString.cpp b/JavaScriptCore/runtime/UString.cpp index 4a89a23..6b16274 100644 --- a/JavaScriptCore/runtime/UString.cpp +++ b/JavaScriptCore/runtime/UString.cpp @@ -57,108 +57,15 @@ namespace JSC { extern const double NaN; extern const double Inf; -CString::CString(const char* c) - : m_length(strlen(c)) - , m_data(new char[m_length + 1]) -{ - memcpy(m_data, c, m_length + 1); -} - -CString::CString(const char* c, size_t length) - : m_length(length) - , m_data(new char[length + 1]) -{ - memcpy(m_data, c, m_length); - m_data[m_length] = 0; -} - -CString::CString(const CString& b) -{ - m_length = b.m_length; - if (b.m_data) { - m_data = new char[m_length + 1]; - memcpy(m_data, b.m_data, m_length + 1); - } else - m_data = 0; -} - -CString::~CString() -{ - delete [] m_data; -} - -CString CString::adopt(char* c, size_t length) -{ - CString s; - s.m_data = c; - s.m_length = length; - return s; -} - -CString& CString::append(const CString& t) -{ - char* n; - n = new char[m_length + t.m_length + 1]; - if (m_length) - memcpy(n, m_data, m_length); - if (t.m_length) - memcpy(n + m_length, t.m_data, t.m_length); - m_length += t.m_length; - n[m_length] = 0; - - delete [] m_data; - m_data = n; - - return *this; -} - -CString& CString::operator=(const char* c) -{ - if (m_data) - delete [] m_data; - m_length = strlen(c); - m_data = new char[m_length + 1]; - memcpy(m_data, c, m_length + 1); - - return *this; -} - -CString& CString::operator=(const CString& str) -{ - if (this == &str) - return *this; - - if (m_data) - delete [] m_data; - m_length = str.m_length; - if (str.m_data) { - m_data = new char[m_length + 1]; - memcpy(m_data, str.m_data, m_length + 1); - } else - m_data = 0; - - return *this; -} - -bool operator==(const CString& c1, const CString& c2) -{ - size_t len = c1.size(); - return len == c2.size() && (len == 0 || memcmp(c1.c_str(), c2.c_str(), len) == 0); -} - -// 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; -UStringImpl* UStringImpl::s_empty; - -UString::Rep* UString::s_nullRep; +// The null string is immutable, except for refCount. UString* UString::s_nullUString; void initializeUString() { - UStringImpl::s_empty = new UStringImpl(&sharedEmptyChar, 0, UStringImpl::ConstructStaticString); + // UStringImpl::empty() does not construct its static string in a threadsafe fashion, + // so ensure it has been initialized from here. + UStringImpl::empty(); - UString::s_nullRep = new UStringImpl(0, 0, UStringImpl::ConstructStaticString); UString::s_nullUString = new UString; } @@ -167,17 +74,14 @@ UString::UString(const char* c) { } -UString::UString(const char* c, int length) +UString::UString(const char* c, unsigned length) : m_rep(Rep::create(c, length)) { } -UString::UString(const UChar* c, int length) +UString::UString(const UChar* c, unsigned length) + : m_rep(Rep::create(c, length)) { - if (length == 0) - m_rep = &Rep::empty(); - else - m_rep = Rep::create(c, length); } UString UString::from(int i) @@ -206,7 +110,7 @@ UString UString::from(int i) *--p = '-'; } - return UString(p, static_cast<int>(end - p)); + return UString(p, static_cast<unsigned>(end - p)); } UString UString::from(long long i) @@ -239,10 +143,10 @@ UString UString::from(long long i) *--p = '-'; } - return UString(p, static_cast<int>(end - p)); + return UString(p, static_cast<unsigned>(end - p)); } -UString UString::from(unsigned int u) +UString UString::from(unsigned u) { UChar buf[sizeof(u) * 3]; UChar* end = buf + sizeof(buf) / sizeof(UChar); @@ -257,7 +161,7 @@ UString UString::from(unsigned int u) } } - return UString(p, static_cast<int>(end - p)); + return UString(p, static_cast<unsigned>(end - p)); } UString UString::from(long l) @@ -286,7 +190,7 @@ UString UString::from(long l) *--p = '-'; } - return UString(p, static_cast<int>(end - p)); + return UString(p, end - p); } UString UString::from(double d) @@ -297,35 +201,12 @@ UString UString::from(double d) return UString(buffer, length); } -bool UString::getCString(CStringBuffer& buffer) const -{ - int length = size(); - int neededSize = length + 1; - buffer.resize(neededSize); - char* buf = buffer.data(); - - UChar ored = 0; - const UChar* p = data(); - char* q = buf; - const UChar* limit = p + length; - while (p != limit) { - UChar c = p[0]; - ored |= c; - *q = static_cast<char>(c); - ++p; - ++q; - } - *q = '\0'; - - return !(ored & 0xFF00); -} - char* UString::ascii() const { static char* asciiBuffer = 0; - int length = size(); - int neededSize = length + 1; + unsigned length = size(); + unsigned neededSize = length + 1; delete[] asciiBuffer; asciiBuffer = new char[neededSize]; @@ -355,7 +236,7 @@ bool UString::is8Bit() const return true; } -UChar UString::operator[](int pos) const +UChar UString::operator[](unsigned pos) const { if (pos >= size()) return '\0'; @@ -373,10 +254,14 @@ double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) co return NaN; } - // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk - // after the number, so this is too strict a check. - CStringBuffer s; - if (!getCString(s)) + // FIXME: If tolerateTrailingJunk is true, then we want to tolerate junk + // after the number, even if it contains invalid UTF-16 sequences. So we + // shouldn't use the UTF8String function, which returns null when it + // encounters invalid UTF-16. Further, we have no need to convert the + // non-ASCII characters to UTF-8, so the UTF8String does quite a bit of + // unnecessary work. + CString s = UTF8String(); + if (s.isNull()) return NaN; const char* c = s.data(); @@ -441,6 +326,7 @@ double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) co while (isASCIISpace(*c)) c++; // don't allow anything after - unless tolerant=true + // FIXME: If string contains a U+0000 character, then this check is incorrect. if (!tolerateTrailingJunk && *c != '\0') d = NaN; @@ -495,10 +381,10 @@ uint32_t UString::toStrictUInt32(bool* ok) const *ok = false; // Empty string is not OK. - int len = m_rep->size(); + unsigned len = m_rep->length(); if (len == 0) return 0; - const UChar* p = m_rep->data(); + const UChar* p = m_rep->characters(); unsigned short c = p[0]; // If the first digit is 0, only 0 itself is OK. @@ -539,102 +425,92 @@ uint32_t UString::toStrictUInt32(bool* ok) const } } -int UString::find(const UString& f, int pos) const +unsigned UString::find(const UString& f, unsigned pos) const { - int fsz = f.size(); - - if (pos < 0) - pos = 0; + unsigned fsz = f.size(); if (fsz == 1) { UChar ch = f[0]; const UChar* end = data() + size(); for (const UChar* c = data() + pos; c < end; c++) { if (*c == ch) - return static_cast<int>(c - data()); + return static_cast<unsigned>(c - data()); } - return -1; + return NotFound; } - int sz = size(); + unsigned sz = size(); if (sz < fsz) - return -1; + return NotFound; if (fsz == 0) return pos; const UChar* end = data() + sz - fsz; - int fsizeminusone = (fsz - 1) * sizeof(UChar); + unsigned fsizeminusone = (fsz - 1) * sizeof(UChar); const UChar* fdata = f.data(); unsigned short fchar = fdata[0]; ++fdata; for (const UChar* c = data() + pos; c <= end; c++) { if (c[0] == fchar && !memcmp(c + 1, fdata, fsizeminusone)) - return static_cast<int>(c - data()); + return static_cast<unsigned>(c - data()); } - return -1; + return NotFound; } -int UString::find(UChar ch, int pos) const +unsigned UString::find(UChar ch, unsigned pos) const { - if (pos < 0) - pos = 0; const UChar* end = data() + size(); for (const UChar* c = data() + pos; c < end; c++) { if (*c == ch) - return static_cast<int>(c - data()); + return static_cast<unsigned>(c - data()); } - return -1; + return NotFound; } -int UString::rfind(const UString& f, int pos) const +unsigned UString::rfind(const UString& f, unsigned pos) const { - int sz = size(); - int fsz = f.size(); + unsigned sz = size(); + unsigned fsz = f.size(); if (sz < fsz) - return -1; - if (pos < 0) - pos = 0; + return NotFound; if (pos > sz - fsz) pos = sz - fsz; if (fsz == 0) return pos; - int fsizeminusone = (fsz - 1) * sizeof(UChar); + unsigned fsizeminusone = (fsz - 1) * sizeof(UChar); const UChar* fdata = f.data(); for (const UChar* c = data() + pos; c >= data(); c--) { if (*c == *fdata && !memcmp(c + 1, fdata + 1, fsizeminusone)) - return static_cast<int>(c - data()); + return static_cast<unsigned>(c - data()); } - return -1; + return NotFound; } -int UString::rfind(UChar ch, int pos) const +unsigned UString::rfind(UChar ch, unsigned pos) const { if (isEmpty()) - return -1; + return NotFound; if (pos + 1 >= size()) pos = size() - 1; for (const UChar* c = data() + pos; c >= data(); c--) { if (*c == ch) - return static_cast<int>(c - data()); + return static_cast<unsigned>(c - data()); } - return -1; + return NotFound; } -UString UString::substr(int pos, int len) const +UString UString::substr(unsigned pos, unsigned len) const { - int s = size(); + unsigned s = size(); - if (pos < 0) - pos = 0; - else if (pos >= s) + if (pos >= s) pos = s; - if (len < 0) - len = s; - if (pos + len >= s) - len = s - pos; + unsigned limit = s - pos; + if (len > limit) + len = limit; if (pos == 0 && len == s) return *this; @@ -661,12 +537,12 @@ bool operator==(const UString& s1, const char *s2) bool operator<(const UString& s1, const UString& s2) { - const int l1 = s1.size(); - const int l2 = s2.size(); - const int lmin = l1 < l2 ? l1 : l2; + const unsigned l1 = s1.size(); + const unsigned l2 = s2.size(); + const unsigned lmin = l1 < l2 ? l1 : l2; const UChar* c1 = s1.data(); const UChar* c2 = s2.data(); - int l = 0; + unsigned l = 0; while (l < lmin && *c1 == *c2) { c1++; c2++; @@ -680,12 +556,12 @@ bool operator<(const UString& s1, const UString& s2) bool operator>(const UString& s1, const UString& s2) { - const int l1 = s1.size(); - const int l2 = s2.size(); - const int lmin = l1 < l2 ? l1 : l2; + const unsigned l1 = s1.size(); + const unsigned l2 = s2.size(); + const unsigned lmin = l1 < l2 ? l1 : l2; const UChar* c1 = s1.data(); const UChar* c2 = s2.data(); - int l = 0; + unsigned l = 0; while (l < lmin && *c1 == *c2) { c1++; c2++; @@ -699,12 +575,12 @@ bool operator>(const UString& s1, const UString& s2) int compare(const UString& s1, const UString& s2) { - const int l1 = s1.size(); - const int l2 = s2.size(); - const int lmin = l1 < l2 ? l1 : l2; + const unsigned l1 = s1.size(); + const unsigned l2 = s2.size(); + const unsigned lmin = l1 < l2 ? l1 : l2; const UChar* c1 = s1.data(); const UChar* c2 = s2.data(); - int l = 0; + unsigned l = 0; while (l < lmin && *c1 == *c2) { c1++; c2++; @@ -720,24 +596,10 @@ int compare(const UString& s1, const UString& s2) return (l1 > l2) ? 1 : -1; } -bool equal(const UString::Rep* r, const UString::Rep* b) -{ - int length = r->size(); - if (length != b->size()) - return false; - const UChar* d = r->data(); - const UChar* s = b->data(); - for (int i = 0; i != length; ++i) { - if (d[i] != s[i]) - return false; - } - return true; -} - CString UString::UTF8String(bool strict) const { // Allocate a buffer big enough to hold all the characters. - const int length = size(); + const unsigned length = size(); Vector<char, 1024> buffer(length * 3); // Convert to runs of 8-bit characters. diff --git a/JavaScriptCore/runtime/UString.h b/JavaScriptCore/runtime/UString.h index 7d9ec49..da1065e 100644 --- a/JavaScriptCore/runtime/UString.h +++ b/JavaScriptCore/runtime/UString.h @@ -31,9 +31,9 @@ #include <wtf/CrossThreadRefCounted.h> #include <wtf/OwnFastMallocPtr.h> #include <wtf/PassRefPtr.h> -#include <wtf/PtrAndFlags.h> #include <wtf/RefPtr.h> #include <wtf/Vector.h> +#include <wtf/text/CString.h> #include <wtf/unicode/Unicode.h> namespace JSC { @@ -41,39 +41,6 @@ namespace JSC { using WTF::PlacementNewAdoptType; using WTF::PlacementNewAdopt; - class CString { - public: - CString() - : m_length(0) - , m_data(0) - { - } - - CString(const char*); - CString(const char*, size_t); - CString(const CString&); - - ~CString(); - - static CString adopt(char*, size_t); // buffer should be allocated with new[]. - - CString& append(const CString&); - CString& operator=(const char* c); - CString& operator=(const CString&); - CString& operator+=(const CString& c) { return append(c); } - - size_t size() const { return m_length; } - const char* c_str() const { return m_data; } - - private: - size_t m_length; - char* m_data; - }; - - bool operator==(const CString&, const CString&); - - typedef Vector<char, 32> CStringBuffer; - class UString { friend class JIT; @@ -81,10 +48,10 @@ namespace JSC { typedef UStringImpl Rep; public: - UString(); + UString() {} UString(const char*); // Constructor for null-terminated string. - UString(const char*, int length); - UString(const UChar*, int length); + UString(const char*, unsigned length); + UString(const UChar*, unsigned length); UString(const Vector<UChar>& buffer); UString(const UString& s) @@ -98,10 +65,6 @@ namespace JSC { { } - ~UString() - { - } - template<size_t inlineCapacity> static PassRefPtr<UStringImpl> adopt(Vector<UChar, inlineCapacity>& vector) { @@ -110,12 +73,10 @@ namespace JSC { static UString from(int); static UString from(long long); - static UString from(unsigned int); + static UString from(unsigned); static UString from(long); static UString from(double); - bool getCString(CStringBuffer&) const; - // NOTE: This method should only be used for *debugging* purposes as it // is neither Unicode safe nor free from side effects nor thread-safe. char* ascii() const; @@ -130,16 +91,26 @@ namespace JSC { */ CString UTF8String(bool strict = false) const; - const UChar* data() const { return m_rep->data(); } + const UChar* data() const + { + if (!m_rep) + return 0; + return m_rep->characters(); + } - bool isNull() const { return m_rep == s_nullRep; } - bool isEmpty() const { return !m_rep->size(); } + unsigned size() const + { + if (!m_rep) + return 0; + return m_rep->length(); + } - bool is8Bit() const; + bool isNull() const { return !m_rep; } + bool isEmpty() const { return !m_rep || !m_rep->length(); } - int size() const { return m_rep->size(); } + bool is8Bit() const; - UChar operator[](int pos) const; + UChar operator[](unsigned pos) const; double toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const; double toDouble(bool tolerateTrailingJunk) const; @@ -151,12 +122,13 @@ namespace JSC { unsigned toArrayIndex(bool* ok = 0) const; - int find(const UString& f, int pos = 0) const; - int find(UChar, int pos = 0) const; - int rfind(const UString& f, int pos) const; - int rfind(UChar, int pos) const; + static const unsigned NotFound = 0xFFFFFFFFu; + unsigned find(const UString& f, unsigned pos = 0) const; + unsigned find(UChar, unsigned pos = 0) const; + unsigned rfind(const UString& f, unsigned pos) const; + unsigned rfind(UChar, unsigned pos) const; - UString substr(int pos = 0, int len = -1) const; + UString substr(unsigned pos = 0, unsigned len = 0xFFFFFFFF) const; static const UString& null() { return *s_nullUString; } @@ -165,15 +137,18 @@ namespace JSC { UString(PassRefPtr<Rep> r) : m_rep(r) { - ASSERT(m_rep); } - size_t cost() const { return m_rep->cost(); } + size_t cost() const + { + if (!m_rep) + return 0; + return m_rep->cost(); + } private: RefPtr<Rep> m_rep; - JS_EXPORTDATA static Rep* s_nullRep; static UString* s_nullUString; friend void initializeUString(); @@ -182,7 +157,7 @@ namespace JSC { ALWAYS_INLINE bool operator==(const UString& s1, const UString& s2) { - int size = s1.size(); + unsigned size = s1.size(); switch (size) { case 0: return !s2.size(); @@ -228,11 +203,6 @@ namespace JSC { int compare(const UString&, const UString&); - inline UString::UString() - : m_rep(s_nullRep) - { - } - // Rule from ECMA 15.2 about what an array index is. // Must exactly match string form of an unsigned integer, and be less than 2^32 - 1. inline unsigned UString::toArrayIndex(bool* ok) const @@ -246,9 +216,7 @@ namespace JSC { // We'd rather not do shared substring append for small strings, since // this runs too much risk of a tiny initial string holding down a // 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::minExtraCost / sizeof(UChar); + static const unsigned minShareSize = Heap::minExtraCost / sizeof(UChar); struct IdentifierRepHash : PtrHash<RefPtr<JSC::UString::Rep> > { static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->existingHash(); } @@ -327,6 +295,14 @@ namespace JSC { unsigned m_length; }; + inline void sumWithOverflow(unsigned& total, unsigned addend, bool& overflow) + { + unsigned oldTotal = total; + total = oldTotal + addend; + if (total < oldTotal) + overflow = true; + } + template<typename StringType1, typename StringType2> PassRefPtr<UStringImpl> tryMakeString(StringType1 string1, StringType2 string2) { @@ -334,7 +310,11 @@ namespace JSC { StringTypeAdapter<StringType2> adapter2(string2); UChar* buffer; - unsigned length = adapter1.length() + adapter2.length(); + bool overflow = false; + unsigned length = adapter1.length(); + sumWithOverflow(length, adapter2.length(), overflow); + if (overflow) + return 0; PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); if (!resultImpl) return 0; @@ -355,7 +335,12 @@ namespace JSC { StringTypeAdapter<StringType3> adapter3(string3); UChar* buffer; - unsigned length = adapter1.length() + adapter2.length() + adapter3.length(); + bool overflow = false; + unsigned length = adapter1.length(); + sumWithOverflow(length, adapter2.length(), overflow); + sumWithOverflow(length, adapter3.length(), overflow); + if (overflow) + return 0; PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); if (!resultImpl) return 0; @@ -379,7 +364,13 @@ namespace JSC { StringTypeAdapter<StringType4> adapter4(string4); UChar* buffer; - unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length(); + bool overflow = false; + unsigned length = adapter1.length(); + sumWithOverflow(length, adapter2.length(), overflow); + sumWithOverflow(length, adapter3.length(), overflow); + sumWithOverflow(length, adapter4.length(), overflow); + if (overflow) + return 0; PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); if (!resultImpl) return 0; @@ -406,7 +397,14 @@ namespace JSC { StringTypeAdapter<StringType5> adapter5(string5); UChar* buffer; - unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length(); + bool overflow = false; + unsigned length = adapter1.length(); + sumWithOverflow(length, adapter2.length(), overflow); + sumWithOverflow(length, adapter3.length(), overflow); + sumWithOverflow(length, adapter4.length(), overflow); + sumWithOverflow(length, adapter5.length(), overflow); + if (overflow) + return 0; PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); if (!resultImpl) return 0; @@ -436,7 +434,15 @@ namespace JSC { StringTypeAdapter<StringType6> adapter6(string6); UChar* buffer; - unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length(); + bool overflow = false; + unsigned length = adapter1.length(); + sumWithOverflow(length, adapter2.length(), overflow); + sumWithOverflow(length, adapter3.length(), overflow); + sumWithOverflow(length, adapter4.length(), overflow); + sumWithOverflow(length, adapter5.length(), overflow); + sumWithOverflow(length, adapter6.length(), overflow); + if (overflow) + return 0; PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); if (!resultImpl) return 0; @@ -469,7 +475,16 @@ namespace JSC { StringTypeAdapter<StringType7> adapter7(string7); UChar* buffer; - unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length() + adapter7.length(); + bool overflow = false; + unsigned length = adapter1.length(); + sumWithOverflow(length, adapter2.length(), overflow); + sumWithOverflow(length, adapter3.length(), overflow); + sumWithOverflow(length, adapter4.length(), overflow); + sumWithOverflow(length, adapter5.length(), overflow); + sumWithOverflow(length, adapter6.length(), overflow); + sumWithOverflow(length, adapter7.length(), overflow); + if (overflow) + return 0; PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); if (!resultImpl) return 0; @@ -505,7 +520,17 @@ namespace JSC { StringTypeAdapter<StringType8> adapter8(string8); UChar* buffer; - unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length() + adapter7.length() + adapter8.length(); + bool overflow = false; + unsigned length = adapter1.length(); + sumWithOverflow(length, adapter2.length(), overflow); + sumWithOverflow(length, adapter3.length(), overflow); + sumWithOverflow(length, adapter4.length(), overflow); + sumWithOverflow(length, adapter5.length(), overflow); + sumWithOverflow(length, adapter6.length(), overflow); + sumWithOverflow(length, adapter7.length(), overflow); + sumWithOverflow(length, adapter8.length(), overflow); + if (overflow) + return 0; PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); if (!resultImpl) return 0; @@ -602,7 +627,7 @@ namespace WTF { template<> struct StrHash<JSC::UString::Rep*> { static unsigned hash(const JSC::UString::Rep* key) { return key->hash(); } - static bool equal(const JSC::UString::Rep* a, const JSC::UString::Rep* b) { return JSC::equal(a, b); } + static bool equal(const JSC::UString::Rep* a, const JSC::UString::Rep* b) { return ::equal(a, b); } static const bool safeToCompareToEmptyOrDeleted = false; }; @@ -610,22 +635,18 @@ namespace WTF { using StrHash<JSC::UString::Rep*>::hash; static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->hash(); } using StrHash<JSC::UString::Rep*>::equal; - static bool equal(const RefPtr<JSC::UString::Rep>& a, const RefPtr<JSC::UString::Rep>& b) { return JSC::equal(a.get(), b.get()); } - static bool equal(const JSC::UString::Rep* a, const RefPtr<JSC::UString::Rep>& b) { return JSC::equal(a, b.get()); } - static bool equal(const RefPtr<JSC::UString::Rep>& a, const JSC::UString::Rep* b) { return JSC::equal(a.get(), b); } + static bool equal(const RefPtr<JSC::UString::Rep>& a, const RefPtr<JSC::UString::Rep>& b) { return ::equal(a.get(), b.get()); } + static bool equal(const JSC::UString::Rep* a, const RefPtr<JSC::UString::Rep>& b) { return ::equal(a, b.get()); } + static bool equal(const RefPtr<JSC::UString::Rep>& a, const JSC::UString::Rep* b) { return ::equal(a.get(), b); } static const bool safeToCompareToEmptyOrDeleted = false; }; - template<> struct DefaultHash<JSC::UString::Rep*> { - typedef StrHash<JSC::UString::Rep*> Hash; - }; - - template<> struct DefaultHash<RefPtr<JSC::UString::Rep> > { - typedef StrHash<RefPtr<JSC::UString::Rep> > Hash; - + template <> struct VectorTraits<JSC::UString> : SimpleClassVectorTraits + { + static const bool canInitializeWithMemset = true; }; - + } // namespace WTF #endif diff --git a/JavaScriptCore/runtime/UStringImpl.cpp b/JavaScriptCore/runtime/UStringImpl.cpp deleted file mode 100644 index 9882007..0000000 --- a/JavaScriptCore/runtime/UStringImpl.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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 { - -PassRefPtr<UStringImpl> UStringImpl::create(const char* c) -{ - ASSERT(c); - - if (!c[0]) - return &UStringImpl::empty(); - - size_t length = strlen(c); - UChar* d; - PassRefPtr<UStringImpl> result = UStringImpl::createUninitialized(length, d); - 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; -} - -PassRefPtr<UStringImpl> UStringImpl::create(const char* c, int length) -{ - ASSERT(c); - - if (!length) - return &UStringImpl::empty(); - - UChar* d; - PassRefPtr<UStringImpl> result = UStringImpl::createUninitialized(length, d); - 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; -} - -PassRefPtr<UStringImpl> UStringImpl::create(const UChar* buffer, int length) -{ - UChar* newBuffer; - PassRefPtr<UStringImpl> impl = createUninitialized(length, newBuffer); - copyChars(newBuffer, buffer, length); - return impl; -} - -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/JavaScriptCore/runtime/UStringImpl.h b/JavaScriptCore/runtime/UStringImpl.h index bbea0aa..08f1fa5 100644 --- a/JavaScriptCore/runtime/UStringImpl.h +++ b/JavaScriptCore/runtime/UStringImpl.h @@ -1,297 +1,30 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google 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 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. * - * 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()) { - ASSERT(vector.data()); - return adoptRef(new UStringImpl(vector.releaseBuffer(), length, BufferOwned)); - } - return &empty(); - } - - static PassRefPtr<UStringImpl> create(const char* c); - static PassRefPtr<UStringImpl> create(const char* c, int length); - static PassRefPtr<UStringImpl> create(const UChar* buffer, int length); - - 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& 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(); - } - - using Noncopyable::operator new; - void* operator new(size_t, void* inPlace) { return inPlace; } - - ~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_empty; - - friend class JIT; - friend class SmallStringsStorage; - friend void initializeUString(); -}; - -bool equal(const UStringImpl*, const UStringImpl*); - -} +// FIXME: Remove this redundant name! +#include <wtf/text/StringImpl.h> +namespace JSC { typedef WebCore::StringImpl UStringImpl; } #endif diff --git a/JavaScriptCore/runtime/WeakGCPtr.h b/JavaScriptCore/runtime/WeakGCPtr.h index 3ed4645..9dce858 100644 --- a/JavaScriptCore/runtime/WeakGCPtr.h +++ b/JavaScriptCore/runtime/WeakGCPtr.h @@ -44,10 +44,13 @@ public: return m_ptr; } - void clear(JSCell* ptr) + bool clear(JSCell* ptr) { - if (ptr == m_ptr) + if (ptr == m_ptr) { m_ptr = 0; + return true; + } + return false; } T& operator*() const { return *get(); } @@ -65,11 +68,15 @@ public: WeakGCPtr& operator=(T*); +#if !ASSERT_DISABLED + bool hasDeadObject() const { return !!m_ptr; } +#endif + private: void assign(T* ptr) { - if (ptr) - Heap::markCell(ptr); + ASSERT(ptr); + Heap::markCell(ptr); m_ptr = ptr; } |