summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'JavaScriptCore/runtime')
-rw-r--r--JavaScriptCore/runtime/ArrayPrototype.cpp62
-rw-r--r--JavaScriptCore/runtime/CachedTranscendentalFunction.h103
-rw-r--r--JavaScriptCore/runtime/Collector.cpp91
-rw-r--r--JavaScriptCore/runtime/Collector.h13
-rw-r--r--JavaScriptCore/runtime/CommonIdentifiers.cpp3
-rw-r--r--JavaScriptCore/runtime/CommonIdentifiers.h1
-rw-r--r--JavaScriptCore/runtime/Completion.cpp12
-rw-r--r--JavaScriptCore/runtime/Completion.h2
-rw-r--r--JavaScriptCore/runtime/DateConversion.cpp2
-rw-r--r--JavaScriptCore/runtime/DatePrototype.cpp3
-rw-r--r--JavaScriptCore/runtime/ExceptionHelpers.cpp19
-rw-r--r--JavaScriptCore/runtime/ExceptionHelpers.h1
-rw-r--r--JavaScriptCore/runtime/Executable.h7
-rw-r--r--JavaScriptCore/runtime/FunctionPrototype.cpp2
-rw-r--r--JavaScriptCore/runtime/GetterSetter.h1
-rw-r--r--JavaScriptCore/runtime/Identifier.cpp164
-rw-r--r--JavaScriptCore/runtime/Identifier.h87
-rw-r--r--JavaScriptCore/runtime/InitializeThreading.cpp2
-rw-r--r--JavaScriptCore/runtime/InternalFunction.cpp2
-rw-r--r--JavaScriptCore/runtime/JSAPIValueWrapper.h2
-rw-r--r--JavaScriptCore/runtime/JSActivation.cpp4
-rw-r--r--JavaScriptCore/runtime/JSActivation.h3
-rw-r--r--JavaScriptCore/runtime/JSArray.cpp12
-rw-r--r--JavaScriptCore/runtime/JSArray.h6
-rw-r--r--JavaScriptCore/runtime/JSCell.cpp10
-rw-r--r--JavaScriptCore/runtime/JSCell.h7
-rw-r--r--JavaScriptCore/runtime/JSFunction.cpp37
-rw-r--r--JavaScriptCore/runtime/JSFunction.h8
-rw-r--r--JavaScriptCore/runtime/JSGlobalData.cpp31
-rw-r--r--JavaScriptCore/runtime/JSGlobalData.h41
-rw-r--r--JavaScriptCore/runtime/JSGlobalObject.cpp10
-rw-r--r--JavaScriptCore/runtime/JSGlobalObject.h13
-rw-r--r--JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp15
-rw-r--r--JavaScriptCore/runtime/JSImmediate.h6
-rw-r--r--JavaScriptCore/runtime/JSLock.cpp8
-rw-r--r--JavaScriptCore/runtime/JSNumberCell.cpp5
-rw-r--r--JavaScriptCore/runtime/JSNumberCell.h1
-rw-r--r--JavaScriptCore/runtime/JSONObject.cpp13
-rw-r--r--JavaScriptCore/runtime/JSONObject.h2
-rw-r--r--JavaScriptCore/runtime/JSObject.cpp9
-rw-r--r--JavaScriptCore/runtime/JSObject.h57
-rw-r--r--JavaScriptCore/runtime/JSPropertyNameIterator.h11
-rw-r--r--JavaScriptCore/runtime/JSString.cpp117
-rw-r--r--JavaScriptCore/runtime/JSString.h270
-rw-r--r--JavaScriptCore/runtime/JSStringBuilder.h54
-rw-r--r--JavaScriptCore/runtime/JSTypeInfo.h8
-rw-r--r--JavaScriptCore/runtime/JSValue.h16
-rw-r--r--JavaScriptCore/runtime/JSZombie.h2
-rw-r--r--JavaScriptCore/runtime/Lookup.cpp14
-rw-r--r--JavaScriptCore/runtime/Lookup.h23
-rw-r--r--JavaScriptCore/runtime/MathObject.cpp5
-rw-r--r--JavaScriptCore/runtime/NumberConstructor.cpp21
-rw-r--r--JavaScriptCore/runtime/NumberPrototype.cpp6
-rw-r--r--JavaScriptCore/runtime/NumericStrings.h23
-rw-r--r--JavaScriptCore/runtime/Operations.h149
-rw-r--r--JavaScriptCore/runtime/PropertyNameArray.cpp2
-rw-r--r--JavaScriptCore/runtime/PropertySlot.cpp8
-rw-r--r--JavaScriptCore/runtime/PropertySlot.h80
-rw-r--r--JavaScriptCore/runtime/RegExp.cpp59
-rw-r--r--JavaScriptCore/runtime/RegExp.h5
-rw-r--r--JavaScriptCore/runtime/RegExpConstructor.cpp99
-rw-r--r--JavaScriptCore/runtime/RegExpMatchesArray.h16
-rw-r--r--JavaScriptCore/runtime/RegExpObject.cpp31
-rw-r--r--JavaScriptCore/runtime/RopeImpl.cpp62
-rw-r--r--JavaScriptCore/runtime/RopeImpl.h88
-rw-r--r--JavaScriptCore/runtime/SmallStrings.cpp8
-rw-r--r--JavaScriptCore/runtime/SmallStrings.h4
-rw-r--r--JavaScriptCore/runtime/StringBuilder.h3
-rw-r--r--JavaScriptCore/runtime/StringConstructor.cpp5
-rw-r--r--JavaScriptCore/runtime/StringPrototype.cpp43
-rw-r--r--JavaScriptCore/runtime/Structure.cpp118
-rw-r--r--JavaScriptCore/runtime/Structure.h74
-rw-r--r--JavaScriptCore/runtime/StructureTransitionTable.h94
-rw-r--r--JavaScriptCore/runtime/Terminator.h47
-rw-r--r--JavaScriptCore/runtime/TimeoutChecker.cpp7
-rw-r--r--JavaScriptCore/runtime/UString.cpp274
-rw-r--r--JavaScriptCore/runtime/UString.h193
-rw-r--r--JavaScriptCore/runtime/UStringImpl.cpp119
-rw-r--r--JavaScriptCore/runtime/UStringImpl.h307
-rw-r--r--JavaScriptCore/runtime/WeakGCPtr.h15
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;
}