summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'JavaScriptCore/runtime')
-rw-r--r--JavaScriptCore/runtime/Arguments.cpp13
-rw-r--r--JavaScriptCore/runtime/Arguments.h3
-rw-r--r--JavaScriptCore/runtime/ArrayPrototype.cpp3
-rw-r--r--JavaScriptCore/runtime/BooleanObject.h2
-rw-r--r--JavaScriptCore/runtime/Collector.cpp742
-rw-r--r--JavaScriptCore/runtime/Collector.h146
-rw-r--r--JavaScriptCore/runtime/CollectorHeapIterator.h126
-rw-r--r--JavaScriptCore/runtime/CommonIdentifiers.h1
-rw-r--r--JavaScriptCore/runtime/Completion.cpp2
-rw-r--r--JavaScriptCore/runtime/DateConstructor.cpp8
-rw-r--r--JavaScriptCore/runtime/DateConversion.cpp26
-rw-r--r--JavaScriptCore/runtime/DateConversion.h14
-rw-r--r--JavaScriptCore/runtime/DateInstance.cpp6
-rw-r--r--JavaScriptCore/runtime/DateInstance.h3
-rw-r--r--JavaScriptCore/runtime/DatePrototype.cpp30
-rw-r--r--JavaScriptCore/runtime/DatePrototype.h2
-rw-r--r--JavaScriptCore/runtime/ErrorPrototype.cpp22
-rw-r--r--JavaScriptCore/runtime/ExceptionHelpers.cpp69
-rw-r--r--JavaScriptCore/runtime/Executable.cpp12
-rw-r--r--JavaScriptCore/runtime/FunctionConstructor.cpp22
-rw-r--r--JavaScriptCore/runtime/FunctionPrototype.cpp6
-rw-r--r--JavaScriptCore/runtime/FunctionPrototype.h2
-rw-r--r--JavaScriptCore/runtime/GetterSetter.h2
-rw-r--r--JavaScriptCore/runtime/GlobalEvalFunction.h2
-rw-r--r--JavaScriptCore/runtime/Identifier.cpp72
-rw-r--r--JavaScriptCore/runtime/Identifier.h66
-rw-r--r--JavaScriptCore/runtime/InitializeThreading.cpp5
-rw-r--r--JavaScriptCore/runtime/InternalFunction.h2
-rw-r--r--JavaScriptCore/runtime/JSAPIValueWrapper.h2
-rw-r--r--JavaScriptCore/runtime/JSActivation.h2
-rw-r--r--JavaScriptCore/runtime/JSArray.cpp34
-rw-r--r--JavaScriptCore/runtime/JSArray.h5
-rw-r--r--JavaScriptCore/runtime/JSByteArray.cpp16
-rw-r--r--JavaScriptCore/runtime/JSByteArray.h8
-rw-r--r--JavaScriptCore/runtime/JSCell.cpp9
-rw-r--r--JavaScriptCore/runtime/JSCell.h24
-rw-r--r--JavaScriptCore/runtime/JSFunction.cpp13
-rw-r--r--JavaScriptCore/runtime/JSFunction.h5
-rw-r--r--JavaScriptCore/runtime/JSGlobalData.cpp47
-rw-r--r--JavaScriptCore/runtime/JSGlobalData.h16
-rw-r--r--JavaScriptCore/runtime/JSGlobalObject.cpp2
-rw-r--r--JavaScriptCore/runtime/JSGlobalObject.h12
-rw-r--r--JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp40
-rw-r--r--JavaScriptCore/runtime/JSNotAnObject.cpp2
-rw-r--r--JavaScriptCore/runtime/JSNotAnObject.h4
-rw-r--r--JavaScriptCore/runtime/JSNumberCell.h2
-rw-r--r--JavaScriptCore/runtime/JSONObject.cpp29
-rw-r--r--JavaScriptCore/runtime/JSONObject.h2
-rw-r--r--JavaScriptCore/runtime/JSObject.cpp18
-rw-r--r--JavaScriptCore/runtime/JSObject.h26
-rw-r--r--JavaScriptCore/runtime/JSPropertyNameIterator.h2
-rw-r--r--JavaScriptCore/runtime/JSStaticScopeObject.h2
-rw-r--r--JavaScriptCore/runtime/JSString.cpp32
-rw-r--r--JavaScriptCore/runtime/JSString.h91
-rw-r--r--JavaScriptCore/runtime/JSValue.h3
-rw-r--r--JavaScriptCore/runtime/JSVariableObject.cpp6
-rw-r--r--JavaScriptCore/runtime/JSVariableObject.h4
-rw-r--r--JavaScriptCore/runtime/JSWrapperObject.h6
-rw-r--r--JavaScriptCore/runtime/LiteralParser.cpp24
-rw-r--r--JavaScriptCore/runtime/Lookup.cpp2
-rw-r--r--JavaScriptCore/runtime/Lookup.h2
-rw-r--r--JavaScriptCore/runtime/MarkStack.h2
-rw-r--r--JavaScriptCore/runtime/MarkStackNone.cpp49
-rw-r--r--JavaScriptCore/runtime/MarkStackPosix.cpp6
-rw-r--r--JavaScriptCore/runtime/MarkStackSymbian.cpp4
-rw-r--r--JavaScriptCore/runtime/MarkStackWin.cpp6
-rw-r--r--JavaScriptCore/runtime/MathObject.h2
-rw-r--r--JavaScriptCore/runtime/NumberConstructor.h2
-rw-r--r--JavaScriptCore/runtime/NumberObject.h2
-rw-r--r--JavaScriptCore/runtime/NumberPrototype.cpp52
-rw-r--r--JavaScriptCore/runtime/ObjectConstructor.cpp16
-rw-r--r--JavaScriptCore/runtime/ObjectPrototype.cpp2
-rw-r--r--JavaScriptCore/runtime/Operations.h57
-rw-r--r--JavaScriptCore/runtime/PropertyNameArray.cpp2
-rw-r--r--JavaScriptCore/runtime/RegExp.cpp1
-rw-r--r--JavaScriptCore/runtime/RegExp.h2
-rw-r--r--JavaScriptCore/runtime/RegExpConstructor.cpp2
-rw-r--r--JavaScriptCore/runtime/RegExpConstructor.h2
-rw-r--r--JavaScriptCore/runtime/RegExpMatchesArray.h4
-rw-r--r--JavaScriptCore/runtime/RegExpObject.cpp2
-rw-r--r--JavaScriptCore/runtime/RegExpObject.h2
-rw-r--r--JavaScriptCore/runtime/RegExpPrototype.cpp16
-rw-r--r--JavaScriptCore/runtime/SmallStrings.cpp22
-rw-r--r--JavaScriptCore/runtime/StringBuilder.h81
-rw-r--r--JavaScriptCore/runtime/StringConstructor.cpp12
-rw-r--r--JavaScriptCore/runtime/StringObject.cpp6
-rw-r--r--JavaScriptCore/runtime/StringObject.h4
-rw-r--r--JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h2
-rw-r--r--JavaScriptCore/runtime/StringPrototype.cpp94
-rw-r--r--JavaScriptCore/runtime/Structure.cpp124
-rw-r--r--JavaScriptCore/runtime/Structure.h41
-rw-r--r--JavaScriptCore/runtime/StructureTransitionTable.h53
-rw-r--r--JavaScriptCore/runtime/TimeoutChecker.cpp17
-rw-r--r--JavaScriptCore/runtime/Tracing.d2
-rw-r--r--JavaScriptCore/runtime/Tracing.h2
-rw-r--r--JavaScriptCore/runtime/UString.cpp927
-rw-r--r--JavaScriptCore/runtime/UString.h565
-rw-r--r--JavaScriptCore/runtime/UStringImpl.cpp82
-rw-r--r--JavaScriptCore/runtime/UStringImpl.h303
-rw-r--r--JavaScriptCore/runtime/WeakGCMap.h122
-rw-r--r--JavaScriptCore/runtime/WeakGCPtr.h128
101 files changed, 2480 insertions, 2241 deletions
diff --git a/JavaScriptCore/runtime/Arguments.cpp b/JavaScriptCore/runtime/Arguments.cpp
index 86a8f0a..bb30e3b 100644
--- a/JavaScriptCore/runtime/Arguments.cpp
+++ b/JavaScriptCore/runtime/Arguments.cpp
@@ -204,6 +204,19 @@ bool Arguments::getOwnPropertyDescriptor(ExecState* exec, const Identifier& prop
return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
}
+void Arguments::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ if (mode == IncludeDontEnumProperties) {
+ for (unsigned i = 0; i < d->numArguments; ++i) {
+ if (!d->deletedArguments || !d->deletedArguments[i])
+ propertyNames.add(Identifier(exec, UString::from(i)));
+ }
+ propertyNames.add(exec->propertyNames().callee);
+ propertyNames.add(exec->propertyNames().length);
+ }
+ JSObject::getOwnPropertyNames(exec, propertyNames, mode);
+}
+
void Arguments::put(ExecState* exec, unsigned i, JSValue value, PutPropertySlot& slot)
{
if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
diff --git a/JavaScriptCore/runtime/Arguments.h b/JavaScriptCore/runtime/Arguments.h
index 9b674a2..9797e08 100644
--- a/JavaScriptCore/runtime/Arguments.h
+++ b/JavaScriptCore/runtime/Arguments.h
@@ -85,7 +85,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
protected:
@@ -96,6 +96,7 @@ namespace JSC {
virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
+ virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
virtual void put(ExecState*, unsigned propertyName, JSValue, PutPropertySlot&);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
diff --git a/JavaScriptCore/runtime/ArrayPrototype.cpp b/JavaScriptCore/runtime/ArrayPrototype.cpp
index 5b359e7..ce814b2 100644
--- a/JavaScriptCore/runtime/ArrayPrototype.cpp
+++ b/JavaScriptCore/runtime/ArrayPrototype.cpp
@@ -204,8 +204,7 @@ JSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec, JSObject*, JSValue
buffer.append(rep->data(), rep->size());
}
ASSERT(buffer.size() == totalSize);
- unsigned finalSize = buffer.size();
- return jsString(exec, UString(buffer.releaseBuffer(), finalSize, false));
+ return jsString(exec, UString::adopt(buffer));
}
JSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
diff --git a/JavaScriptCore/runtime/BooleanObject.h b/JavaScriptCore/runtime/BooleanObject.h
index 69c2e51..4b02acb 100644
--- a/JavaScriptCore/runtime/BooleanObject.h
+++ b/JavaScriptCore/runtime/BooleanObject.h
@@ -34,7 +34,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
};
diff --git a/JavaScriptCore/runtime/Collector.cpp b/JavaScriptCore/runtime/Collector.cpp
index 1630a58..63139a2 100644
--- a/JavaScriptCore/runtime/Collector.cpp
+++ b/JavaScriptCore/runtime/Collector.cpp
@@ -45,7 +45,7 @@
#include <wtf/UnusedParam.h>
#include <wtf/VMTags.h>
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
#include <mach/mach_init.h>
#include <mach/mach_port.h>
@@ -53,29 +53,29 @@
#include <mach/thread_act.h>
#include <mach/vm_map.h>
-#elif PLATFORM(SYMBIAN)
+#elif OS(SYMBIAN)
#include <e32std.h>
#include <e32cmn.h>
#include <unistd.h>
-#elif PLATFORM(WIN_OS)
+#elif OS(WINDOWS)
#include <windows.h>
#include <malloc.h>
-#elif PLATFORM(HAIKU)
+#elif OS(HAIKU)
#include <OS.h>
-#elif PLATFORM(UNIX)
+#elif OS(UNIX)
#include <stdlib.h>
-#if !PLATFORM(HAIKU)
+#if !OS(HAIKU)
#include <sys/mman.h>
#endif
#include <unistd.h>
-#if PLATFORM(SOLARIS)
+#if OS(SOLARIS)
#include <thread.h>
#else
#include <pthread.h>
@@ -85,7 +85,7 @@
#include <pthread_np.h>
#endif
-#if PLATFORM(QNX)
+#if OS(QNX)
#include <fcntl.h>
#include <sys/procfs.h>
#include <stdio.h>
@@ -104,21 +104,21 @@ namespace JSC {
const size_t GROWTH_FACTOR = 2;
const size_t LOW_WATER_FACTOR = 4;
-const size_t ALLOCATIONS_PER_COLLECTION = 4000;
+const size_t ALLOCATIONS_PER_COLLECTION = 3600;
// This value has to be a macro to be used in max() without introducing
// a PIC branch in Mach-O binaries, see <rdar://problem/5971391>.
#define MIN_ARRAY_SIZE (static_cast<size_t>(14))
-#if PLATFORM(SYMBIAN)
+#if OS(SYMBIAN)
const size_t MAX_NUM_BLOCKS = 256; // Max size of collector heap set to 16 MB
static RHeap* userChunk = 0;
#endif
#if ENABLE(JSC_MULTIPLE_THREADS)
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
typedef mach_port_t PlatformThread;
-#elif PLATFORM(WIN_OS)
+#elif OS(WINDOWS)
typedef HANDLE PlatformThread;
#endif
@@ -148,8 +148,8 @@ Heap::Heap(JSGlobalData* globalData)
, m_globalData(globalData)
{
ASSERT(globalData);
-
-#if PLATFORM(SYMBIAN)
+
+#if OS(SYMBIAN)
// Symbian OpenC supports mmap but currently not the MAP_ANON flag.
// Using fastMalloc() does not properly align blocks on 64k boundaries
// and previous implementation was flawed/incomplete.
@@ -167,10 +167,10 @@ Heap::Heap(JSGlobalData* globalData)
if (!userChunk)
CRASH();
}
-#endif // PLATFORM(SYMBIAN)
+#endif // OS(SYMBIAN)
- memset(&primaryHeap, 0, sizeof(CollectorHeap));
- memset(&numberHeap, 0, sizeof(CollectorHeap));
+ memset(&m_heap, 0, sizeof(CollectorHeap));
+ allocateBlock();
}
Heap::~Heap()
@@ -186,6 +186,9 @@ void Heap::destroy()
if (!m_globalData)
return;
+ ASSERT(!m_globalData->dynamicGlobalObject);
+ ASSERT(!isBusy());
+
// The global object is not GC protected at this point, so sweeping may delete it
// (and thus the global data) before other objects that may use the global data.
RefPtr<JSGlobalData> protect(m_globalData);
@@ -193,15 +196,7 @@ void Heap::destroy()
delete m_markListSet;
m_markListSet = 0;
- sweep<PrimaryHeap>();
- // No need to sweep number heap, because the JSNumber destructor doesn't do anything.
-#if ENABLE(JSC_ZOMBIES)
- ASSERT(primaryHeap.numLiveObjects == primaryHeap.numZombies);
-#else
- ASSERT(!primaryHeap.numLiveObjects);
-#endif
- freeBlocks(&primaryHeap);
- freeBlocks(&numberHeap);
+ freeBlocks();
#if ENABLE(JSC_MULTIPLE_THREADS)
if (m_currentThreadRegistrar) {
@@ -220,24 +215,20 @@ void Heap::destroy()
m_globalData = 0;
}
-template <HeapType heapType>
NEVER_INLINE CollectorBlock* Heap::allocateBlock()
{
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
vm_address_t address = 0;
- // FIXME: tag the region as a JavaScriptCore heap when we get a registered VM tag: <rdar://problem/6054788>.
vm_map(current_task(), &address, BLOCK_SIZE, BLOCK_OFFSET_MASK, VM_FLAGS_ANYWHERE | VM_TAG_FOR_COLLECTOR_MEMORY, MEMORY_OBJECT_NULL, 0, FALSE, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_DEFAULT);
-#elif PLATFORM(SYMBIAN)
+#elif OS(SYMBIAN)
// Allocate a 64 kb aligned CollectorBlock
unsigned char* mask = reinterpret_cast<unsigned char*>(userChunk->Alloc(BLOCK_SIZE));
if (!mask)
CRASH();
uintptr_t address = reinterpret_cast<uintptr_t>(mask);
-
- memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE);
-#elif PLATFORM(WINCE)
+#elif OS(WINCE)
void* address = VirtualAlloc(NULL, BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
-#elif PLATFORM(WIN_OS)
+#elif OS(WINDOWS)
#if COMPILER(MINGW)
void* address = __mingw_aligned_malloc(BLOCK_SIZE, BLOCK_SIZE);
#else
@@ -247,7 +238,6 @@ NEVER_INLINE CollectorBlock* Heap::allocateBlock()
#elif HAVE(POSIX_MEMALIGN)
void* address;
posix_memalign(&address, BLOCK_SIZE, BLOCK_SIZE);
- memset(address, 0, BLOCK_SIZE);
#else
#if ENABLE(JSC_MULTIPLE_THREADS)
@@ -273,55 +263,63 @@ NEVER_INLINE CollectorBlock* Heap::allocateBlock()
munmap(reinterpret_cast<char*>(address + adjust + BLOCK_SIZE), extra - adjust);
address += adjust;
- memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE);
#endif
+ // Initialize block.
+
CollectorBlock* block = reinterpret_cast<CollectorBlock*>(address);
- block->freeList = block->cells;
block->heap = this;
- block->type = heapType;
+ clearMarkBits(block);
- CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
- size_t numBlocks = heap.numBlocks;
- if (heap.usedBlocks == numBlocks) {
+ Structure* dummyMarkableCellStructure = m_globalData->dummyMarkableCellStructure.get();
+ for (size_t i = 0; i < HeapConstants::cellsPerBlock; ++i)
+ new (block->cells + i) JSCell(dummyMarkableCellStructure);
+
+ // Add block to blocks vector.
+
+ size_t numBlocks = m_heap.numBlocks;
+ if (m_heap.usedBlocks == numBlocks) {
static const size_t maxNumBlocks = ULONG_MAX / sizeof(CollectorBlock*) / GROWTH_FACTOR;
if (numBlocks > maxNumBlocks)
CRASH();
numBlocks = max(MIN_ARRAY_SIZE, numBlocks * GROWTH_FACTOR);
- heap.numBlocks = numBlocks;
- heap.blocks = static_cast<CollectorBlock**>(fastRealloc(heap.blocks, numBlocks * sizeof(CollectorBlock*)));
+ m_heap.numBlocks = numBlocks;
+ m_heap.blocks = static_cast<CollectorBlock**>(fastRealloc(m_heap.blocks, numBlocks * sizeof(CollectorBlock*)));
}
- heap.blocks[heap.usedBlocks++] = block;
+ m_heap.blocks[m_heap.usedBlocks++] = block;
return block;
}
-template <HeapType heapType>
NEVER_INLINE void Heap::freeBlock(size_t block)
{
- CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
+ m_heap.didShrink = true;
- freeBlock(heap.blocks[block]);
+ ObjectIterator it(m_heap, block);
+ ObjectIterator end(m_heap, block + 1);
+ for ( ; it != end; ++it)
+ (*it)->~JSCell();
+ freeBlockPtr(m_heap.blocks[block]);
// swap with the last block so we compact as we go
- heap.blocks[block] = heap.blocks[heap.usedBlocks - 1];
- heap.usedBlocks--;
+ m_heap.blocks[block] = m_heap.blocks[m_heap.usedBlocks - 1];
+ m_heap.usedBlocks--;
- if (heap.numBlocks > MIN_ARRAY_SIZE && heap.usedBlocks < heap.numBlocks / LOW_WATER_FACTOR) {
- heap.numBlocks = heap.numBlocks / GROWTH_FACTOR;
- heap.blocks = static_cast<CollectorBlock**>(fastRealloc(heap.blocks, heap.numBlocks * sizeof(CollectorBlock*)));
+ if (m_heap.numBlocks > MIN_ARRAY_SIZE && m_heap.usedBlocks < m_heap.numBlocks / LOW_WATER_FACTOR) {
+ m_heap.numBlocks = m_heap.numBlocks / GROWTH_FACTOR;
+ m_heap.blocks = static_cast<CollectorBlock**>(fastRealloc(m_heap.blocks, m_heap.numBlocks * sizeof(CollectorBlock*)));
}
}
-NEVER_INLINE void Heap::freeBlock(CollectorBlock* block)
+NEVER_INLINE void Heap::freeBlockPtr(CollectorBlock* block)
{
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
vm_deallocate(current_task(), reinterpret_cast<vm_address_t>(block), BLOCK_SIZE);
-#elif PLATFORM(SYMBIAN)
+#elif OS(SYMBIAN)
userChunk->Free(reinterpret_cast<TAny*>(block));
-#elif PLATFORM(WINCE)
+#elif OS(WINCE)
VirtualFree(block, 0, MEM_RELEASE);
-#elif PLATFORM(WIN_OS)
+#elif OS(WINDOWS)
#if COMPILER(MINGW)
__mingw_aligned_free(block);
#else
@@ -334,13 +332,34 @@ NEVER_INLINE void Heap::freeBlock(CollectorBlock* block)
#endif
}
-void Heap::freeBlocks(CollectorHeap* heap)
+void Heap::freeBlocks()
{
- for (size_t i = 0; i < heap->usedBlocks; ++i)
- if (heap->blocks[i])
- freeBlock(heap->blocks[i]);
- fastFree(heap->blocks);
- memset(heap, 0, sizeof(CollectorHeap));
+ ProtectCountSet protectedValuesCopy = m_protectedValues;
+
+ clearMarkBits();
+ ProtectCountSet::iterator protectedValuesEnd = protectedValuesCopy.end();
+ for (ProtectCountSet::iterator it = protectedValuesCopy.begin(); it != protectedValuesEnd; ++it)
+ markCell(it->first);
+
+ m_heap.nextCell = 0;
+ m_heap.nextBlock = 0;
+ DeadObjectIterator it(m_heap, m_heap.nextBlock, m_heap.nextCell);
+ DeadObjectIterator end(m_heap, m_heap.usedBlocks);
+ for ( ; it != end; ++it)
+ (*it)->~JSCell();
+
+ ASSERT(!protectedObjectCount());
+
+ protectedValuesEnd = protectedValuesCopy.end();
+ for (ProtectCountSet::iterator it = protectedValuesCopy.begin(); it != protectedValuesEnd; ++it)
+ it->first->~JSCell();
+
+ for (size_t block = 0; block < m_heap.usedBlocks; ++block)
+ freeBlockPtr(m_heap.blocks[block]);
+
+ fastFree(m_heap.blocks);
+
+ memset(&m_heap, 0, sizeof(CollectorHeap));
}
void Heap::recordExtraCost(size_t cost)
@@ -355,123 +374,109 @@ void Heap::recordExtraCost(size_t cost)
// are either very short lived temporaries, or have extremely long lifetimes. So
// if a large value survives one garbage collection, there is not much point to
// collecting more frequently as long as it stays alive.
- // NOTE: we target the primaryHeap unconditionally as JSNumber doesn't modify cost
- primaryHeap.extraCost += cost;
+ if (m_heap.extraCost > maxExtraCost && m_heap.extraCost > m_heap.usedBlocks * BLOCK_SIZE / 2) {
+ // If the last iteration through the heap deallocated blocks, we need
+ // to clean up remaining garbage before marking. Otherwise, the conservative
+ // marking mechanism might follow a pointer to unmapped memory.
+ if (m_heap.didShrink)
+ sweep();
+ reset();
+ }
+ m_heap.extraCost += cost;
}
-template <HeapType heapType> ALWAYS_INLINE void* Heap::heapAllocate(size_t s)
+void* Heap::allocate(size_t s)
{
- typedef typename HeapConstants<heapType>::Block Block;
- typedef typename HeapConstants<heapType>::Cell Cell;
-
- CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
+ typedef HeapConstants::Block Block;
+ typedef HeapConstants::Cell Cell;
+
ASSERT(JSLock::lockCount() > 0);
ASSERT(JSLock::currentThreadIsHoldingLock());
- ASSERT_UNUSED(s, s <= HeapConstants<heapType>::cellSize);
+ ASSERT_UNUSED(s, s <= HeapConstants::cellSize);
- ASSERT(heap.operationInProgress == NoOperation);
- ASSERT(heapType == PrimaryHeap || heap.extraCost == 0);
- // FIXME: If another global variable access here doesn't hurt performance
- // too much, we could CRASH() in NDEBUG builds, which could help ensure we
- // don't spend any time debugging cases where we allocate inside an object's
- // deallocation code.
+ ASSERT(m_heap.operationInProgress == NoOperation);
#if COLLECT_ON_EVERY_ALLOCATION
- collect();
+ collectAllGarbage();
+ ASSERT(m_heap.operationInProgress == NoOperation);
#endif
- size_t numLiveObjects = heap.numLiveObjects;
- size_t usedBlocks = heap.usedBlocks;
- size_t i = heap.firstBlockWithPossibleSpace;
-
- // if we have a huge amount of extra cost, we'll try to collect even if we still have
- // free cells left.
- if (heapType == PrimaryHeap && heap.extraCost > ALLOCATIONS_PER_COLLECTION) {
- size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect;
- size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect;
- const size_t newCost = numNewObjects + heap.extraCost;
- if (newCost >= ALLOCATIONS_PER_COLLECTION && newCost >= numLiveObjectsAtLastCollect)
- goto collect;
- }
+allocate:
- ASSERT(heap.operationInProgress == NoOperation);
-#ifndef NDEBUG
- // FIXME: Consider doing this in NDEBUG builds too (see comment above).
- heap.operationInProgress = Allocation;
-#endif
+ // Fast case: find the next garbage cell and recycle it.
-scan:
- Block* targetBlock;
- size_t targetBlockUsedCells;
- if (i != usedBlocks) {
- targetBlock = reinterpret_cast<Block*>(heap.blocks[i]);
- targetBlockUsedCells = targetBlock->usedCells;
- ASSERT(targetBlockUsedCells <= HeapConstants<heapType>::cellsPerBlock);
- while (targetBlockUsedCells == HeapConstants<heapType>::cellsPerBlock) {
- if (++i == usedBlocks)
- goto collect;
- targetBlock = reinterpret_cast<Block*>(heap.blocks[i]);
- targetBlockUsedCells = targetBlock->usedCells;
- ASSERT(targetBlockUsedCells <= HeapConstants<heapType>::cellsPerBlock);
- }
- heap.firstBlockWithPossibleSpace = i;
- } else {
+ do {
+ ASSERT(m_heap.nextBlock < m_heap.usedBlocks);
+ Block* block = reinterpret_cast<Block*>(m_heap.blocks[m_heap.nextBlock]);
+ do {
+ ASSERT(m_heap.nextCell < HeapConstants::cellsPerBlock);
+ if (!block->marked.get(m_heap.nextCell)) { // Always false for the last cell in the block
+ Cell* cell = block->cells + m_heap.nextCell;
-collect:
- size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect;
- size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect;
- const size_t newCost = numNewObjects + heap.extraCost;
+ m_heap.operationInProgress = Allocation;
+ JSCell* imp = reinterpret_cast<JSCell*>(cell);
+ imp->~JSCell();
+ m_heap.operationInProgress = NoOperation;
- if (newCost >= ALLOCATIONS_PER_COLLECTION && newCost >= numLiveObjectsAtLastCollect) {
-#ifndef NDEBUG
- heap.operationInProgress = NoOperation;
-#endif
- bool foundGarbage = collect();
- numLiveObjects = heap.numLiveObjects;
- usedBlocks = heap.usedBlocks;
- i = heap.firstBlockWithPossibleSpace;
-#ifndef NDEBUG
- heap.operationInProgress = Allocation;
-#endif
- if (foundGarbage)
- goto scan;
- }
+ ++m_heap.nextCell;
+ return cell;
+ }
+ } while (++m_heap.nextCell != HeapConstants::cellsPerBlock);
+ m_heap.nextCell = 0;
+ } while (++m_heap.nextBlock != m_heap.usedBlocks);
- // didn't find a block, and GC didn't reclaim anything, need to allocate a new block
- targetBlock = reinterpret_cast<Block*>(allocateBlock<heapType>());
- heap.firstBlockWithPossibleSpace = heap.usedBlocks - 1;
- targetBlockUsedCells = 0;
- }
+ // Slow case: reached the end of the heap. Mark live objects and start over.
- // find a free spot in the block and detach it from the free list
- Cell* newCell = targetBlock->freeList;
+ reset();
+ goto allocate;
+}
- // "next" field is a cell offset -- 0 means next cell, so a zeroed block is already initialized
- targetBlock->freeList = (newCell + 1) + newCell->u.freeCell.next;
+void Heap::resizeBlocks()
+{
+ m_heap.didShrink = false;
- targetBlock->usedCells = static_cast<uint32_t>(targetBlockUsedCells + 1);
- heap.numLiveObjects = numLiveObjects + 1;
+ size_t usedCellCount = markedCells();
+ size_t minCellCount = usedCellCount + max(ALLOCATIONS_PER_COLLECTION, usedCellCount);
+ size_t minBlockCount = (minCellCount + HeapConstants::cellsPerBlock - 1) / HeapConstants::cellsPerBlock;
-#ifndef NDEBUG
- // FIXME: Consider doing this in NDEBUG builds too (see comment above).
- heap.operationInProgress = NoOperation;
-#endif
+ size_t maxCellCount = 1.25f * minCellCount;
+ size_t maxBlockCount = (maxCellCount + HeapConstants::cellsPerBlock - 1) / HeapConstants::cellsPerBlock;
- return newCell;
+ if (m_heap.usedBlocks < minBlockCount)
+ growBlocks(minBlockCount);
+ else if (m_heap.usedBlocks > maxBlockCount)
+ shrinkBlocks(maxBlockCount);
}
-void* Heap::allocate(size_t s)
+void Heap::growBlocks(size_t neededBlocks)
{
- return heapAllocate<PrimaryHeap>(s);
+ ASSERT(m_heap.usedBlocks < neededBlocks);
+ while (m_heap.usedBlocks < neededBlocks)
+ allocateBlock();
}
-void* Heap::allocateNumber(size_t s)
+void Heap::shrinkBlocks(size_t neededBlocks)
{
- return heapAllocate<NumberHeap>(s);
+ ASSERT(m_heap.usedBlocks > neededBlocks);
+
+ // Clear the always-on last bit, so isEmpty() isn't fooled by it.
+ for (size_t i = 0; i < m_heap.usedBlocks; ++i)
+ m_heap.blocks[i]->marked.clear(HeapConstants::cellsPerBlock - 1);
+
+ for (size_t i = 0; i != m_heap.usedBlocks && m_heap.usedBlocks != neededBlocks; ) {
+ if (m_heap.blocks[i]->marked.isEmpty()) {
+ freeBlock(i);
+ } else
+ ++i;
+ }
+
+ // Reset the always-on last bit.
+ for (size_t i = 0; i < m_heap.usedBlocks; ++i)
+ m_heap.blocks[i]->marked.set(HeapConstants::cellsPerBlock - 1);
}
-#if PLATFORM(WINCE)
+#if OS(WINCE)
void* g_stackBase = 0;
inline bool isPageWritable(void* page)
@@ -528,7 +533,7 @@ static void* getStackBase(void* previousFrame)
}
#endif
-#if PLATFORM(QNX)
+#if OS(QNX)
static inline void *currentThreadStackBaseQNX()
{
static void* stackBase = 0;
@@ -557,10 +562,10 @@ static inline void *currentThreadStackBaseQNX()
static inline void* currentThreadStackBase()
{
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
pthread_t thread = pthread_self();
return pthread_get_stackaddr_np(thread);
-#elif PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(MSVC)
+#elif OS(WINDOWS) && CPU(X86) && COMPILER(MSVC)
// offset 0x18 from the FS segment register gives a pointer to
// the thread information block for the current thread
NT_TIB* pTib;
@@ -569,10 +574,11 @@ static inline void* currentThreadStackBase()
MOV pTib, EAX
}
return static_cast<void*>(pTib->StackBase);
-#elif PLATFORM(WIN_OS) && PLATFORM(X86_64) && COMPILER(MSVC)
+#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 PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(GCC)
+#elif OS(WINDOWS) && CPU(X86) && COMPILER(GCC)
// offset 0x18 from the FS segment register gives a pointer to
// the thread information block for the current thread
NT_TIB* pTib;
@@ -580,18 +586,18 @@ static inline void* currentThreadStackBase()
: "=r" (pTib)
);
return static_cast<void*>(pTib->StackBase);
-#elif PLATFORM(QNX)
+#elif OS(QNX)
return currentThreadStackBaseQNX();
-#elif PLATFORM(SOLARIS)
+#elif OS(SOLARIS)
stack_t s;
thr_stksegment(&s);
return s.ss_sp;
-#elif PLATFORM(OPENBSD)
+#elif OS(OPENBSD)
pthread_t thread = pthread_self();
stack_t stack;
pthread_stackseg_np(thread, &stack);
return stack.ss_sp;
-#elif PLATFORM(SYMBIAN)
+#elif OS(SYMBIAN)
static void* stackBase = 0;
if (stackBase == 0) {
TThreadStackInfo info;
@@ -600,11 +606,11 @@ static inline void* currentThreadStackBase()
stackBase = (void*)info.iBase;
}
return (void*)stackBase;
-#elif PLATFORM(HAIKU)
+#elif OS(HAIKU)
thread_info threadInfo;
get_thread_info(find_thread(NULL), &threadInfo);
return threadInfo.stack_end;
-#elif PLATFORM(UNIX)
+#elif OS(UNIX)
static void* stackBase = 0;
static size_t stackSize = 0;
static pthread_t stackThread;
@@ -612,7 +618,7 @@ static inline void* currentThreadStackBase()
if (stackBase == 0 || thread != stackThread) {
pthread_attr_t sattr;
pthread_attr_init(&sattr);
-#if HAVE(PTHREAD_NP_H) || PLATFORM(NETBSD)
+#if HAVE(PTHREAD_NP_H) || OS(NETBSD)
// e.g. on FreeBSD 5.4, neundorf@kde.org
pthread_attr_get_np(thread, &sattr);
#else
@@ -626,7 +632,7 @@ static inline void* currentThreadStackBase()
stackThread = thread;
}
return static_cast<char*>(stackBase) + stackSize;
-#elif PLATFORM(WINCE)
+#elif OS(WINCE)
if (g_stackBase)
return g_stackBase;
else {
@@ -642,9 +648,9 @@ static inline void* currentThreadStackBase()
static inline PlatformThread getCurrentPlatformThread()
{
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
return pthread_mach_thread_np(pthread_self());
-#elif PLATFORM(WIN_OS)
+#elif OS(WINDOWS)
return pthread_getw32threadhandle_np(pthread_self());
#endif
}
@@ -714,10 +720,37 @@ void Heap::registerThread()
#endif
-#define IS_POINTER_ALIGNED(p) (((intptr_t)(p) & (sizeof(char*) - 1)) == 0)
+inline bool isPointerAligned(void* p)
+{
+ return (((intptr_t)(p) & (sizeof(char*) - 1)) == 0);
+}
+
+// Cell size needs to be a power of two for isPossibleCell to be valid.
+COMPILE_ASSERT(sizeof(CollectorCell) % 2 == 0, Collector_cell_size_is_power_of_two);
+
+#if USE(JSVALUE32)
+static bool isHalfCellAligned(void *p)
+{
+ return (((intptr_t)(p) & (CELL_MASK >> 1)) == 0);
+}
+
+static inline bool isPossibleCell(void* p)
+{
+ return isHalfCellAligned(p) && p;
+}
+
+#else
+
+static inline bool isCellAligned(void *p)
+{
+ return (((intptr_t)(p) & CELL_MASK) == 0);
+}
-// cell size needs to be a power of two for this to be valid
-#define IS_HALF_CELL_ALIGNED(p) (((intptr_t)(p) & (CELL_MASK >> 1)) == 0)
+static inline bool isPossibleCell(void* p)
+{
+ return isCellAligned(p) && p;
+}
+#endif // USE(JSVALUE32)
void Heap::markConservatively(MarkStack& markStack, void* start, void* end)
{
@@ -728,46 +761,33 @@ void Heap::markConservatively(MarkStack& markStack, void* start, void* end)
}
ASSERT((static_cast<char*>(end) - static_cast<char*>(start)) < 0x1000000);
- ASSERT(IS_POINTER_ALIGNED(start));
- ASSERT(IS_POINTER_ALIGNED(end));
+ ASSERT(isPointerAligned(start));
+ ASSERT(isPointerAligned(end));
char** p = static_cast<char**>(start);
char** e = static_cast<char**>(end);
- size_t usedPrimaryBlocks = primaryHeap.usedBlocks;
- size_t usedNumberBlocks = numberHeap.usedBlocks;
- CollectorBlock** primaryBlocks = primaryHeap.blocks;
- CollectorBlock** numberBlocks = numberHeap.blocks;
-
- const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1);
-
+ CollectorBlock** blocks = m_heap.blocks;
while (p != e) {
char* x = *p++;
- if (IS_HALF_CELL_ALIGNED(x) && x) {
+ if (isPossibleCell(x)) {
+ size_t usedBlocks;
uintptr_t xAsBits = reinterpret_cast<uintptr_t>(x);
xAsBits &= CELL_ALIGN_MASK;
+
uintptr_t offset = xAsBits & BLOCK_OFFSET_MASK;
+ const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1);
+ if (offset > lastCellOffset)
+ continue;
+
CollectorBlock* blockAddr = reinterpret_cast<CollectorBlock*>(xAsBits - offset);
- // Mark the the number heap, we can mark these Cells directly to avoid the virtual call cost
- for (size_t block = 0; block < usedNumberBlocks; block++) {
- if ((numberBlocks[block] == blockAddr) & (offset <= lastCellOffset)) {
- Heap::markCell(reinterpret_cast<JSCell*>(xAsBits));
- goto endMarkLoop;
- }
- }
-
- // Mark the primary heap
- for (size_t block = 0; block < usedPrimaryBlocks; block++) {
- if ((primaryBlocks[block] == blockAddr) & (offset <= lastCellOffset)) {
- if (reinterpret_cast<CollectorCell*>(xAsBits)->u.freeCell.zeroIfFree) {
- markStack.append(reinterpret_cast<JSCell*>(xAsBits));
- markStack.drain();
- }
- break;
- }
+ usedBlocks = m_heap.usedBlocks;
+ for (size_t block = 0; block < usedBlocks; block++) {
+ if (blocks[block] != blockAddr)
+ continue;
+ markStack.append(reinterpret_cast<JSCell*>(xAsBits));
+ markStack.drain();
}
- endMarkLoop:
- ;
}
}
}
@@ -806,9 +826,9 @@ void Heap::markCurrentThreadConservatively(MarkStack& markStack)
static inline void suspendThread(const PlatformThread& platformThread)
{
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
thread_suspend(platformThread);
-#elif PLATFORM(WIN_OS)
+#elif OS(WINDOWS)
SuspendThread(platformThread);
#else
#error Need a way to suspend threads on this platform
@@ -817,9 +837,9 @@ static inline void suspendThread(const PlatformThread& platformThread)
static inline void resumeThread(const PlatformThread& platformThread)
{
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
thread_resume(platformThread);
-#elif PLATFORM(WIN_OS)
+#elif OS(WINDOWS)
ResumeThread(platformThread);
#else
#error Need a way to resume threads on this platform
@@ -828,23 +848,23 @@ static inline void resumeThread(const PlatformThread& platformThread)
typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
-#if PLATFORM(X86)
+#if CPU(X86)
typedef i386_thread_state_t PlatformThreadRegisters;
-#elif PLATFORM(X86_64)
+#elif CPU(X86_64)
typedef x86_thread_state64_t PlatformThreadRegisters;
-#elif PLATFORM(PPC)
+#elif CPU(PPC)
typedef ppc_thread_state_t PlatformThreadRegisters;
-#elif PLATFORM(PPC64)
+#elif CPU(PPC64)
typedef ppc_thread_state64_t PlatformThreadRegisters;
-#elif PLATFORM(ARM)
+#elif CPU(ARM)
typedef arm_thread_state_t PlatformThreadRegisters;
#else
#error Unknown Architecture
#endif
-#elif PLATFORM(WIN_OS)&& PLATFORM(X86)
+#elif OS(WINDOWS) && CPU(X86)
typedef CONTEXT PlatformThreadRegisters;
#else
#error Need a thread register struct for this platform
@@ -852,21 +872,21 @@ typedef CONTEXT PlatformThreadRegisters;
static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, PlatformThreadRegisters& regs)
{
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
-#if PLATFORM(X86)
+#if CPU(X86)
unsigned user_count = sizeof(regs)/sizeof(int);
thread_state_flavor_t flavor = i386_THREAD_STATE;
-#elif PLATFORM(X86_64)
+#elif CPU(X86_64)
unsigned user_count = x86_THREAD_STATE64_COUNT;
thread_state_flavor_t flavor = x86_THREAD_STATE64;
-#elif PLATFORM(PPC)
+#elif CPU(PPC)
unsigned user_count = PPC_THREAD_STATE_COUNT;
thread_state_flavor_t flavor = PPC_THREAD_STATE;
-#elif PLATFORM(PPC64)
+#elif CPU(PPC64)
unsigned user_count = PPC_THREAD_STATE64_COUNT;
thread_state_flavor_t flavor = PPC_THREAD_STATE64;
-#elif PLATFORM(ARM)
+#elif CPU(ARM)
unsigned user_count = ARM_THREAD_STATE_COUNT;
thread_state_flavor_t flavor = ARM_THREAD_STATE;
#else
@@ -880,9 +900,9 @@ static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, P
CRASH();
}
return user_count * sizeof(usword_t);
-// end PLATFORM(DARWIN)
+// end OS(DARWIN)
-#elif PLATFORM(WIN_OS) && PLATFORM(X86)
+#elif OS(WINDOWS) && CPU(X86)
regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS;
GetThreadContext(platformThread, &regs);
return sizeof(CONTEXT);
@@ -893,17 +913,17 @@ static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, P
static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs)
{
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
#if __DARWIN_UNIX03
-#if PLATFORM(X86)
+#if CPU(X86)
return reinterpret_cast<void*>(regs.__esp);
-#elif PLATFORM(X86_64)
+#elif CPU(X86_64)
return reinterpret_cast<void*>(regs.__rsp);
-#elif PLATFORM(PPC) || PLATFORM(PPC64)
+#elif CPU(PPC) || CPU(PPC64)
return reinterpret_cast<void*>(regs.__r1);
-#elif PLATFORM(ARM)
+#elif CPU(ARM)
return reinterpret_cast<void*>(regs.__sp);
#else
#error Unknown Architecture
@@ -911,11 +931,11 @@ static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs)
#else // !__DARWIN_UNIX03
-#if PLATFORM(X86)
+#if CPU(X86)
return reinterpret_cast<void*>(regs.esp);
-#elif PLATFORM(X86_64)
+#elif CPU(X86_64)
return reinterpret_cast<void*>(regs.rsp);
-#elif (PLATFORM(PPC) || PLATFORM(PPC64))
+#elif CPU(PPC) || CPU(PPC64)
return reinterpret_cast<void*>(regs.r1);
#else
#error Unknown Architecture
@@ -923,8 +943,8 @@ static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs)
#endif // __DARWIN_UNIX03
-// end PLATFORM(DARWIN)
-#elif PLATFORM(X86) && PLATFORM(WIN_OS)
+// end OS(DARWIN)
+#elif CPU(X86) && OS(WINDOWS)
return reinterpret_cast<void*>((uintptr_t) regs.Esp);
#else
#error Need a way to get the stack pointer for another thread on this platform
@@ -1009,129 +1029,68 @@ void Heap::markProtectedObjects(MarkStack& markStack)
}
}
-template <HeapType heapType> size_t Heap::sweep()
+void Heap::clearMarkBits()
{
- typedef typename HeapConstants<heapType>::Block Block;
- typedef typename HeapConstants<heapType>::Cell Cell;
+ for (size_t i = 0; i < m_heap.usedBlocks; ++i)
+ clearMarkBits(m_heap.blocks[i]);
+}
- // SWEEP: delete everything with a zero refcount (garbage) and unmark everything else
- CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
-
- size_t emptyBlocks = 0;
- size_t numLiveObjects = heap.numLiveObjects;
+void Heap::clearMarkBits(CollectorBlock* block)
+{
+ // allocate assumes that the last cell in every block is marked.
+ block->marked.clearAll();
+ block->marked.set(HeapConstants::cellsPerBlock - 1);
+}
+
+size_t Heap::markedCells(size_t startBlock, size_t startCell) const
+{
+ ASSERT(startBlock <= m_heap.usedBlocks);
+ ASSERT(startCell < HeapConstants::cellsPerBlock);
+
+ if (startBlock >= m_heap.usedBlocks)
+ return 0;
+
+ size_t result = 0;
+ result += m_heap.blocks[startBlock]->marked.count(startCell);
+ for (size_t i = startBlock + 1; i < m_heap.usedBlocks; ++i)
+ result += m_heap.blocks[i]->marked.count();
+
+ return result;
+}
+
+void Heap::sweep()
+{
+ ASSERT(m_heap.operationInProgress == NoOperation);
+ if (m_heap.operationInProgress != NoOperation)
+ CRASH();
+ m_heap.operationInProgress = Collection;
- for (size_t block = 0; block < heap.usedBlocks; block++) {
- Block* curBlock = reinterpret_cast<Block*>(heap.blocks[block]);
-
- size_t usedCells = curBlock->usedCells;
- Cell* freeList = curBlock->freeList;
-
- if (usedCells == HeapConstants<heapType>::cellsPerBlock) {
- // special case with a block where all cells are used -- testing indicates this happens often
- for (size_t i = 0; i < HeapConstants<heapType>::cellsPerBlock; i++) {
- if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) {
- Cell* cell = curBlock->cells + i;
-
- if (heapType != NumberHeap) {
- JSCell* imp = reinterpret_cast<JSCell*>(cell);
- // special case for allocated but uninitialized object
- // (We don't need this check earlier because nothing prior this point
- // assumes the object has a valid vptr.)
- if (cell->u.freeCell.zeroIfFree == 0)
- continue;
-#if ENABLE(JSC_ZOMBIES)
- if (!imp->isZombie()) {
- const ClassInfo* info = imp->classInfo();
- imp->~JSCell();
- new (imp) JSZombie(info, JSZombie::leakedZombieStructure());
- heap.numZombies++;
- }
-#else
- imp->~JSCell();
-#endif
- }
- --numLiveObjects;
#if !ENABLE(JSC_ZOMBIES)
- --usedCells;
-
- // put cell on the free list
- cell->u.freeCell.zeroIfFree = 0;
- cell->u.freeCell.next = freeList - (cell + 1);
- freeList = cell;
+ Structure* dummyMarkableCellStructure = m_globalData->dummyMarkableCellStructure.get();
#endif
- }
- }
- } else {
- size_t minimumCellsToProcess = usedCells;
- for (size_t i = 0; (i < minimumCellsToProcess) & (i < HeapConstants<heapType>::cellsPerBlock); i++) {
- Cell* cell = curBlock->cells + i;
- if (cell->u.freeCell.zeroIfFree == 0) {
- ++minimumCellsToProcess;
- } else {
- if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) {
- if (heapType != NumberHeap) {
- JSCell* imp = reinterpret_cast<JSCell*>(cell);
+
+ DeadObjectIterator it(m_heap, m_heap.nextBlock, m_heap.nextCell);
+ DeadObjectIterator end(m_heap, m_heap.usedBlocks);
+ for ( ; it != end; ++it) {
+ JSCell* cell = *it;
#if ENABLE(JSC_ZOMBIES)
- if (!imp->isZombie()) {
- const ClassInfo* info = imp->classInfo();
- imp->~JSCell();
- new (imp) JSZombie(info, JSZombie::leakedZombieStructure());
- heap.numZombies++;
- }
+ if (!cell->isZombie()) {
+ const ClassInfo* info = cell->classInfo();
+ cell->~JSCell();
+ new (cell) JSZombie(info, JSZombie::leakedZombieStructure());
+ Heap::markCell(cell);
+ }
#else
- imp->~JSCell();
+ cell->~JSCell();
+ // Callers of sweep assume it's safe to mark any cell in the heap.
+ new (cell) JSCell(dummyMarkableCellStructure);
#endif
- }
-#if !ENABLE(JSC_ZOMBIES)
- --usedCells;
- --numLiveObjects;
-
- // put cell on the free list
- cell->u.freeCell.zeroIfFree = 0;
- cell->u.freeCell.next = freeList - (cell + 1);
- freeList = cell;
-#endif
- }
- }
- }
- }
-
- curBlock->usedCells = static_cast<uint32_t>(usedCells);
- curBlock->freeList = freeList;
- curBlock->marked.clearAll();
-
- if (!usedCells)
- ++emptyBlocks;
}
-
- if (heap.numLiveObjects != numLiveObjects)
- heap.firstBlockWithPossibleSpace = 0;
-
- heap.numLiveObjects = numLiveObjects;
- heap.numLiveObjectsAtLastCollect = numLiveObjects;
- heap.extraCost = 0;
-
- if (!emptyBlocks)
- return numLiveObjects;
-
- size_t neededCells = 1.25f * (numLiveObjects + max(ALLOCATIONS_PER_COLLECTION, numLiveObjects));
- size_t neededBlocks = (neededCells + HeapConstants<heapType>::cellsPerBlock - 1) / HeapConstants<heapType>::cellsPerBlock;
- for (size_t block = 0; block < heap.usedBlocks; block++) {
- if (heap.usedBlocks <= neededBlocks)
- break;
- Block* curBlock = reinterpret_cast<Block*>(heap.blocks[block]);
- if (curBlock->usedCells)
- continue;
-
- freeBlock<heapType>(block);
- block--; // Don't move forward a step in this case
- }
-
- return numLiveObjects;
+ m_heap.operationInProgress = NoOperation;
}
-bool Heap::collect()
+void Heap::markRoots()
{
#ifndef NDEBUG
if (m_globalData->isSharedInstance) {
@@ -1140,23 +1099,29 @@ bool Heap::collect()
}
#endif
- ASSERT((primaryHeap.operationInProgress == NoOperation) | (numberHeap.operationInProgress == NoOperation));
- if ((primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation))
+ ASSERT(m_heap.operationInProgress == NoOperation);
+ if (m_heap.operationInProgress != NoOperation)
CRASH();
- JAVASCRIPTCORE_GC_BEGIN();
- primaryHeap.operationInProgress = Collection;
- numberHeap.operationInProgress = Collection;
+ m_heap.operationInProgress = Collection;
- // MARK: first mark all referenced objects recursively starting out from the set of root objects
MarkStack& markStack = m_globalData->markStack;
+
+ // Reset mark bits.
+ clearMarkBits();
+
+ // Mark stack roots.
markStackObjectsConservatively(markStack);
+ m_globalData->interpreter->registerFile().markCallFrames(markStack, this);
+
+ // Mark explicitly registered roots.
markProtectedObjects(markStack);
+
+ // Mark misc. other roots.
if (m_markListSet && m_markListSet->size())
MarkedArgumentBuffer::markLists(markStack, *m_markListSet);
if (m_globalData->exception)
markStack.append(m_globalData->exception);
- m_globalData->interpreter->registerFile().markCallFrames(markStack, this);
m_globalData->smallStrings.markChildren(markStack);
if (m_globalData->functionCodeBlockBeingReparsed)
m_globalData->functionCodeBlockBeingReparsed->markAggregate(markStack);
@@ -1165,41 +1130,28 @@ bool Heap::collect()
markStack.drain();
markStack.compact();
- JAVASCRIPTCORE_GC_MARKED();
-
- size_t originalLiveObjects = primaryHeap.numLiveObjects + numberHeap.numLiveObjects;
- size_t numLiveObjects = sweep<PrimaryHeap>();
- numLiveObjects += sweep<NumberHeap>();
- primaryHeap.operationInProgress = NoOperation;
- numberHeap.operationInProgress = NoOperation;
- JAVASCRIPTCORE_GC_END(originalLiveObjects, numLiveObjects);
-
- return numLiveObjects < originalLiveObjects;
+ m_heap.operationInProgress = NoOperation;
}
-size_t Heap::objectCount()
+size_t Heap::objectCount() const
{
- return primaryHeap.numLiveObjects + numberHeap.numLiveObjects - m_globalData->smallStrings.count();
+ return m_heap.nextBlock * HeapConstants::cellsPerBlock // allocated full blocks
+ + m_heap.nextCell // allocated cells in current block
+ + markedCells(m_heap.nextBlock, m_heap.nextCell) // marked cells in remainder of m_heap
+ - m_heap.usedBlocks; // 1 cell per block is a dummy sentinel
}
-template <HeapType heapType>
-static void addToStatistics(Heap::Statistics& statistics, const CollectorHeap& heap)
+void Heap::addToStatistics(Heap::Statistics& statistics) const
{
- typedef HeapConstants<heapType> HC;
- for (size_t i = 0; i < heap.usedBlocks; ++i) {
- if (heap.blocks[i]) {
- statistics.size += BLOCK_SIZE;
- statistics.free += (HC::cellsPerBlock - heap.blocks[i]->usedCells) * HC::cellSize;
- }
- }
+ statistics.size += m_heap.usedBlocks * BLOCK_SIZE;
+ statistics.free += m_heap.usedBlocks * BLOCK_SIZE - (objectCount() * HeapConstants::cellSize);
}
Heap::Statistics Heap::statistics() const
{
Statistics statistics = { 0, 0 };
- JSC::addToStatistics<PrimaryHeap>(statistics, primaryHeap);
- JSC::addToStatistics<NumberHeap>(statistics, numberHeap);
+ addToStatistics(statistics);
return statistics;
}
@@ -1268,17 +1220,61 @@ HashCountedSet<const char*>* Heap::protectedObjectTypeCounts()
bool Heap::isBusy()
{
- return (primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation);
+ return m_heap.operationInProgress != NoOperation;
+}
+
+void Heap::reset()
+{
+ JAVASCRIPTCORE_GC_BEGIN();
+
+ markRoots();
+
+ JAVASCRIPTCORE_GC_MARKED();
+
+ m_heap.nextCell = 0;
+ m_heap.nextBlock = 0;
+ m_heap.nextNumber = 0;
+ m_heap.extraCost = 0;
+#if ENABLE(JSC_ZOMBIES)
+ sweep();
+#endif
+ resizeBlocks();
+
+ JAVASCRIPTCORE_GC_END();
+}
+
+void Heap::collectAllGarbage()
+{
+ JAVASCRIPTCORE_GC_BEGIN();
+
+ // If the last iteration through the heap deallocated blocks, we need
+ // to clean up remaining garbage before marking. Otherwise, the conservative
+ // marking mechanism might follow a pointer to unmapped memory.
+ if (m_heap.didShrink)
+ sweep();
+
+ markRoots();
+
+ JAVASCRIPTCORE_GC_MARKED();
+
+ m_heap.nextCell = 0;
+ m_heap.nextBlock = 0;
+ m_heap.nextNumber = 0;
+ m_heap.extraCost = 0;
+ sweep();
+ resizeBlocks();
+
+ JAVASCRIPTCORE_GC_END();
}
-Heap::iterator Heap::primaryHeapBegin()
+LiveObjectIterator Heap::primaryHeapBegin()
{
- return iterator(primaryHeap.blocks, primaryHeap.blocks + primaryHeap.usedBlocks);
+ return LiveObjectIterator(m_heap, 0);
}
-Heap::iterator Heap::primaryHeapEnd()
+LiveObjectIterator Heap::primaryHeapEnd()
{
- return iterator(primaryHeap.blocks + primaryHeap.usedBlocks, primaryHeap.blocks + primaryHeap.usedBlocks);
+ return LiveObjectIterator(m_heap, m_heap.usedBlocks);
}
} // namespace JSC
diff --git a/JavaScriptCore/runtime/Collector.h b/JavaScriptCore/runtime/Collector.h
index 9128701..7f7a679 100644
--- a/JavaScriptCore/runtime/Collector.h
+++ b/JavaScriptCore/runtime/Collector.h
@@ -28,9 +28,9 @@
#include <wtf/HashSet.h>
#include <wtf/Noncopyable.h>
#include <wtf/OwnPtr.h>
+#include <wtf/StdLibExtras.h>
#include <wtf/Threading.h>
-// This is supremely lame that we require pthreads to build on windows.
#if ENABLE(JSC_MULTIPLE_THREADS)
#include <pthread.h>
#endif
@@ -47,22 +47,21 @@ namespace JSC {
class MarkStack;
enum OperationInProgress { NoOperation, Allocation, Collection };
- enum HeapType { PrimaryHeap, NumberHeap };
- template <HeapType> class CollectorHeapIterator;
+ class LiveObjectIterator;
struct CollectorHeap {
+ size_t nextBlock;
+ size_t nextCell;
CollectorBlock** blocks;
+
+ void* nextNumber;
+
size_t numBlocks;
size_t usedBlocks;
- size_t firstBlockWithPossibleSpace;
- size_t numLiveObjects;
- size_t numLiveObjectsAtLastCollect;
size_t extraCost;
-#if ENABLE(JSC_ZOMBIES)
- size_t numZombies;
-#endif
+ bool didShrink;
OperationInProgress operationInProgress;
};
@@ -70,21 +69,21 @@ namespace JSC {
class Heap : public Noncopyable {
public:
class Thread;
- typedef CollectorHeapIterator<PrimaryHeap> iterator;
void destroy();
void* allocateNumber(size_t);
void* allocate(size_t);
- bool collect();
bool isBusy(); // true if an allocation or collection is in progress
+ void collectAllGarbage();
- static const size_t minExtraCostSize = 256;
+ static const size_t minExtraCost = 256;
+ static const size_t maxExtraCost = 1024 * 1024;
void reportExtraMemoryCost(size_t cost);
- size_t objectCount();
+ size_t objectCount() const;
struct Statistics {
size_t size;
size_t free;
@@ -114,13 +113,12 @@ namespace JSC {
JSGlobalData* globalData() const { return m_globalData; }
static bool isNumber(JSCell*);
- // Iterators for the object heap.
- iterator primaryHeapBegin();
- iterator primaryHeapEnd();
+ LiveObjectIterator primaryHeapBegin();
+ LiveObjectIterator primaryHeapEnd();
private:
- template <HeapType heapType> void* heapAllocate(size_t);
- template <HeapType heapType> size_t sweep();
+ void reset();
+ void sweep();
static CollectorBlock* cellBlock(const JSCell*);
static size_t cellOffset(const JSCell*);
@@ -128,12 +126,22 @@ namespace JSC {
Heap(JSGlobalData*);
~Heap();
- template <HeapType heapType> NEVER_INLINE CollectorBlock* allocateBlock();
- template <HeapType heapType> NEVER_INLINE void freeBlock(size_t);
- NEVER_INLINE void freeBlock(CollectorBlock*);
- void freeBlocks(CollectorHeap*);
+ NEVER_INLINE CollectorBlock* allocateBlock();
+ NEVER_INLINE void freeBlock(size_t);
+ NEVER_INLINE void freeBlockPtr(CollectorBlock*);
+ void freeBlocks();
+ void resizeBlocks();
+ void growBlocks(size_t neededBlocks);
+ void shrinkBlocks(size_t neededBlocks);
+ void clearMarkBits();
+ void clearMarkBits(CollectorBlock*);
+ size_t markedCells(size_t startBlock = 0, size_t startCell = 0) const;
void recordExtraCost(size_t);
+
+ void addToStatistics(Statistics&) const;
+
+ void markRoots();
void markProtectedObjects(MarkStack&);
void markCurrentThreadConservatively(MarkStack&);
void markCurrentThreadConservativelyInternal(MarkStack&);
@@ -142,8 +150,7 @@ namespace JSC {
typedef HashCountedSet<JSCell*> ProtectCountSet;
- CollectorHeap primaryHeap;
- CollectorHeap numberHeap;
+ CollectorHeap m_heap;
ProtectCountSet m_protectedValues;
@@ -174,7 +181,7 @@ namespace JSC {
#endif
template<> struct CellSize<sizeof(uint64_t)> { static const size_t m_value = 64; };
-#if PLATFORM(WINCE) || PLATFORM(SYMBIAN)
+#if OS(WINCE) || OS(SYMBIAN)
const size_t BLOCK_SIZE = 64 * 1024; // 64k
#else
const size_t BLOCK_SIZE = 64 * 4096; // 256k
@@ -189,87 +196,60 @@ namespace JSC {
const size_t SMALL_CELL_SIZE = CELL_SIZE / 2;
const size_t CELL_MASK = CELL_SIZE - 1;
const size_t CELL_ALIGN_MASK = ~CELL_MASK;
- const size_t CELLS_PER_BLOCK = (BLOCK_SIZE * 8 - sizeof(uint32_t) * 8 - sizeof(void *) * 8 - 2 * (7 + 3 * 8)) / (CELL_SIZE * 8 + 2);
- const size_t SMALL_CELLS_PER_BLOCK = 2 * CELLS_PER_BLOCK;
+ const size_t CELLS_PER_BLOCK = (BLOCK_SIZE - sizeof(Heap*)) * 8 * CELL_SIZE / (8 * CELL_SIZE + 1) / CELL_SIZE; // one bitmap byte can represent 8 cells.
+
const size_t BITMAP_SIZE = (CELLS_PER_BLOCK + 7) / 8;
const size_t BITMAP_WORDS = (BITMAP_SIZE + 3) / sizeof(uint32_t);
-
+
struct CollectorBitmap {
uint32_t bits[BITMAP_WORDS];
bool get(size_t n) const { return !!(bits[n >> 5] & (1 << (n & 0x1F))); }
void set(size_t n) { bits[n >> 5] |= (1 << (n & 0x1F)); }
void clear(size_t n) { bits[n >> 5] &= ~(1 << (n & 0x1F)); }
void clearAll() { memset(bits, 0, sizeof(bits)); }
+ size_t count(size_t startCell = 0)
+ {
+ size_t result = 0;
+ for ( ; (startCell & 0x1F) != 0; ++startCell) {
+ if (get(startCell))
+ ++result;
+ }
+ for (size_t i = startCell >> 5; i < BITMAP_WORDS; ++i)
+ result += WTF::bitCount(bits[i]);
+ return result;
+ }
+ size_t isEmpty() // Much more efficient than testing count() == 0.
+ {
+ for (size_t i = 0; i < BITMAP_WORDS; ++i)
+ if (bits[i] != 0)
+ return false;
+ return true;
+ }
};
struct CollectorCell {
- union {
- double memory[CELL_ARRAY_LENGTH];
- struct {
- void* zeroIfFree;
- ptrdiff_t next;
- } freeCell;
- } u;
- };
-
- struct SmallCollectorCell {
- union {
- double memory[CELL_ARRAY_LENGTH / 2];
- struct {
- void* zeroIfFree;
- ptrdiff_t next;
- } freeCell;
- } u;
+ double memory[CELL_ARRAY_LENGTH];
};
class CollectorBlock {
public:
CollectorCell cells[CELLS_PER_BLOCK];
- uint32_t usedCells;
- CollectorCell* freeList;
- CollectorBitmap marked;
- Heap* heap;
- HeapType type;
- };
-
- class SmallCellCollectorBlock {
- public:
- SmallCollectorCell cells[SMALL_CELLS_PER_BLOCK];
- uint32_t usedCells;
- SmallCollectorCell* freeList;
CollectorBitmap marked;
Heap* heap;
- HeapType type;
};
-
- template <HeapType heapType> struct HeapConstants;
- template <> struct HeapConstants<PrimaryHeap> {
+ struct HeapConstants {
static const size_t cellSize = CELL_SIZE;
static const size_t cellsPerBlock = CELLS_PER_BLOCK;
- static const size_t bitmapShift = 0;
typedef CollectorCell Cell;
typedef CollectorBlock Block;
};
- template <> struct HeapConstants<NumberHeap> {
- static const size_t cellSize = SMALL_CELL_SIZE;
- static const size_t cellsPerBlock = SMALL_CELLS_PER_BLOCK;
- static const size_t bitmapShift = 1;
- typedef SmallCollectorCell Cell;
- typedef SmallCellCollectorBlock Block;
- };
-
inline CollectorBlock* Heap::cellBlock(const JSCell* cell)
{
return reinterpret_cast<CollectorBlock*>(reinterpret_cast<uintptr_t>(cell) & BLOCK_MASK);
}
- inline bool Heap::isNumber(JSCell* cell)
- {
- return Heap::cellBlock(cell)->type == NumberHeap;
- }
-
inline size_t Heap::cellOffset(const JSCell* cell)
{
return (reinterpret_cast<uintptr_t>(cell) & BLOCK_OFFSET_MASK) / CELL_SIZE;
@@ -287,8 +267,20 @@ namespace JSC {
inline void Heap::reportExtraMemoryCost(size_t cost)
{
- if (cost > minExtraCostSize)
- recordExtraCost(cost / (CELL_SIZE * 2));
+ if (cost > minExtraCost)
+ recordExtraCost(cost);
+ }
+
+ inline void* Heap::allocateNumber(size_t s)
+ {
+ if (void* result = m_heap.nextNumber) {
+ m_heap.nextNumber = 0;
+ return result;
+ }
+
+ void* result = allocate(s);
+ m_heap.nextNumber = static_cast<char*>(result) + (CELL_SIZE / 2);
+ return result;
}
} // namespace JSC
diff --git a/JavaScriptCore/runtime/CollectorHeapIterator.h b/JavaScriptCore/runtime/CollectorHeapIterator.h
index e38a852..e4f2f91 100644
--- a/JavaScriptCore/runtime/CollectorHeapIterator.h
+++ b/JavaScriptCore/runtime/CollectorHeapIterator.h
@@ -31,58 +31,108 @@
namespace JSC {
- template <HeapType heapType> class CollectorHeapIterator {
+ class CollectorHeapIterator {
public:
- CollectorHeapIterator(CollectorBlock** block, CollectorBlock** endBlock);
-
- bool operator!=(const CollectorHeapIterator<heapType>& other) { return m_block != other.m_block || m_cell != other.m_cell; }
- CollectorHeapIterator<heapType>& operator++();
+ bool operator!=(const CollectorHeapIterator& other);
JSCell* operator*() const;
- private:
- typedef typename HeapConstants<heapType>::Block Block;
- typedef typename HeapConstants<heapType>::Cell Cell;
-
- Block** m_block;
- Block** m_endBlock;
- Cell* m_cell;
- Cell* m_endCell;
+ protected:
+ CollectorHeapIterator(CollectorHeap&, size_t startBlock, size_t startCell);
+ void advance(size_t cellsPerBlock);
+
+ CollectorHeap& m_heap;
+ size_t m_block;
+ size_t m_cell;
+ };
+
+ class LiveObjectIterator : public CollectorHeapIterator {
+ public:
+ LiveObjectIterator(CollectorHeap&, size_t startBlock, size_t startCell = 0);
+ LiveObjectIterator& operator++();
+ };
+
+ class DeadObjectIterator : public CollectorHeapIterator {
+ public:
+ DeadObjectIterator(CollectorHeap&, size_t startBlock, size_t startCell = 0);
+ DeadObjectIterator& operator++();
+ };
+
+ class ObjectIterator : public CollectorHeapIterator {
+ public:
+ ObjectIterator(CollectorHeap&, size_t startBlock, size_t startCell = 0);
+ ObjectIterator& operator++();
};
- template <HeapType heapType>
- CollectorHeapIterator<heapType>::CollectorHeapIterator(CollectorBlock** block, CollectorBlock** endBlock)
- : m_block(reinterpret_cast<Block**>(block))
- , m_endBlock(reinterpret_cast<Block**>(endBlock))
- , m_cell(m_block == m_endBlock ? 0 : (*m_block)->cells)
- , m_endCell(m_block == m_endBlock ? 0 : (*m_block)->cells + HeapConstants<heapType>::cellsPerBlock)
+ inline CollectorHeapIterator::CollectorHeapIterator(CollectorHeap& heap, size_t startBlock, size_t startCell)
+ : m_heap(heap)
+ , m_block(startBlock)
+ , m_cell(startCell)
+ {
+ }
+
+ inline bool CollectorHeapIterator::operator!=(const CollectorHeapIterator& other)
+ {
+ return m_block != other.m_block || m_cell != other.m_cell;
+ }
+
+ inline JSCell* CollectorHeapIterator::operator*() const
+ {
+ return reinterpret_cast<JSCell*>(m_heap.blocks[m_block]->cells + m_cell);
+ }
+
+ inline void CollectorHeapIterator::advance(size_t cellsPerBlock)
+ {
+ ++m_cell;
+ if (m_cell == cellsPerBlock) {
+ m_cell = 0;
+ ++m_block;
+ }
+ }
+
+ inline LiveObjectIterator::LiveObjectIterator(CollectorHeap& heap, size_t startBlock, size_t startCell)
+ : CollectorHeapIterator(heap, startBlock, startCell - 1)
+ {
+ ++(*this);
+ }
+
+ inline LiveObjectIterator& LiveObjectIterator::operator++()
+ {
+ if (m_block < m_heap.nextBlock || m_cell < m_heap.nextCell) {
+ advance(HeapConstants::cellsPerBlock);
+ return *this;
+ }
+
+ do {
+ advance(HeapConstants::cellsPerBlock);
+ } while (m_block < m_heap.usedBlocks && !m_heap.blocks[m_block]->marked.get(m_cell));
+ return *this;
+ }
+
+ inline DeadObjectIterator::DeadObjectIterator(CollectorHeap& heap, size_t startBlock, size_t startCell)
+ : CollectorHeapIterator(heap, startBlock, startCell - 1)
{
- if (m_cell && m_cell->u.freeCell.zeroIfFree == 0)
- ++*this;
+ ++(*this);
}
- template <HeapType heapType>
- CollectorHeapIterator<heapType>& CollectorHeapIterator<heapType>::operator++()
+ inline DeadObjectIterator& DeadObjectIterator::operator++()
{
do {
- for (++m_cell; m_cell != m_endCell; ++m_cell)
- if (m_cell->u.freeCell.zeroIfFree != 0) {
- return *this;
- }
-
- if (++m_block != m_endBlock) {
- m_cell = (*m_block)->cells;
- m_endCell = (*m_block)->cells + HeapConstants<heapType>::cellsPerBlock;
- }
- } while(m_block != m_endBlock);
-
- m_cell = 0;
+ advance(HeapConstants::cellsPerBlock);
+ ASSERT(m_block > m_heap.nextBlock || (m_block == m_heap.nextBlock && m_cell >= m_heap.nextCell));
+ } while (m_block < m_heap.usedBlocks && m_heap.blocks[m_block]->marked.get(m_cell));
return *this;
}
- template <HeapType heapType>
- JSCell* CollectorHeapIterator<heapType>::operator*() const
+ inline ObjectIterator::ObjectIterator(CollectorHeap& heap, size_t startBlock, size_t startCell)
+ : CollectorHeapIterator(heap, startBlock, startCell - 1)
{
- return reinterpret_cast<JSCell*>(m_cell);
+ ++(*this);
+ }
+
+ inline ObjectIterator& ObjectIterator::operator++()
+ {
+ advance(HeapConstants::cellsPerBlock);
+ return *this;
}
} // namespace JSC
diff --git a/JavaScriptCore/runtime/CommonIdentifiers.h b/JavaScriptCore/runtime/CommonIdentifiers.h
index abe5038..de24f4a 100644
--- a/JavaScriptCore/runtime/CommonIdentifiers.h
+++ b/JavaScriptCore/runtime/CommonIdentifiers.h
@@ -50,6 +50,7 @@
macro(get) \
macro(getPrototypeOf) \
macro(getOwnPropertyDescriptor) \
+ macro(getOwnPropertyNames) \
macro(hasOwnProperty) \
macro(ignoreCase) \
macro(index) \
diff --git a/JavaScriptCore/runtime/Completion.cpp b/JavaScriptCore/runtime/Completion.cpp
index 2507698..2f88df9 100644
--- a/JavaScriptCore/runtime/Completion.cpp
+++ b/JavaScriptCore/runtime/Completion.cpp
@@ -36,6 +36,7 @@ namespace JSC {
Completion checkSyntax(ExecState* exec, const SourceCode& source)
{
JSLock lock(exec);
+ ASSERT(exec->globalData().identifierTable == currentIdentifierTable());
RefPtr<ProgramExecutable> program = ProgramExecutable::create(exec, source);
JSObject* error = program->checkSyntax(exec);
@@ -48,6 +49,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());
RefPtr<ProgramExecutable> program = ProgramExecutable::create(exec, source);
JSObject* error = program->compile(exec, scopeChain.node());
diff --git a/JavaScriptCore/runtime/DateConstructor.cpp b/JavaScriptCore/runtime/DateConstructor.cpp
index 61ec4c5..2e476b3 100644
--- a/JavaScriptCore/runtime/DateConstructor.cpp
+++ b/JavaScriptCore/runtime/DateConstructor.cpp
@@ -35,7 +35,7 @@
#include <wtf/DateMath.h>
#include <wtf/MathExtras.h>
-#if PLATFORM(WINCE) && !PLATFORM(QT)
+#if OS(WINCE) && !PLATFORM(QT)
extern "C" time_t time(time_t* timer); // Provided by libce.
#endif
@@ -133,7 +133,11 @@ static JSValue JSC_HOST_CALL callDate(ExecState* exec, JSObject*, JSValue, const
tm localTM;
getLocalTime(&localTime, &localTM);
GregorianDateTime ts(exec, localTM);
- return jsNontrivialString(exec, formatDate(ts) + " " + formatTime(ts));
+ DateConversionBuffer date;
+ DateConversionBuffer time;
+ formatDate(ts, date);
+ formatTime(ts, time);
+ return jsNontrivialString(exec, makeString(date, " ", time));
}
CallType DateConstructor::getCallData(CallData& callData)
diff --git a/JavaScriptCore/runtime/DateConversion.cpp b/JavaScriptCore/runtime/DateConversion.cpp
index b9d0e02..f129407 100644
--- a/JavaScriptCore/runtime/DateConversion.cpp
+++ b/JavaScriptCore/runtime/DateConversion.cpp
@@ -62,49 +62,41 @@ double parseDate(ExecState* exec, const UString &date)
return value;
}
-UString formatDate(const GregorianDateTime &t)
+void formatDate(const GregorianDateTime &t, DateConversionBuffer& buffer)
{
- char buffer[100];
- snprintf(buffer, sizeof(buffer), "%s %s %02d %04d",
+ snprintf(buffer, DateConversionBufferSize, "%s %s %02d %04d",
weekdayName[(t.weekDay + 6) % 7],
monthName[t.month], t.monthDay, t.year + 1900);
- return buffer;
}
-UString formatDateUTCVariant(const GregorianDateTime &t)
+void formatDateUTCVariant(const GregorianDateTime &t, DateConversionBuffer& buffer)
{
- char buffer[100];
- snprintf(buffer, sizeof(buffer), "%s, %02d %s %04d",
+ snprintf(buffer, DateConversionBufferSize, "%s, %02d %s %04d",
weekdayName[(t.weekDay + 6) % 7],
t.monthDay, monthName[t.month], t.year + 1900);
- return buffer;
}
-UString formatTime(const GregorianDateTime &t)
+void formatTime(const GregorianDateTime &t, DateConversionBuffer& buffer)
{
- char buffer[100];
int offset = abs(gmtoffset(t));
char timeZoneName[70];
struct tm gtm = t;
strftime(timeZoneName, sizeof(timeZoneName), "%Z", &gtm);
if (timeZoneName[0]) {
- snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d (%s)",
+ snprintf(buffer, DateConversionBufferSize, "%02d:%02d:%02d GMT%c%02d%02d (%s)",
t.hour, t.minute, t.second,
gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60, timeZoneName);
} else {
- snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d",
+ snprintf(buffer, DateConversionBufferSize, "%02d:%02d:%02d GMT%c%02d%02d",
t.hour, t.minute, t.second,
gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60);
}
- return UString(buffer);
}
-UString formatTimeUTC(const GregorianDateTime &t)
+void formatTimeUTC(const GregorianDateTime &t, DateConversionBuffer& buffer)
{
- char buffer[100];
- snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", t.hour, t.minute, t.second);
- return UString(buffer);
+ snprintf(buffer, DateConversionBufferSize, "%02d:%02d:%02d GMT", t.hour, t.minute, t.second);
}
} // namespace JSC
diff --git a/JavaScriptCore/runtime/DateConversion.h b/JavaScriptCore/runtime/DateConversion.h
index dc980d3..ff32b50 100644
--- a/JavaScriptCore/runtime/DateConversion.h
+++ b/JavaScriptCore/runtime/DateConversion.h
@@ -42,17 +42,21 @@
#ifndef DateConversion_h
#define DateConversion_h
+#include "UString.h"
+
namespace JSC {
class ExecState;
-class UString;
struct GregorianDateTime;
+static const unsigned DateConversionBufferSize = 100;
+typedef char DateConversionBuffer[DateConversionBufferSize];
+
double parseDate(ExecState* exec, const UString&);
-UString formatDate(const GregorianDateTime&);
-UString formatDateUTCVariant(const GregorianDateTime&);
-UString formatTime(const GregorianDateTime&);
-UString formatTimeUTC(const GregorianDateTime&);
+void formatDate(const GregorianDateTime&, DateConversionBuffer&);
+void formatDateUTCVariant(const GregorianDateTime&, DateConversionBuffer&);
+void formatTime(const GregorianDateTime&, DateConversionBuffer&);
+void formatTimeUTC(const GregorianDateTime&, DateConversionBuffer&);
} // namespace JSC
diff --git a/JavaScriptCore/runtime/DateInstance.cpp b/JavaScriptCore/runtime/DateInstance.cpp
index 77a92be..b43b183 100644
--- a/JavaScriptCore/runtime/DateInstance.cpp
+++ b/JavaScriptCore/runtime/DateInstance.cpp
@@ -40,6 +40,12 @@ DateInstance::DateInstance(ExecState* exec, NonNullPassRefPtr<Structure> structu
setInternalValue(jsNaN(exec));
}
+DateInstance::DateInstance(ExecState* exec, NonNullPassRefPtr<Structure> structure, double time)
+ : JSWrapperObject(structure)
+{
+ setInternalValue(jsNumber(exec, timeClip(time)));
+}
+
DateInstance::DateInstance(ExecState* exec, double time)
: JSWrapperObject(exec->lexicalGlobalObject()->dateStructure())
{
diff --git a/JavaScriptCore/runtime/DateInstance.h b/JavaScriptCore/runtime/DateInstance.h
index 44b7521..77d46de 100644
--- a/JavaScriptCore/runtime/DateInstance.h
+++ b/JavaScriptCore/runtime/DateInstance.h
@@ -32,6 +32,7 @@ namespace JSC {
class DateInstance : public JSWrapperObject {
public:
DateInstance(ExecState*, double);
+ DateInstance(ExecState*, NonNullPassRefPtr<Structure>, double);
explicit DateInstance(ExecState*, NonNullPassRefPtr<Structure>);
double internalNumber() const { return internalValue().uncheckedGetNumber(); }
@@ -54,7 +55,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
protected:
diff --git a/JavaScriptCore/runtime/DatePrototype.cpp b/JavaScriptCore/runtime/DatePrototype.cpp
index 7a2e802..ca9d4ea 100644
--- a/JavaScriptCore/runtime/DatePrototype.cpp
+++ b/JavaScriptCore/runtime/DatePrototype.cpp
@@ -59,7 +59,7 @@
#include <CoreFoundation/CoreFoundation.h>
#endif
-#if PLATFORM(WINCE) && !PLATFORM(QT)
+#if OS(WINCE) && !PLATFORM(QT)
extern "C" size_t strftime(char * const s, const size_t maxsize, const char * const format, const struct tm * const t); //provided by libce
#endif
@@ -197,7 +197,7 @@ static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, L
{
#if HAVE(LANGINFO_H)
static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT };
-#elif (PLATFORM(WINCE) && !PLATFORM(QT)) || PLATFORM(SYMBIAN)
+#elif (OS(WINCE) && !PLATFORM(QT)) || OS(SYMBIAN)
// strftime() does not support '#' on WinCE or Symbian
static const char* const formatStrings[] = { "%c", "%x", "%X" };
#else
@@ -423,7 +423,11 @@ JSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec, JSObject*, JSValue
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
return jsNontrivialString(exec, "Invalid Date");
- return jsNontrivialString(exec, formatDate(*gregorianDateTime) + " " + formatTime(*gregorianDateTime));
+ DateConversionBuffer date;
+ DateConversionBuffer time;
+ formatDate(*gregorianDateTime, date);
+ formatTime(*gregorianDateTime, time);
+ return jsNontrivialString(exec, makeString(date, " ", time));
}
JSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
@@ -436,7 +440,11 @@ JSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec, JSObject*, JSVal
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
return jsNontrivialString(exec, "Invalid Date");
- return jsNontrivialString(exec, formatDateUTCVariant(*gregorianDateTime) + " " + formatTimeUTC(*gregorianDateTime));
+ DateConversionBuffer date;
+ DateConversionBuffer time;
+ formatDateUTCVariant(*gregorianDateTime, date);
+ formatTimeUTC(*gregorianDateTime, time);
+ return jsNontrivialString(exec, makeString(date, " ", time));
}
JSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
@@ -467,7 +475,9 @@ JSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec, JSObject*, JSVa
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
return jsNontrivialString(exec, "Invalid Date");
- return jsNontrivialString(exec, formatDate(*gregorianDateTime));
+ DateConversionBuffer date;
+ formatDate(*gregorianDateTime, date);
+ return jsNontrivialString(exec, date);
}
JSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
@@ -480,7 +490,9 @@ JSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec, JSObject*, JSVa
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
return jsNontrivialString(exec, "Invalid Date");
- return jsNontrivialString(exec, formatTime(*gregorianDateTime));
+ DateConversionBuffer time;
+ formatTime(*gregorianDateTime, time);
+ return jsNontrivialString(exec, time);
}
JSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
@@ -554,7 +566,11 @@ JSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec, JSObject*, JSVal
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
return jsNontrivialString(exec, "Invalid Date");
- return jsNontrivialString(exec, formatDateUTCVariant(*gregorianDateTime) + " " + formatTimeUTC(*gregorianDateTime));
+ DateConversionBuffer date;
+ DateConversionBuffer time;
+ formatDateUTCVariant(*gregorianDateTime, date);
+ formatTimeUTC(*gregorianDateTime, time);
+ return jsNontrivialString(exec, makeString(date, " ", time));
}
JSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
diff --git a/JavaScriptCore/runtime/DatePrototype.h b/JavaScriptCore/runtime/DatePrototype.h
index f565775..612ca06 100644
--- a/JavaScriptCore/runtime/DatePrototype.h
+++ b/JavaScriptCore/runtime/DatePrototype.h
@@ -39,7 +39,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
protected:
diff --git a/JavaScriptCore/runtime/ErrorPrototype.cpp b/JavaScriptCore/runtime/ErrorPrototype.cpp
index a9a7a43..be9e4b8 100644
--- a/JavaScriptCore/runtime/ErrorPrototype.cpp
+++ b/JavaScriptCore/runtime/ErrorPrototype.cpp
@@ -48,21 +48,19 @@ ErrorPrototype::ErrorPrototype(ExecState* exec, NonNullPassRefPtr<Structure> str
JSValue JSC_HOST_CALL errorProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
{
JSObject* thisObj = thisValue.toThisObject(exec);
+ JSValue name = thisObj->get(exec, exec->propertyNames().name);
+ JSValue message = thisObj->get(exec, exec->propertyNames().message);
- UString s = "Error";
+ // Mozilla-compatible format.
- JSValue v = thisObj->get(exec, exec->propertyNames().name);
- if (!v.isUndefined())
- s = v.toString(exec);
-
- v = thisObj->get(exec, exec->propertyNames().message);
- if (!v.isUndefined()) {
- // Mozilla-compatible format.
- s += ": ";
- s += v.toString(exec);
+ if (!name.isUndefined()) {
+ if (!message.isUndefined())
+ return jsNontrivialString(exec, makeString(name.toString(exec), ": ", message.toString(exec)));
+ return jsNontrivialString(exec, name.toString(exec));
}
-
- return jsNontrivialString(exec, s);
+ if (!message.isUndefined())
+ return jsNontrivialString(exec, makeString("Error: ", message.toString(exec)));
+ return jsNontrivialString(exec, "Error");
}
} // namespace JSC
diff --git a/JavaScriptCore/runtime/ExceptionHelpers.cpp b/JavaScriptCore/runtime/ExceptionHelpers.cpp
index 5bead90..9bb740e 100644
--- a/JavaScriptCore/runtime/ExceptionHelpers.cpp
+++ b/JavaScriptCore/runtime/ExceptionHelpers.cpp
@@ -77,9 +77,7 @@ JSValue createUndefinedVariableError(ExecState* exec, const Identifier& ident, u
int endOffset = 0;
int divotPoint = 0;
int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset);
- UString message = "Can't find variable: ";
- message.append(ident.ustring());
- JSObject* exception = Error::create(exec, ReferenceError, message, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL());
+ JSObject* exception = Error::create(exec, ReferenceError, makeString("Can't find variable: ", ident.ustring()), line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL());
exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
@@ -88,59 +86,36 @@ JSValue createUndefinedVariableError(ExecState* exec, const Identifier& ident, u
static UString createErrorMessage(ExecState* exec, CodeBlock* codeBlock, int, int expressionStart, int expressionStop, JSValue value, UString error)
{
- if (!expressionStop || expressionStart > codeBlock->source()->length()) {
- UString errorText = value.toString(exec);
- errorText.append(" is ");
- errorText.append(error);
- return errorText;
- }
+ if (!expressionStop || expressionStart > codeBlock->source()->length())
+ return makeString(value.toString(exec), " is ", error);
+ if (expressionStart < expressionStop)
+ return makeString("Result of expression '", codeBlock->source()->getRange(expressionStart, expressionStop), "' [", value.toString(exec), "] is ", error, ".");
- UString errorText = "Result of expression ";
-
- if (expressionStart < expressionStop) {
- errorText.append('\'');
- errorText.append(codeBlock->source()->getRange(expressionStart, expressionStop));
- errorText.append("' [");
- errorText.append(value.toString(exec));
- errorText.append("] is ");
- } else {
- // No range information, so give a few characters of context
- const UChar* data = codeBlock->source()->data();
- int dataLength = codeBlock->source()->length();
- int start = expressionStart;
- int stop = expressionStart;
- // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
- // then strip whitespace.
- while (start > 0 && (expressionStart - start < 20) && data[start - 1] != '\n')
- start--;
- while (start < (expressionStart - 1) && isStrWhiteSpace(data[start]))
- start++;
- while (stop < dataLength && (stop - expressionStart < 20) && data[stop] != '\n')
- stop++;
- while (stop > expressionStart && isStrWhiteSpace(data[stop]))
- stop--;
- errorText.append("near '...");
- errorText.append(codeBlock->source()->getRange(start, stop));
- errorText.append("...' [");
- errorText.append(value.toString(exec));
- errorText.append("] is ");
- }
- errorText.append(error);
- errorText.append(".");
- return errorText;
+ // No range information, so give a few characters of context
+ const UChar* data = codeBlock->source()->data();
+ int dataLength = codeBlock->source()->length();
+ int start = expressionStart;
+ int stop = expressionStart;
+ // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
+ // then strip whitespace.
+ while (start > 0 && (expressionStart - start < 20) && data[start - 1] != '\n')
+ start--;
+ while (start < (expressionStart - 1) && isStrWhiteSpace(data[start]))
+ start++;
+ while (stop < dataLength && (stop - expressionStart < 20) && data[stop] != '\n')
+ stop++;
+ while (stop > expressionStart && isStrWhiteSpace(data[stop]))
+ stop--;
+ return makeString("Result of expression near '...", codeBlock->source()->getRange(start, stop), "...' [", value.toString(exec), "] is ", error, ".");
}
JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock)
{
- UString message = "not a valid argument for '";
- message.append(op);
- message.append("'");
-
int startOffset = 0;
int endOffset = 0;
int divotPoint = 0;
int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset);
- UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint, divotPoint + endOffset, value, message);
+ UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint, divotPoint + endOffset, value, makeString("not a valid argument for '", op, "'"));
JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL());
exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
diff --git a/JavaScriptCore/runtime/Executable.cpp b/JavaScriptCore/runtime/Executable.cpp
index 7586746..bc18cc9 100644
--- a/JavaScriptCore/runtime/Executable.cpp
+++ b/JavaScriptCore/runtime/Executable.cpp
@@ -30,6 +30,7 @@
#include "CodeBlock.h"
#include "JIT.h"
#include "Parser.h"
+#include "StringBuilder.h"
#include "Vector.h"
namespace JSC {
@@ -265,14 +266,13 @@ PassRefPtr<FunctionExecutable> FunctionExecutable::fromGlobalCode(const Identifi
UString FunctionExecutable::paramString() const
{
FunctionParameters& parameters = *m_parameters;
- UString s("");
+ StringBuilder builder;
for (size_t pos = 0; pos < parameters.size(); ++pos) {
- if (!s.isEmpty())
- s += ", ";
- s += parameters[pos].ustring();
+ if (!builder.isEmpty())
+ builder.append(", ");
+ builder.append(parameters[pos].ustring());
}
-
- return s;
+ return builder.release();
}
};
diff --git a/JavaScriptCore/runtime/FunctionConstructor.cpp b/JavaScriptCore/runtime/FunctionConstructor.cpp
index 9d88400..9d55dd1 100644
--- a/JavaScriptCore/runtime/FunctionConstructor.cpp
+++ b/JavaScriptCore/runtime/FunctionConstructor.cpp
@@ -21,14 +21,15 @@
#include "config.h"
#include "FunctionConstructor.h"
+#include "Debugger.h"
#include "FunctionPrototype.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "JSString.h"
-#include "Parser.h"
-#include "Debugger.h"
#include "Lexer.h"
#include "Nodes.h"
+#include "Parser.h"
+#include "StringBuilder.h"
namespace JSC {
@@ -76,12 +77,19 @@ JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifi
if (args.isEmpty())
program = "(function() { \n})";
else if (args.size() == 1)
- program = "(function() { " + args.at(0).toString(exec) + "\n})";
+ program = makeString("(function() { ", args.at(0).toString(exec), "\n})");
else {
- program = "(function(" + args.at(0).toString(exec);
- for (size_t i = 1; i < args.size() - 1; i++)
- program += "," + args.at(i).toString(exec);
- program += ") { " + args.at(args.size() - 1).toString(exec) + "\n})";
+ StringBuilder builder;
+ builder.append("(function(");
+ builder.append(args.at(0).toString(exec));
+ for (size_t i = 1; i < args.size() - 1; i++) {
+ builder.append(",");
+ builder.append(args.at(i).toString(exec));
+ }
+ builder.append(") { ");
+ builder.append(args.at(args.size() - 1).toString(exec));
+ builder.append("\n})");
+ program = builder.release();
}
int errLine;
diff --git a/JavaScriptCore/runtime/FunctionPrototype.cpp b/JavaScriptCore/runtime/FunctionPrototype.cpp
index a3a7479..f08bd5e 100644
--- a/JavaScriptCore/runtime/FunctionPrototype.cpp
+++ b/JavaScriptCore/runtime/FunctionPrototype.cpp
@@ -76,7 +76,7 @@ static inline void insertSemicolonIfNeeded(UString& functionBody)
UChar ch = functionBody[i];
if (!Lexer::isWhiteSpace(ch) && !Lexer::isLineTerminator(ch)) {
if (ch != ';' && ch != '}')
- functionBody = functionBody.substr(0, i + 1) + ";" + functionBody.substr(i + 1, functionBody.size() - (i + 1));
+ functionBody = makeString(functionBody.substr(0, i + 1), ";", functionBody.substr(i + 1, functionBody.size() - (i + 1)));
return;
}
}
@@ -90,13 +90,13 @@ JSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec, JSObject*, JSVa
FunctionExecutable* executable = function->jsExecutable();
UString sourceString = executable->source().toString();
insertSemicolonIfNeeded(sourceString);
- return jsString(exec, "function " + function->name(exec) + "(" + executable->paramString() + ") " + sourceString);
+ return jsString(exec, makeString("function ", function->name(exec), "(", executable->paramString(), ") ", sourceString));
}
}
if (thisValue.inherits(&InternalFunction::info)) {
InternalFunction* function = asInternalFunction(thisValue);
- return jsString(exec, "function " + function->name(exec) + "() {\n [native code]\n}");
+ return jsString(exec, makeString("function ", function->name(exec), "() {\n [native code]\n}"));
}
return throwError(exec, TypeError);
diff --git a/JavaScriptCore/runtime/FunctionPrototype.h b/JavaScriptCore/runtime/FunctionPrototype.h
index d1d6a1d..af783f7 100644
--- a/JavaScriptCore/runtime/FunctionPrototype.h
+++ b/JavaScriptCore/runtime/FunctionPrototype.h
@@ -34,7 +34,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue proto)
{
- return Structure::create(proto, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
private:
diff --git a/JavaScriptCore/runtime/GetterSetter.h b/JavaScriptCore/runtime/GetterSetter.h
index 68e9ea3..4e47361 100644
--- a/JavaScriptCore/runtime/GetterSetter.h
+++ b/JavaScriptCore/runtime/GetterSetter.h
@@ -50,7 +50,7 @@ namespace JSC {
void setSetter(JSObject* setter) { m_setter = setter; }
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(GetterSetterType, OverridesMarkChildren));
+ return Structure::create(prototype, TypeInfo(GetterSetterType, OverridesMarkChildren), AnonymousSlotCount);
}
private:
virtual bool isGetterSetter() const;
diff --git a/JavaScriptCore/runtime/GlobalEvalFunction.h b/JavaScriptCore/runtime/GlobalEvalFunction.h
index 389b1c3..a14ce4d 100644
--- a/JavaScriptCore/runtime/GlobalEvalFunction.h
+++ b/JavaScriptCore/runtime/GlobalEvalFunction.h
@@ -37,7 +37,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
protected:
diff --git a/JavaScriptCore/runtime/Identifier.cpp b/JavaScriptCore/runtime/Identifier.cpp
index 7db723b..747c4ac 100644
--- a/JavaScriptCore/runtime/Identifier.cpp
+++ b/JavaScriptCore/runtime/Identifier.cpp
@@ -28,6 +28,8 @@
#include <wtf/FastMalloc.h>
#include <wtf/HashSet.h>
+using WTF::ThreadSpecific;
+
namespace JSC {
typedef HashMap<const char*, RefPtr<UString::Rep>, PtrHash<const char*> > LiteralIdentifierTable;
@@ -38,13 +40,13 @@ public:
{
HashSet<UString::Rep*>::iterator end = m_table.end();
for (HashSet<UString::Rep*>::iterator iter = m_table.begin(); iter != end; ++iter)
- (*iter)->setIdentifierTable(0);
+ (*iter)->setIsIdentifier(false);
}
std::pair<HashSet<UString::Rep*>::iterator, bool> add(UString::Rep* value)
{
std::pair<HashSet<UString::Rep*>::iterator, bool> result = m_table.add(value);
- (*result.first)->setIdentifierTable(this);
+ (*result.first)->setIsIdentifier(true);
return result;
}
@@ -52,7 +54,7 @@ public:
std::pair<HashSet<UString::Rep*>::iterator, bool> add(U value)
{
std::pair<HashSet<UString::Rep*>::iterator, bool> result = m_table.add<U, V>(value);
- (*result.first)->setIdentifierTable(this);
+ (*result.first)->setIsIdentifier(true);
return result;
}
@@ -77,7 +79,7 @@ void deleteIdentifierTable(IdentifierTable* table)
bool Identifier::equal(const UString::Rep* r, const char* s)
{
- int length = r->len;
+ int length = r->size();
const UChar* d = r->data();
for (int i = 0; i != length; ++i)
if (d[i] != (unsigned char)s[i])
@@ -87,7 +89,7 @@ bool Identifier::equal(const UString::Rep* r, const char* s)
bool Identifier::equal(const UString::Rep* r, const UChar* s, int length)
{
- if (r->len != length)
+ if (r->size() != length)
return false;
const UChar* d = r->data();
for (int i = 0; i != length; ++i)
@@ -110,13 +112,11 @@ struct CStringTranslator {
static void translate(UString::Rep*& location, const char* c, unsigned hash)
{
size_t length = strlen(c);
- UChar* d = static_cast<UChar*>(fastMalloc(sizeof(UChar) * length));
+ UChar* d;
+ UString::Rep* r = UString::Rep::createUninitialized(length, d).releaseRef();
for (size_t i = 0; i != length; i++)
d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend
-
- UString::Rep* r = UString::Rep::create(d, static_cast<int>(length)).releaseRef();
- r->_hash = hash;
-
+ r->setHash(hash);
location = r;
}
};
@@ -175,13 +175,11 @@ struct UCharBufferTranslator {
static void translate(UString::Rep*& location, const UCharBuffer& buf, unsigned hash)
{
- UChar* d = static_cast<UChar*>(fastMalloc(sizeof(UChar) * buf.length));
+ UChar* d;
+ UString::Rep* r = UString::Rep::createUninitialized(buf.length, d).releaseRef();
for (unsigned i = 0; i != buf.length; i++)
d[i] = buf.s[i];
-
- UString::Rep* r = UString::Rep::create(d, buf.length).releaseRef();
- r->_hash = hash;
-
+ r->setHash(hash);
location = r;
}
};
@@ -212,19 +210,19 @@ PassRefPtr<UString::Rep> Identifier::add(ExecState* exec, const UChar* s, int le
PassRefPtr<UString::Rep> Identifier::addSlowCase(JSGlobalData* globalData, UString::Rep* r)
{
- ASSERT(!r->identifierTable());
- if (r->len == 1) {
+ ASSERT(!r->isIdentifier());
+ if (r->size() == 1) {
UChar c = r->data()[0];
if (c <= 0xFF)
r = globalData->smallStrings.singleCharacterStringRep(c);
- if (r->identifierTable()) {
+ if (r->isIdentifier()) {
#ifndef NDEBUG
checkSameIdentifierTable(globalData, r);
#endif
return r;
}
}
- if (!r->len) {
+ if (!r->size()) {
UString::Rep::empty().hash();
return &UString::Rep::empty();
}
@@ -238,19 +236,19 @@ PassRefPtr<UString::Rep> Identifier::addSlowCase(ExecState* exec, UString::Rep*
void Identifier::remove(UString::Rep* r)
{
- r->identifierTable()->remove(r);
+ currentIdentifierTable()->remove(r);
}
#ifndef NDEBUG
-void Identifier::checkSameIdentifierTable(ExecState* exec, UString::Rep* rep)
+void Identifier::checkSameIdentifierTable(ExecState* exec, UString::Rep*)
{
- ASSERT(rep->identifierTable() == exec->globalData().identifierTable);
+ ASSERT_UNUSED(exec, exec->globalData().identifierTable == currentIdentifierTable());
}
-void Identifier::checkSameIdentifierTable(JSGlobalData* globalData, UString::Rep* rep)
+void Identifier::checkSameIdentifierTable(JSGlobalData* globalData, UString::Rep*)
{
- ASSERT(rep->identifierTable() == globalData->identifierTable);
+ ASSERT_UNUSED(globalData, globalData->identifierTable == currentIdentifierTable());
}
#else
@@ -265,4 +263,30 @@ void Identifier::checkSameIdentifierTable(JSGlobalData*, UString::Rep*)
#endif
+ThreadSpecific<ThreadIdentifierTableData>* g_identifierTableSpecific = 0;
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+
+pthread_once_t createIdentifierTableSpecificOnce = PTHREAD_ONCE_INIT;
+static void createIdentifierTableSpecificCallback()
+{
+ ASSERT(!g_identifierTableSpecific);
+ g_identifierTableSpecific = new ThreadSpecific<ThreadIdentifierTableData>();
+}
+void createIdentifierTableSpecific()
+{
+ pthread_once(&createIdentifierTableSpecificOnce, createIdentifierTableSpecificCallback);
+ ASSERT(g_identifierTableSpecific);
+}
+
+#else
+
+void createIdentifierTableSpecific()
+{
+ ASSERT(!g_identifierTableSpecific);
+ g_identifierTableSpecific = new ThreadSpecific<ThreadIdentifierTableData>();
+}
+
+#endif
+
} // namespace JSC
diff --git a/JavaScriptCore/runtime/Identifier.h b/JavaScriptCore/runtime/Identifier.h
index 2249179..1d1bd18 100644
--- a/JavaScriptCore/runtime/Identifier.h
+++ b/JavaScriptCore/runtime/Identifier.h
@@ -22,6 +22,7 @@
#define Identifier_h
#include "JSGlobalData.h"
+#include "ThreadSpecific.h"
#include "UString.h"
namespace JSC {
@@ -92,7 +93,7 @@ namespace JSC {
static PassRefPtr<UString::Rep> add(ExecState* exec, UString::Rep* r)
{
- if (r->identifierTable()) {
+ if (r->isIdentifier()) {
#ifndef NDEBUG
checkSameIdentifierTable(exec, r);
#endif
@@ -102,7 +103,7 @@ namespace JSC {
}
static PassRefPtr<UString::Rep> add(JSGlobalData* globalData, UString::Rep* r)
{
- if (r->identifierTable()) {
+ if (r->isIdentifier()) {
#ifndef NDEBUG
checkSameIdentifierTable(globalData, r);
#endif
@@ -141,6 +142,67 @@ namespace JSC {
IdentifierTable* createIdentifierTable();
void deleteIdentifierTable(IdentifierTable*);
+ struct ThreadIdentifierTableData {
+ ThreadIdentifierTableData()
+ : defaultIdentifierTable(0)
+ , currentIdentifierTable(0)
+ {
+ }
+
+ IdentifierTable* defaultIdentifierTable;
+ IdentifierTable* currentIdentifierTable;
+ };
+
+ extern WTF::ThreadSpecific<ThreadIdentifierTableData>* g_identifierTableSpecific;
+ void createIdentifierTableSpecific();
+
+ inline IdentifierTable* defaultIdentifierTable()
+ {
+ if (!g_identifierTableSpecific)
+ createIdentifierTableSpecific();
+ ThreadIdentifierTableData& data = **g_identifierTableSpecific;
+
+ return data.defaultIdentifierTable;
+ }
+
+ inline void setDefaultIdentifierTable(IdentifierTable* identifierTable)
+ {
+ if (!g_identifierTableSpecific)
+ createIdentifierTableSpecific();
+ ThreadIdentifierTableData& data = **g_identifierTableSpecific;
+
+ data.defaultIdentifierTable = identifierTable;
+ }
+
+ inline IdentifierTable* currentIdentifierTable()
+ {
+ if (!g_identifierTableSpecific)
+ createIdentifierTableSpecific();
+ ThreadIdentifierTableData& data = **g_identifierTableSpecific;
+
+ return data.currentIdentifierTable;
+ }
+
+ inline IdentifierTable* setCurrentIdentifierTable(IdentifierTable* identifierTable)
+ {
+ if (!g_identifierTableSpecific)
+ createIdentifierTableSpecific();
+ ThreadIdentifierTableData& data = **g_identifierTableSpecific;
+
+ IdentifierTable* oldIdentifierTable = data.currentIdentifierTable;
+ data.currentIdentifierTable = identifierTable;
+ return oldIdentifierTable;
+ }
+
+ inline void resetCurrentIdentifierTable()
+ {
+ if (!g_identifierTableSpecific)
+ createIdentifierTableSpecific();
+ ThreadIdentifierTableData& data = **g_identifierTableSpecific;
+
+ data.currentIdentifierTable = data.defaultIdentifierTable;
+ }
+
} // namespace JSC
#endif // Identifier_h
diff --git a/JavaScriptCore/runtime/InitializeThreading.cpp b/JavaScriptCore/runtime/InitializeThreading.cpp
index aad1af8..2605a9a 100644
--- a/JavaScriptCore/runtime/InitializeThreading.cpp
+++ b/JavaScriptCore/runtime/InitializeThreading.cpp
@@ -41,7 +41,7 @@ using namespace WTF;
namespace JSC {
-#if PLATFORM(DARWIN) && ENABLE(JSC_MULTIPLE_THREADS)
+#if OS(DARWIN) && ENABLE(JSC_MULTIPLE_THREADS)
static pthread_once_t initializeThreadingKeyOnce = PTHREAD_ONCE_INIT;
#endif
@@ -49,6 +49,7 @@ static void initializeThreadingOnce()
{
WTF::initializeThreading();
initializeUString();
+ JSGlobalData::storeVPtrs();
#if ENABLE(JSC_MULTIPLE_THREADS)
s_dtoaP5Mutex = new Mutex;
initializeDates();
@@ -57,7 +58,7 @@ static void initializeThreadingOnce()
void initializeThreading()
{
-#if PLATFORM(DARWIN) && ENABLE(JSC_MULTIPLE_THREADS)
+#if OS(DARWIN) && ENABLE(JSC_MULTIPLE_THREADS)
pthread_once(&initializeThreadingKeyOnce, initializeThreadingOnce);
#else
static bool initializedThreading = false;
diff --git a/JavaScriptCore/runtime/InternalFunction.h b/JavaScriptCore/runtime/InternalFunction.h
index fa1e5aa..d19b82b 100644
--- a/JavaScriptCore/runtime/InternalFunction.h
+++ b/JavaScriptCore/runtime/InternalFunction.h
@@ -42,7 +42,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue proto)
{
- return Structure::create(proto, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
protected:
diff --git a/JavaScriptCore/runtime/JSAPIValueWrapper.h b/JavaScriptCore/runtime/JSAPIValueWrapper.h
index aca550e..b5016c2 100644
--- a/JavaScriptCore/runtime/JSAPIValueWrapper.h
+++ b/JavaScriptCore/runtime/JSAPIValueWrapper.h
@@ -39,7 +39,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren | OverridesGetPropertyNames));
+ return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren | OverridesGetPropertyNames), AnonymousSlotCount);
}
diff --git a/JavaScriptCore/runtime/JSActivation.h b/JavaScriptCore/runtime/JSActivation.h
index ee98191..761bee4 100644
--- a/JavaScriptCore/runtime/JSActivation.h
+++ b/JavaScriptCore/runtime/JSActivation.h
@@ -66,7 +66,7 @@ namespace JSC {
virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info;
- static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); }
+ static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); }
protected:
static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NeedsThisConversion | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
diff --git a/JavaScriptCore/runtime/JSArray.cpp b/JavaScriptCore/runtime/JSArray.cpp
index b16d3fa..2be7371 100644
--- a/JavaScriptCore/runtime/JSArray.cpp
+++ b/JavaScriptCore/runtime/JSArray.cpp
@@ -152,6 +152,7 @@ JSArray::JSArray(NonNullPassRefPtr<Structure> structure, unsigned initialLength)
m_storage->m_numValuesInVector = 0;
m_storage->m_sparseValueMap = 0;
m_storage->lazyCreationData = 0;
+ m_storage->reportedMapCapacity = 0;
JSValue* vector = m_storage->m_vector;
for (size_t i = 0; i < initialCapacity; ++i)
@@ -172,6 +173,8 @@ 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->reportedMapCapacity = 0;
size_t i = 0;
ArgList::const_iterator end = list.end();
@@ -185,6 +188,7 @@ JSArray::JSArray(NonNullPassRefPtr<Structure> structure, const ArgList& list)
JSArray::~JSArray()
{
+ ASSERT(vptr() == JSGlobalData::jsArrayVPtr);
checkConsistency(DestructorConsistencyCheck);
delete m_storage->m_sparseValueMap;
@@ -328,13 +332,24 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue valu
}
// We miss some cases where we could compact the storage, such as a large array that is being filled from the end
- // (which will only be compacted as we reach indices that are less than cutoff) - but this makes the check much faster.
+ // (which will only be compacted as we reach indices that are less than MIN_SPARSE_ARRAY_INDEX) - but this makes the check much faster.
if ((i > MAX_STORAGE_VECTOR_INDEX) || !isDenseEnoughForVector(i + 1, storage->m_numValuesInVector + 1)) {
if (!map) {
map = new SparseArrayValueMap;
storage->m_sparseValueMap = map;
}
- map->set(i, value);
+
+ pair<SparseArrayValueMap::iterator, bool> result = map->add(i, value);
+ if (!result.second) { // pre-existing entry
+ result.first->second = value;
+ return;
+ }
+
+ size_t capacity = map->capacity();
+ if (capacity != storage->reportedMapCapacity) {
+ Heap::heap(this)->reportExtraMemoryCost((capacity - storage->reportedMapCapacity) * (sizeof(unsigned) + sizeof(JSValue)));
+ storage->reportedMapCapacity = capacity;
+ }
return;
}
}
@@ -380,8 +395,6 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue valu
unsigned vectorLength = m_vectorLength;
- Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
-
if (newNumValuesInVector == storage->m_numValuesInVector + 1) {
for (unsigned j = vectorLength; j < newVectorLength; ++j)
storage->m_vector[j] = JSValue();
@@ -402,6 +415,8 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue valu
m_storage = storage;
checkConsistency();
+
+ Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
}
bool JSArray::deleteProperty(ExecState* exec, const Identifier& propertyName)
@@ -454,7 +469,7 @@ bool JSArray::deleteProperty(ExecState* exec, unsigned i)
return false;
}
-void JSArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
+void JSArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
// FIXME: Filling PropertyNameArray with an identifier for every integer
// is incredibly inefficient for large arrays. We need a different approach,
@@ -474,7 +489,10 @@ void JSArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNa
propertyNames.add(Identifier::from(exec, it->first));
}
- JSObject::getOwnPropertyNames(exec, propertyNames);
+ if (mode == IncludeDontEnumProperties)
+ propertyNames.add(exec->propertyNames().length);
+
+ JSObject::getOwnPropertyNames(exec, propertyNames, mode);
}
bool JSArray::increaseVectorLength(unsigned newLength)
@@ -492,13 +510,15 @@ bool JSArray::increaseVectorLength(unsigned newLength)
if (!tryFastRealloc(storage, storageSize(newVectorLength)).getValue(storage))
return false;
- Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
m_vectorLength = newVectorLength;
for (unsigned i = vectorLength; i < newVectorLength; ++i)
storage->m_vector[i] = JSValue();
m_storage = storage;
+
+ Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
+
return true;
}
diff --git a/JavaScriptCore/runtime/JSArray.h b/JavaScriptCore/runtime/JSArray.h
index 8c22451..ad6ee88 100644
--- a/JavaScriptCore/runtime/JSArray.h
+++ b/JavaScriptCore/runtime/JSArray.h
@@ -32,6 +32,7 @@ namespace JSC {
unsigned m_numValuesInVector;
SparseArrayValueMap* m_sparseValueMap;
void* lazyCreationData; // A JSArray subclass can use this to fill the vector lazily.
+ size_t reportedMapCapacity;
JSValue m_vector[1];
};
@@ -87,7 +88,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
inline void markChildrenDirect(MarkStack& markStack);
@@ -97,7 +98,7 @@ namespace JSC {
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
virtual bool deleteProperty(ExecState*, unsigned propertyName);
- virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&);
+ virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
virtual void markChildren(MarkStack&);
void* lazyCreationData();
diff --git a/JavaScriptCore/runtime/JSByteArray.cpp b/JavaScriptCore/runtime/JSByteArray.cpp
index 5e5003b..803a08c 100644
--- a/JavaScriptCore/runtime/JSByteArray.cpp
+++ b/JavaScriptCore/runtime/JSByteArray.cpp
@@ -42,10 +42,18 @@ JSByteArray::JSByteArray(ExecState* exec, NonNullPassRefPtr<Structure> structure
{
putDirect(exec->globalData().propertyNames->length, jsNumber(exec, m_storage->length()), ReadOnly | DontDelete);
}
-
+
+#if !ASSERT_DISABLED
+JSByteArray::~JSByteArray()
+{
+ ASSERT(vptr() == JSGlobalData::jsByteArrayVPtr);
+}
+#endif
+
+
PassRefPtr<Structure> JSByteArray::createStructure(JSValue prototype)
{
- PassRefPtr<Structure> result = Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ PassRefPtr<Structure> result = Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
return result;
}
@@ -96,12 +104,12 @@ void JSByteArray::put(ExecState* exec, unsigned propertyName, JSValue value)
setIndex(exec, propertyName, value);
}
-void JSByteArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
+void JSByteArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
unsigned length = m_storage->length();
for (unsigned i = 0; i < length; ++i)
propertyNames.add(Identifier::from(exec, i));
- JSObject::getOwnPropertyNames(exec, propertyNames);
+ JSObject::getOwnPropertyNames(exec, propertyNames, mode);
}
}
diff --git a/JavaScriptCore/runtime/JSByteArray.h b/JavaScriptCore/runtime/JSByteArray.h
index fe6e124..5b7adcf 100644
--- a/JavaScriptCore/runtime/JSByteArray.h
+++ b/JavaScriptCore/runtime/JSByteArray.h
@@ -33,7 +33,7 @@
namespace JSC {
class JSByteArray : public JSObject {
- friend struct VPtrSet;
+ friend class JSGlobalData;
public:
bool canAccessIndex(unsigned i) { return i < m_storage->length(); }
JSValue getIndex(ExecState* exec, unsigned i)
@@ -82,7 +82,7 @@ namespace JSC {
virtual void put(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&);
virtual void put(JSC::ExecState*, unsigned propertyName, JSC::JSValue);
- virtual void getOwnPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&);
+ virtual void getOwnPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
virtual const ClassInfo* classInfo() const { return m_classInfo; }
static const ClassInfo s_defaultInfo;
@@ -91,6 +91,10 @@ namespace JSC {
WTF::ByteArray* storage() const { return m_storage.get(); }
+#if !ASSERT_DISABLED
+ virtual ~JSByteArray();
+#endif
+
protected:
static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags;
diff --git a/JavaScriptCore/runtime/JSCell.cpp b/JavaScriptCore/runtime/JSCell.cpp
index 17410e2..869fbfc 100644
--- a/JavaScriptCore/runtime/JSCell.cpp
+++ b/JavaScriptCore/runtime/JSCell.cpp
@@ -59,10 +59,10 @@ static const union {
} doubles;
} NaNInf = { {
-#if PLATFORM(BIG_ENDIAN)
+#if CPU(BIG_ENDIAN)
{ 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 },
{ 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }
-#elif PLATFORM(MIDDLE_ENDIAN)
+#elif CPU(MIDDLE_ENDIAN)
{ 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 },
{ 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 }
#else
@@ -76,11 +76,6 @@ extern const double Inf = NaNInf.doubles.Inf_Double;
#endif // !(defined NAN && defined INFINITY)
-void* JSCell::operator new(size_t size, ExecState* exec)
-{
- return exec->heap()->allocate(size);
-}
-
bool JSCell::getUInt32(uint32_t&) const
{
return false;
diff --git a/JavaScriptCore/runtime/JSCell.h b/JavaScriptCore/runtime/JSCell.h
index c8ba2b8..3c8c829 100644
--- a/JavaScriptCore/runtime/JSCell.h
+++ b/JavaScriptCore/runtime/JSCell.h
@@ -43,14 +43,18 @@ namespace JSC {
friend class JSValue;
friend class JSAPIValueWrapper;
friend class JSZombie;
- friend struct VPtrSet;
+ friend class JSGlobalData;
private:
explicit JSCell(Structure*);
- JSCell(); // Only used for initializing Collector blocks.
virtual ~JSCell();
public:
+ static PassRefPtr<Structure> createDummyStructure()
+ {
+ return Structure::create(jsNull(), TypeInfo(UnspecifiedType), AnonymousSlotCount);
+ }
+
// Querying the type.
#if USE(JSVALUE32)
bool isNumber() const;
@@ -107,6 +111,10 @@ namespace JSC {
virtual JSString* toThisJSString(ExecState*);
virtual JSValue getJSNumber();
void* vptr() { return *reinterpret_cast<void**>(this); }
+ void setVPtr(void* vptr) { *reinterpret_cast<void**>(this) = vptr; }
+
+ protected:
+ static const unsigned AnonymousSlotCount = 0;
private:
// Base implementation; for non-object classes implements getPropertySlot.
@@ -122,11 +130,6 @@ namespace JSC {
{
}
- // Only used for initializing Collector blocks.
- inline JSCell::JSCell()
- {
- }
-
inline JSCell::~JSCell()
{
}
@@ -134,7 +137,7 @@ namespace JSC {
#if USE(JSVALUE32)
inline bool JSCell::isNumber() const
{
- return Heap::isNumber(const_cast<JSCell*>(this));
+ return m_structure->typeInfo().type() == NumberType;
}
#endif
@@ -162,6 +165,11 @@ namespace JSC {
return globalData->heap.allocate(size);
}
+ inline void* JSCell::operator new(size_t size, ExecState* exec)
+ {
+ return exec->heap()->allocate(size);
+ }
+
// --- JSValue inlines ----------------------------
inline bool JSValue::isString() const
diff --git a/JavaScriptCore/runtime/JSFunction.cpp b/JavaScriptCore/runtime/JSFunction.cpp
index 024e586..d213b4a 100644
--- a/JavaScriptCore/runtime/JSFunction.cpp
+++ b/JavaScriptCore/runtime/JSFunction.cpp
@@ -81,6 +81,8 @@ JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<FunctionExecutable> ex
JSFunction::~JSFunction()
{
+ ASSERT(vptr() == JSGlobalData::jsFunctionVPtr);
+
// JIT code for other functions may have had calls linked directly to the code for this function; these links
// are based on a check for the this pointer value for this JSFunction - which will no longer be valid once
// this memory is freed and may be reused (potentially for another, different JSFunction).
@@ -206,6 +208,17 @@ bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyN
return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
}
+void JSFunction::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ if (!isHostFunction() && (mode == IncludeDontEnumProperties)) {
+ propertyNames.add(exec->propertyNames().arguments);
+ propertyNames.add(exec->propertyNames().callee);
+ propertyNames.add(exec->propertyNames().caller);
+ propertyNames.add(exec->propertyNames().length);
+ }
+ Base::getOwnPropertyNames(exec, propertyNames, mode);
+}
+
void JSFunction::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
{
if (isHostFunction()) {
diff --git a/JavaScriptCore/runtime/JSFunction.h b/JavaScriptCore/runtime/JSFunction.h
index fcac9aa..8cd4b51 100644
--- a/JavaScriptCore/runtime/JSFunction.h
+++ b/JavaScriptCore/runtime/JSFunction.h
@@ -36,7 +36,7 @@ namespace JSC {
class JSFunction : public InternalFunction {
friend class JIT;
- friend struct VPtrSet;
+ friend class JSGlobalData;
typedef InternalFunction Base;
@@ -61,7 +61,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
NativeFunction nativeFunction()
@@ -82,6 +82,7 @@ namespace JSC {
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
+ virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
diff --git a/JavaScriptCore/runtime/JSGlobalData.cpp b/JavaScriptCore/runtime/JSGlobalData.cpp
index 234449f..45abc86 100644
--- a/JavaScriptCore/runtime/JSGlobalData.cpp
+++ b/JavaScriptCore/runtime/JSGlobalData.cpp
@@ -45,10 +45,10 @@
#include "JSNotAnObject.h"
#include "JSPropertyNameIterator.h"
#include "JSStaticScopeObject.h"
-#include "Parser.h"
#include "Lexer.h"
#include "Lookup.h"
#include "Nodes.h"
+#include "Parser.h"
#if ENABLE(JSC_MULTIPLE_THREADS)
#include <wtf/Threading.h>
@@ -71,42 +71,38 @@ extern JSC_CONST_HASHTABLE HashTable regExpTable;
extern JSC_CONST_HASHTABLE HashTable regExpConstructorTable;
extern JSC_CONST_HASHTABLE HashTable stringTable;
-struct VPtrSet {
- VPtrSet();
-
- void* jsArrayVPtr;
- void* jsByteArrayVPtr;
- void* jsStringVPtr;
- void* jsFunctionVPtr;
-};
+void* JSGlobalData::jsArrayVPtr;
+void* JSGlobalData::jsByteArrayVPtr;
+void* JSGlobalData::jsStringVPtr;
+void* JSGlobalData::jsFunctionVPtr;
-VPtrSet::VPtrSet()
+void JSGlobalData::storeVPtrs()
{
CollectorCell cell;
void* storage = &cell;
COMPILE_ASSERT(sizeof(JSArray) <= sizeof(CollectorCell), sizeof_JSArray_must_be_less_than_CollectorCell);
JSCell* jsArray = new (storage) JSArray(JSArray::createStructure(jsNull()));
- jsArrayVPtr = jsArray->vptr();
+ JSGlobalData::jsArrayVPtr = jsArray->vptr();
jsArray->~JSCell();
COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(CollectorCell), sizeof_JSByteArray_must_be_less_than_CollectorCell);
JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack);
- jsByteArrayVPtr = jsByteArray->vptr();
+ JSGlobalData::jsByteArrayVPtr = jsByteArray->vptr();
jsByteArray->~JSCell();
COMPILE_ASSERT(sizeof(JSString) <= sizeof(CollectorCell), sizeof_JSString_must_be_less_than_CollectorCell);
JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack);
- jsStringVPtr = jsString->vptr();
+ JSGlobalData::jsStringVPtr = jsString->vptr();
jsString->~JSCell();
COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(CollectorCell), sizeof_JSFunction_must_be_less_than_CollectorCell);
JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull()));
- jsFunctionVPtr = jsFunction->vptr();
+ JSGlobalData::jsFunctionVPtr = jsFunction->vptr();
jsFunction->~JSCell();
}
-JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet)
+JSGlobalData::JSGlobalData(bool isShared)
: isSharedInstance(isShared)
, clientData(0)
, arrayTable(fastNew<HashTable>(JSC::arrayTable))
@@ -126,13 +122,10 @@ JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet)
, propertyNameIteratorStructure(JSPropertyNameIterator::createStructure(jsNull()))
, getterSetterStructure(GetterSetter::createStructure(jsNull()))
, apiWrapperStructure(JSAPIValueWrapper::createStructure(jsNull()))
+ , dummyMarkableCellStructure(JSCell::createDummyStructure())
#if USE(JSVALUE32)
, numberStructure(JSNumberCell::createStructure(jsNull()))
#endif
- , jsArrayVPtr(vptrSet.jsArrayVPtr)
- , jsByteArrayVPtr(vptrSet.jsByteArrayVPtr)
- , jsStringVPtr(vptrSet.jsStringVPtr)
- , jsFunctionVPtr(vptrSet.jsFunctionVPtr)
, identifierTable(createIdentifierTable())
, propertyNames(new CommonIdentifiers(this))
, emptyList(new MarkedArgumentBuffer)
@@ -148,7 +141,7 @@ JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet)
, dynamicGlobalObject(0)
, functionCodeBlockBeingReparsed(0)
, firstStringifierToMark(0)
- , markStack(vptrSet.jsArrayVPtr)
+ , markStack(jsArrayVPtr)
, cachedUTCOffset(NaN)
, weakRandom(static_cast<int>(currentTime()))
#ifndef NDEBUG
@@ -201,9 +194,17 @@ JSGlobalData::~JSGlobalData()
delete clientData;
}
-PassRefPtr<JSGlobalData> JSGlobalData::create(bool isShared)
+PassRefPtr<JSGlobalData> JSGlobalData::createNonDefault()
+{
+ return adoptRef(new JSGlobalData(false));
+}
+
+PassRefPtr<JSGlobalData> JSGlobalData::create()
{
- return adoptRef(new JSGlobalData(isShared, VPtrSet()));
+ JSGlobalData* globalData = new JSGlobalData(false);
+ setDefaultIdentifierTable(globalData->identifierTable);
+ setCurrentIdentifierTable(globalData->identifierTable);
+ return adoptRef(globalData);
}
PassRefPtr<JSGlobalData> JSGlobalData::createLeaked()
@@ -223,7 +224,7 @@ JSGlobalData& JSGlobalData::sharedInstance()
{
JSGlobalData*& instance = sharedInstanceInternal();
if (!instance) {
- instance = create(true).releaseRef();
+ instance = new JSGlobalData(true);
#if ENABLE(JSC_MULTIPLE_THREADS)
instance->makeUsableFromMultipleThreads();
#endif
diff --git a/JavaScriptCore/runtime/JSGlobalData.h b/JavaScriptCore/runtime/JSGlobalData.h
index f0c1b5c..0f1f3c6 100644
--- a/JavaScriptCore/runtime/JSGlobalData.h
+++ b/JavaScriptCore/runtime/JSGlobalData.h
@@ -62,7 +62,6 @@ namespace JSC {
struct HashTable;
struct Instruction;
- struct VPtrSet;
struct DSTOffsetCache {
DSTOffsetCache()
@@ -93,8 +92,9 @@ namespace JSC {
static bool sharedInstanceExists();
static JSGlobalData& sharedInstance();
- static PassRefPtr<JSGlobalData> create(bool isShared = false);
+ static PassRefPtr<JSGlobalData> create();
static PassRefPtr<JSGlobalData> createLeaked();
+ static PassRefPtr<JSGlobalData> createNonDefault();
~JSGlobalData();
#if ENABLE(JSC_MULTIPLE_THREADS)
@@ -123,15 +123,17 @@ namespace JSC {
RefPtr<Structure> propertyNameIteratorStructure;
RefPtr<Structure> getterSetterStructure;
RefPtr<Structure> apiWrapperStructure;
+ RefPtr<Structure> dummyMarkableCellStructure;
#if USE(JSVALUE32)
RefPtr<Structure> numberStructure;
#endif
- void* jsArrayVPtr;
- void* jsByteArrayVPtr;
- void* jsStringVPtr;
- void* jsFunctionVPtr;
+ static void storeVPtrs();
+ static JS_EXPORTDATA void* jsArrayVPtr;
+ static JS_EXPORTDATA void* jsByteArrayVPtr;
+ static JS_EXPORTDATA void* jsStringVPtr;
+ static JS_EXPORTDATA void* jsFunctionVPtr;
IdentifierTable* identifierTable;
CommonIdentifiers* propertyNames;
@@ -192,7 +194,7 @@ namespace JSC {
void stopSampling();
void dumpSampleData(ExecState* exec);
private:
- JSGlobalData(bool isShared, const VPtrSet&);
+ JSGlobalData(bool isShared);
static JSGlobalData*& sharedInstanceInternal();
void createNativeThunk();
};
diff --git a/JavaScriptCore/runtime/JSGlobalObject.cpp b/JavaScriptCore/runtime/JSGlobalObject.cpp
index cf3f1d1..4bf0a69 100644
--- a/JavaScriptCore/runtime/JSGlobalObject.cpp
+++ b/JavaScriptCore/runtime/JSGlobalObject.cpp
@@ -128,6 +128,8 @@ void JSGlobalObject::init(JSObject* thisValue)
{
ASSERT(JSLock::currentThreadIsHoldingLock());
+ structure()->disableSpecificFunctionTracking();
+
d()->globalData = Heap::heap(this)->globalData();
d()->globalScopeChain = ScopeChain(this, d()->globalData.get(), this, thisValue);
diff --git a/JavaScriptCore/runtime/JSGlobalObject.h b/JavaScriptCore/runtime/JSGlobalObject.h
index 9e4ef49..bbb6d5e 100644
--- a/JavaScriptCore/runtime/JSGlobalObject.h
+++ b/JavaScriptCore/runtime/JSGlobalObject.h
@@ -267,7 +267,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
protected:
@@ -413,11 +413,21 @@ namespace JSC {
{
return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure());
}
+
+ inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject)
+ {
+ return new (exec) JSObject(globalObject->emptyObjectStructure());
+ }
inline JSArray* constructEmptyArray(ExecState* exec)
{
return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure());
}
+
+ inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject)
+ {
+ return new (exec) JSArray(globalObject->arrayStructure());
+ }
inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength)
{
diff --git a/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
index dc32718..0bc1274 100644
--- a/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
+++ b/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
@@ -27,14 +27,16 @@
#include "CallFrame.h"
#include "GlobalEvalFunction.h"
+#include "Interpreter.h"
#include "JSGlobalObject.h"
-#include "LiteralParser.h"
#include "JSString.h"
-#include "Interpreter.h"
-#include "Parser.h"
-#include "dtoa.h"
#include "Lexer.h"
+#include "LiteralParser.h"
#include "Nodes.h"
+#include "Parser.h"
+#include "StringBuilder.h"
+#include "StringExtras.h"
+#include "dtoa.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -55,24 +57,24 @@ static JSValue encode(ExecState* exec, const ArgList& args, const char* doNotEsc
if (!cstr.c_str())
return throwError(exec, URIError, "String contained an illegal UTF-16 sequence.");
- UString result = "";
+ StringBuilder builder;
const char* p = cstr.c_str();
for (size_t k = 0; k < cstr.size(); k++, p++) {
char c = *p;
if (c && strchr(doNotEscape, c))
- result.append(c);
+ builder.append(c);
else {
char tmp[4];
- sprintf(tmp, "%%%02X", static_cast<unsigned char>(c));
- result += tmp;
+ snprintf(tmp, 4, "%%%02X", static_cast<unsigned char>(c));
+ builder.append((const char*)tmp);
}
}
- return jsString(exec, result);
+ return jsString(exec, builder.release());
}
static JSValue decode(ExecState* exec, const ArgList& args, const char* doNotUnescape, bool strict)
{
- UString result = "";
+ StringBuilder builder;
UString str = args.at(0).toString(exec);
int k = 0;
int len = str.size();
@@ -106,7 +108,7 @@ static JSValue decode(ExecState* exec, const ArgList& args, const char* doNotUne
charLen = 0;
else if (character >= 0x10000) {
// Convert to surrogate pair.
- result.append(static_cast<UChar>(0xD800 | ((character - 0x10000) >> 10)));
+ builder.append(static_cast<UChar>(0xD800 | ((character - 0x10000) >> 10)));
u = static_cast<UChar>(0xDC00 | ((character - 0x10000) & 0x3FF));
} else
u = static_cast<UChar>(character);
@@ -131,9 +133,9 @@ static JSValue decode(ExecState* exec, const ArgList& args, const char* doNotUne
}
}
k++;
- result.append(c);
+ builder.append(c);
}
- return jsString(exec, result);
+ return jsString(exec, builder.release());
}
bool isStrWhiteSpace(UChar c)
@@ -376,7 +378,7 @@ JSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec, JSObject*, JSValue, cons
"0123456789"
"*+-./@_";
- UString result = "";
+ StringBuilder builder;
UString s;
UString str = args.at(0).toString(exec);
const UChar* c = str.data();
@@ -393,15 +395,15 @@ JSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec, JSObject*, JSValue, cons
sprintf(tmp, "%%%02X", u);
s = UString(tmp);
}
- result += s;
+ builder.append(s);
}
- return jsString(exec, result);
+ return jsString(exec, builder.release());
}
JSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec, JSObject*, JSValue, const ArgList& args)
{
- UString result = "";
+ StringBuilder builder;
UString str = args.at(0).toString(exec);
int k = 0;
int len = str.size();
@@ -420,10 +422,10 @@ JSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec, JSObject*, JSValue, co
k += 2;
}
k++;
- result.append(*c);
+ builder.append(*c);
}
- return jsString(exec, result);
+ return jsString(exec, builder.release());
}
#ifndef NDEBUG
diff --git a/JavaScriptCore/runtime/JSNotAnObject.cpp b/JavaScriptCore/runtime/JSNotAnObject.cpp
index c36dc10..f4764e2 100644
--- a/JavaScriptCore/runtime/JSNotAnObject.cpp
+++ b/JavaScriptCore/runtime/JSNotAnObject.cpp
@@ -121,7 +121,7 @@ bool JSNotAnObject::deleteProperty(ExecState* exec, unsigned)
return false;
}
-void JSNotAnObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray&)
+void JSNotAnObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray&, EnumerationMode)
{
ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
}
diff --git a/JavaScriptCore/runtime/JSNotAnObject.h b/JavaScriptCore/runtime/JSNotAnObject.h
index a271c4e..339d41f 100644
--- a/JavaScriptCore/runtime/JSNotAnObject.h
+++ b/JavaScriptCore/runtime/JSNotAnObject.h
@@ -62,7 +62,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
private:
@@ -91,7 +91,7 @@ namespace JSC {
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
virtual bool deleteProperty(ExecState*, unsigned propertyName);
- virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&);
+ virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
JSNotAnObjectErrorStub* m_exception;
};
diff --git a/JavaScriptCore/runtime/JSNumberCell.h b/JavaScriptCore/runtime/JSNumberCell.h
index e9e2470..bcb506b 100644
--- a/JavaScriptCore/runtime/JSNumberCell.h
+++ b/JavaScriptCore/runtime/JSNumberCell.h
@@ -76,7 +76,7 @@ namespace JSC {
return globalData->heap.allocateNumber(size);
}
- static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(NumberType, OverridesGetOwnPropertySlot | NeedsThisConversion)); }
+ static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(NumberType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount); }
private:
JSNumberCell(JSGlobalData* globalData, double value)
diff --git a/JavaScriptCore/runtime/JSONObject.cpp b/JavaScriptCore/runtime/JSONObject.cpp
index cc7f6d9..ce0dcff 100644
--- a/JavaScriptCore/runtime/JSONObject.cpp
+++ b/JavaScriptCore/runtime/JSONObject.cpp
@@ -32,6 +32,7 @@
#include "JSArray.h"
#include "LiteralParser.h"
#include "PropertyNameArray.h"
+#include "StringBuilder.h"
#include <wtf/MathExtras.h>
namespace JSC {
@@ -70,24 +71,6 @@ public:
void markAggregate(MarkStack&);
private:
- class StringBuilder : public Vector<UChar> {
- public:
- using Vector<UChar>::append;
-
- inline void append(const char* str)
- {
- size_t len = strlen(str);
- reserveCapacity(size() + len);
- for (size_t i = 0; i < len; i++)
- Vector<UChar>::append(str[i]);
- }
-
- inline void append(const UString& str)
- {
- append(str.data(), str.size());
- }
- };
-
class Holder {
public:
Holder(JSObject*);
@@ -285,9 +268,7 @@ JSValue Stringifier::stringify(JSValue value)
if (m_exec->hadException())
return jsNull();
- result.shrinkToFit();
- size_t length = result.size();
- return jsString(m_exec, UString(result.releaseBuffer(), length, false));
+ return jsString(m_exec, result.release());
}
void Stringifier::appendQuotedString(StringBuilder& builder, const UString& value)
@@ -477,7 +458,7 @@ inline void Stringifier::indent()
// Use a single shared string, m_repeatedGap, so we don't keep allocating new ones as we indent and unindent.
int newSize = m_indent.size() + m_gap.size();
if (newSize > m_repeatedGap.size())
- m_repeatedGap.append(m_gap);
+ m_repeatedGap = makeString(m_repeatedGap, m_gap);
ASSERT(newSize <= m_repeatedGap.size());
m_indent = m_repeatedGap.substr(0, newSize);
}
@@ -520,7 +501,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui
m_propertyNames = stringifier.m_arrayReplacerPropertyNames.data();
else {
PropertyNameArray objectPropertyNames(exec);
- m_object->getPropertyNames(exec, objectPropertyNames);
+ m_object->getOwnPropertyNames(exec, objectPropertyNames);
m_propertyNames = objectPropertyNames.releaseData();
}
m_size = m_propertyNames->propertyNameVector().size();
@@ -765,7 +746,7 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered)
objectStack.append(object);
indexStack.append(0);
propertyStack.append(PropertyNameArray(m_exec));
- object->getPropertyNames(m_exec, propertyStack.last());
+ object->getOwnPropertyNames(m_exec, propertyStack.last());
// fallthrough
}
objectStartVisitMember:
diff --git a/JavaScriptCore/runtime/JSONObject.h b/JavaScriptCore/runtime/JSONObject.h
index ec3fa40..905e4bc 100644
--- a/JavaScriptCore/runtime/JSONObject.h
+++ b/JavaScriptCore/runtime/JSONObject.h
@@ -41,7 +41,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
static void markStringifiers(MarkStack&, Stringifier*);
diff --git a/JavaScriptCore/runtime/JSObject.cpp b/JavaScriptCore/runtime/JSObject.cpp
index ed9fdc2..d9500aa 100644
--- a/JavaScriptCore/runtime/JSObject.cpp
+++ b/JavaScriptCore/runtime/JSObject.cpp
@@ -42,7 +42,7 @@ namespace JSC {
ASSERT_CLASS_FITS_IN_CELL(JSObject);
-static inline void getEnumerablePropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames)
+static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode)
{
// Add properties from the static hashtables of properties
for (; classInfo; classInfo = classInfo->parentClass) {
@@ -55,7 +55,7 @@ static inline void getEnumerablePropertyNames(ExecState* exec, const ClassInfo*
int hashSizeMask = table->compactSize - 1;
const HashEntry* entry = table->table;
for (int i = 0; i <= hashSizeMask; ++i, ++entry) {
- if (entry->key() && !(entry->attributes() & DontEnum))
+ if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties)))
propertyNames.add(entry->key());
}
}
@@ -425,9 +425,9 @@ bool JSObject::getPropertySpecificValue(ExecState*, const Identifier& propertyNa
return false;
}
-void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
+void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
- getOwnPropertyNames(exec, propertyNames);
+ getOwnPropertyNames(exec, propertyNames, mode);
if (prototype().isNull())
return;
@@ -435,10 +435,10 @@ void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyName
JSObject* prototype = asObject(this->prototype());
while(1) {
if (prototype->structure()->typeInfo().overridesGetPropertyNames()) {
- prototype->getPropertyNames(exec, propertyNames);
+ prototype->getPropertyNames(exec, propertyNames, mode);
break;
}
- prototype->getOwnPropertyNames(exec, propertyNames);
+ prototype->getOwnPropertyNames(exec, propertyNames, mode);
JSValue nextProto = prototype->prototype();
if (nextProto.isNull())
break;
@@ -446,10 +446,10 @@ void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyName
}
}
-void JSObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
+void JSObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
- m_structure->getEnumerablePropertyNames(propertyNames);
- getEnumerablePropertyNames(exec, classInfo(), propertyNames);
+ m_structure->getPropertyNames(propertyNames, mode);
+ getClassPropertyNames(exec, classInfo(), propertyNames, mode);
}
bool JSObject::toBoolean(ExecState*) const
diff --git a/JavaScriptCore/runtime/JSObject.h b/JavaScriptCore/runtime/JSObject.h
index a5da267..2b31a65 100644
--- a/JavaScriptCore/runtime/JSObject.h
+++ b/JavaScriptCore/runtime/JSObject.h
@@ -122,8 +122,8 @@ namespace JSC {
virtual bool hasInstance(ExecState*, JSValue, JSValue prototypeProperty);
- virtual void getPropertyNames(ExecState*, PropertyNameArray&);
- virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&);
+ virtual void getPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
+ virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
@@ -206,7 +206,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
void flattenDictionaryObject()
@@ -217,13 +217,14 @@ namespace JSC {
protected:
static const unsigned StructureFlags = 0;
- void addAnonymousSlots(unsigned count);
void putAnonymousValue(unsigned index, JSValue value)
{
+ ASSERT(index < m_structure->anonymousSlotCount());
*locationForOffset(index) = value;
}
- JSValue getAnonymousValue(unsigned index)
+ JSValue getAnonymousValue(unsigned index) const
{
+ ASSERT(index < m_structure->anonymousSlotCount());
return *locationForOffset(index);
}
@@ -381,7 +382,7 @@ ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, const Identif
// It may seem crazy to inline a function this large but it makes a big difference
// since this is function very hot in variable lookup
-inline bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
JSObject* object = this;
while (true) {
@@ -394,7 +395,7 @@ inline bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propert
}
}
-inline bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
+ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
{
JSObject* object = this;
while (true) {
@@ -528,17 +529,6 @@ inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi
putDirectInternal(propertyName, value, attributes, false, slot, getJSFunction(globalData, value));
}
-inline void JSObject::addAnonymousSlots(unsigned count)
-{
- size_t currentCapacity = m_structure->propertyStorageCapacity();
- RefPtr<Structure> structure = Structure::addAnonymousSlotsTransition(m_structure, count);
-
- if (currentCapacity != structure->propertyStorageCapacity())
- allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
-
- setStructure(structure.release());
-}
-
inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
{
ASSERT(value);
diff --git a/JavaScriptCore/runtime/JSPropertyNameIterator.h b/JavaScriptCore/runtime/JSPropertyNameIterator.h
index 529ae8b..d18c2c5 100644
--- a/JavaScriptCore/runtime/JSPropertyNameIterator.h
+++ b/JavaScriptCore/runtime/JSPropertyNameIterator.h
@@ -47,7 +47,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren));
+ return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren), AnonymousSlotCount);
}
virtual bool isPropertyNameIterator() const { return true; }
diff --git a/JavaScriptCore/runtime/JSStaticScopeObject.h b/JavaScriptCore/runtime/JSStaticScopeObject.h
index 2542878..4d156d4 100644
--- a/JavaScriptCore/runtime/JSStaticScopeObject.h
+++ b/JavaScriptCore/runtime/JSStaticScopeObject.h
@@ -57,7 +57,7 @@ namespace JSC{
virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&);
void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes);
- static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); }
+ static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); }
protected:
static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NeedsThisConversion | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
diff --git a/JavaScriptCore/runtime/JSString.cpp b/JavaScriptCore/runtime/JSString.cpp
index 28ae6f7..1e23a15 100644
--- a/JavaScriptCore/runtime/JSString.cpp
+++ b/JavaScriptCore/runtime/JSString.cpp
@@ -66,20 +66,6 @@ JSString::Rope::~Rope()
destructNonRecursive();
}
-#define ROPE_COPY_CHARS_INLINE_CUTOFF 20
-
-static inline void copyChars(UChar* destination, const UChar* source, unsigned numCharacters)
-{
-#ifdef ROPE_COPY_CHARS_INLINE_CUTOFF
- if (numCharacters <= ROPE_COPY_CHARS_INLINE_CUTOFF) {
- for (unsigned i = 0; i < numCharacters; ++i)
- destination[i] = source[i];
- return;
- }
-#endif
- memcpy(destination, source, numCharacters * sizeof(UChar));
-}
-
// 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
@@ -96,13 +82,16 @@ void JSString::resolveRope(ExecState* exec) const
// Allocate the buffer to hold the final string, position initially points to the end.
UChar* buffer;
- if (!tryFastMalloc(m_stringLength * sizeof(UChar)).getValue(buffer)) {
- for (unsigned i = 0; i < m_ropeLength; ++i)
+ if (PassRefPtr<UStringImpl> newImpl = UStringImpl::tryCreateUninitialized(m_stringLength, buffer))
+ m_value = newImpl;
+ else {
+ for (unsigned i = 0; i < m_ropeLength; ++i) {
m_fibers[i].deref();
+ m_fibers[i] = static_cast<void*>(0);
+ }
m_ropeLength = 0;
ASSERT(!isRope());
ASSERT(m_value == UString());
-
throwOutOfMemoryError(exec);
return;
}
@@ -125,17 +114,18 @@ void JSString::resolveRope(ExecState* exec) const
currentFiber = rope->fibers(ropeLengthMinusOne);
} else {
UString::Rep* string = currentFiber.string();
- unsigned length = string->len;
+ unsigned length = string->size();
position -= length;
- copyChars(position, string->data(), length);
+ UStringImpl::copyChars(position, string->data(), length);
// Was this the last item in the work queue?
if (workQueue.isEmpty()) {
// Create a string from the UChar buffer, clear the rope RefPtr.
ASSERT(buffer == position);
- m_value = UString::Rep::create(buffer, m_stringLength);
- for (unsigned i = 0; i < m_ropeLength; ++i)
+ for (unsigned i = 0; i < m_ropeLength; ++i) {
m_fibers[i].deref();
+ m_fibers[i] = static_cast<void*>(0);
+ }
m_ropeLength = 0;
ASSERT(!isRope());
diff --git a/JavaScriptCore/runtime/JSString.h b/JavaScriptCore/runtime/JSString.h
index 93b11f1..7288b6f 100644
--- a/JavaScriptCore/runtime/JSString.h
+++ b/JavaScriptCore/runtime/JSString.h
@@ -59,10 +59,13 @@ namespace JSC {
JSString* jsOwnedString(JSGlobalData*, const UString&);
JSString* jsOwnedString(ExecState*, const UString&);
- class JSString : public JSCell {
+ typedef void (*JSStringFinalizerCallback)(JSString*, void* context);
+ JSString* jsStringWithFinalizer(ExecState*, const UString&, JSStringFinalizerCallback callback, void* context);
+
+ class JS_EXPORTCLASS JSString : public JSCell {
public:
friend class JIT;
- friend struct VPtrSet;
+ friend class JSGlobalData;
// A Rope is a string composed of a set of substrings.
class Rope : public RefCounted<Rope> {
@@ -71,10 +74,12 @@ namespace JSC {
// Each Fiber in a rope is either UString::Rep or another Rope.
class Fiber {
public:
- Fiber() {}
+ 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())
@@ -96,7 +101,7 @@ namespace JSC {
{
if (isString()) {
UString::Rep* rep = string();
- return rep->ref()->len;
+ return rep->ref()->size();
} else {
Rope* r = rope();
r->ref();
@@ -109,6 +114,7 @@ namespace JSC {
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;
};
@@ -135,7 +141,7 @@ namespace JSC {
{
UString::Rep* rep = string.rep();
m_fibers[index++] = Fiber(rep);
- m_stringLength += rep->ref()->len;
+ m_stringLength += rep->ref()->size();
}
void append(unsigned& index, JSString* jsString)
{
@@ -159,7 +165,7 @@ namespace JSC {
Fiber m_fibers[1];
};
- JSString(JSGlobalData* globalData, const UString& value)
+ ALWAYS_INLINE JSString(JSGlobalData* globalData, const UString& value)
: JSCell(globalData->stringStructure.get())
, m_stringLength(value.size())
, m_value(value)
@@ -219,10 +225,28 @@ namespace JSC {
ASSERT(index == s_maxInternalRopeLength);
}
+ JSString(JSGlobalData* globalData, const UString& value, JSStringFinalizerCallback finalizer, void* context)
+ : JSCell(globalData->stringStructure.get())
+ , m_stringLength(value.size())
+ , m_value(value)
+ , m_ropeLength(0)
+ {
+ // nasty hack because we can't union non-POD types
+ m_fibers[0] = reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(finalizer));
+ m_fibers[1] = context;
+ Heap::heap(this)->reportExtraMemoryCost(value.cost());
+ }
+
~JSString()
{
+ ASSERT(vptr() == JSGlobalData::jsStringVPtr);
for (unsigned i = 0; i < m_ropeLength; ++i)
m_fibers[i].deref();
+
+ if (!m_ropeLength && m_fibers[0].nonFiber()) {
+ JSStringFinalizerCallback finalizer = reinterpret_cast<JSStringFinalizerCallback>(m_fibers[0].nonFiber());
+ finalizer(this, m_fibers[1].nonFiber());
+ }
}
const UString& value(ExecState* exec) const
@@ -246,7 +270,7 @@ namespace JSC {
bool canGetIndex(unsigned i) { return i < m_stringLength; }
JSString* getIndex(ExecState*, unsigned);
- static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion)); }
+ static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount); }
private:
enum VPtrStealingHackType { VPtrStealingHack };
@@ -312,10 +336,22 @@ namespace JSC {
friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2);
friend JSValue jsString(ExecState* exec, Register* strings, unsigned count);
+ friend JSValue jsString(ExecState* exec, JSValue thisValue, const ArgList& args);
+ friend JSString* jsStringWithFinalizer(ExecState*, const UString&, JSStringFinalizerCallback callback, void* context);
};
JSString* asString(JSValue);
+ // When an object is created from a different DLL, MSVC changes vptr to a "local" one right after invoking a constructor,
+ // see <http://groups.google.com/group/microsoft.public.vc.language/msg/55cdcefeaf770212>.
+ // This breaks isJSString(), and we don't need that hack anyway, so we change vptr back to primary one.
+ // The below function must be called by any inline function that invokes a JSString constructor.
+#if COMPILER(MSVC) && !defined(BUILDING_JavaScriptCore)
+ inline JSString* fixupVPtr(JSGlobalData* globalData, JSString* string) { string->setVPtr(globalData->jsStringVPtr); return string; }
+#else
+ inline JSString* fixupVPtr(JSGlobalData*, JSString* string) { return string; }
+#endif
+
inline JSString* asString(JSValue value)
{
ASSERT(asCell(value)->isString());
@@ -331,7 +367,7 @@ namespace JSC {
{
if (c <= 0xFF)
return globalData->smallStrings.singleCharacterString(globalData, c);
- return new (globalData) JSString(globalData, UString(&c, 1));
+ return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(&c, 1)));
}
inline JSString* jsSingleCharacterSubstring(JSGlobalData* globalData, const UString& s, unsigned offset)
@@ -340,7 +376,7 @@ namespace JSC {
UChar c = s.data()[offset];
if (c <= 0xFF)
return globalData->smallStrings.singleCharacterString(globalData, c);
- return new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, 1)));
+ return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, 1))));
}
inline JSString* jsNontrivialString(JSGlobalData* globalData, const char* s)
@@ -348,13 +384,13 @@ namespace JSC {
ASSERT(s);
ASSERT(s[0]);
ASSERT(s[1]);
- return new (globalData) JSString(globalData, s);
+ return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
}
inline JSString* jsNontrivialString(JSGlobalData* globalData, const UString& s)
{
ASSERT(s.size() > 1);
- return new (globalData) JSString(globalData, s);
+ return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
}
inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
@@ -373,7 +409,14 @@ namespace JSC {
if (c <= 0xFF)
return globalData->smallStrings.singleCharacterString(globalData, c);
}
- return new (globalData) JSString(globalData, s);
+ return fixupVPtr(globalData, new (globalData) JSString(globalData, s));
+ }
+
+ inline JSString* jsStringWithFinalizer(ExecState* exec, const UString& s, JSStringFinalizerCallback callback, void* context)
+ {
+ ASSERT(s.size() && (s.size() > 1 || s.data()[0] > 0xFF));
+ JSGlobalData* globalData = &exec->globalData();
+ return fixupVPtr(globalData, new (globalData) JSString(globalData, s, callback, context));
}
inline JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length)
@@ -388,7 +431,7 @@ namespace JSC {
if (c <= 0xFF)
return globalData->smallStrings.singleCharacterString(globalData, c);
}
- return new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, length)));
+ return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, length)), JSString::HasOtherOwner));
}
inline JSString* jsOwnedString(JSGlobalData* globalData, const UString& s)
@@ -401,7 +444,7 @@ namespace JSC {
if (c <= 0xFF)
return globalData->smallStrings.singleCharacterString(globalData, c);
}
- return new (globalData) JSString(globalData, s, JSString::HasOtherOwner);
+ return fixupVPtr(globalData, new (globalData) JSString(globalData, s, JSString::HasOtherOwner));
}
inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); }
@@ -469,6 +512,26 @@ namespace JSC {
return asCell()->toString(exec);
}
+ inline UString JSValue::toPrimitiveString(ExecState* exec) const
+ {
+ if (isString())
+ return static_cast<JSString*>(asCell())->value(exec);
+ if (isInt32())
+ return exec->globalData().numericStrings.add(asInt32());
+ if (isDouble())
+ return exec->globalData().numericStrings.add(asDouble());
+ if (isTrue())
+ return "true";
+ if (isFalse())
+ return "false";
+ if (isNull())
+ return "null";
+ if (isUndefined())
+ return "undefined";
+ ASSERT(isCell());
+ return asCell()->toPrimitive(exec, NoPreference).toString(exec);
+ }
+
} // namespace JSC
#endif // JSString_h
diff --git a/JavaScriptCore/runtime/JSValue.h b/JavaScriptCore/runtime/JSValue.h
index fa5b5c0..6da921f 100644
--- a/JavaScriptCore/runtime/JSValue.h
+++ b/JavaScriptCore/runtime/JSValue.h
@@ -158,6 +158,7 @@ namespace JSC {
double toNumber(ExecState*) const;
JSValue toJSNumber(ExecState*) const; // Fast path for when you expect that the value is an immediate number.
UString toString(ExecState*) const;
+ UString toPrimitiveString(ExecState*) const;
JSObject* toObject(ExecState*) const;
// Integer conversions.
@@ -234,7 +235,7 @@ namespace JSC {
union {
EncodedJSValue asEncodedJSValue;
double asDouble;
-#if PLATFORM(BIG_ENDIAN)
+#if CPU(BIG_ENDIAN)
struct {
int32_t tag;
int32_t payload;
diff --git a/JavaScriptCore/runtime/JSVariableObject.cpp b/JavaScriptCore/runtime/JSVariableObject.cpp
index 3aa9e62..7365001 100644
--- a/JavaScriptCore/runtime/JSVariableObject.cpp
+++ b/JavaScriptCore/runtime/JSVariableObject.cpp
@@ -42,15 +42,15 @@ bool JSVariableObject::deleteProperty(ExecState* exec, const Identifier& propert
return JSObject::deleteProperty(exec, propertyName);
}
-void JSVariableObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
+void JSVariableObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
SymbolTable::const_iterator end = symbolTable().end();
for (SymbolTable::const_iterator it = symbolTable().begin(); it != end; ++it) {
- if (!(it->second.getAttributes() & DontEnum))
+ if (!(it->second.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties))
propertyNames.add(Identifier(exec, it->first.get()));
}
- JSObject::getOwnPropertyNames(exec, propertyNames);
+ JSObject::getOwnPropertyNames(exec, propertyNames, mode);
}
bool JSVariableObject::isVariableObject() const
diff --git a/JavaScriptCore/runtime/JSVariableObject.h b/JavaScriptCore/runtime/JSVariableObject.h
index 15d6ff5..6c679ce 100644
--- a/JavaScriptCore/runtime/JSVariableObject.h
+++ b/JavaScriptCore/runtime/JSVariableObject.h
@@ -49,7 +49,7 @@ namespace JSC {
virtual void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes) = 0;
virtual bool deleteProperty(ExecState*, const Identifier&);
- virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&);
+ virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
virtual bool isVariableObject() const;
virtual bool isDynamicScope() const = 0;
@@ -58,7 +58,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
protected:
diff --git a/JavaScriptCore/runtime/JSWrapperObject.h b/JavaScriptCore/runtime/JSWrapperObject.h
index 191ff3b..f19cd30 100644
--- a/JavaScriptCore/runtime/JSWrapperObject.h
+++ b/JavaScriptCore/runtime/JSWrapperObject.h
@@ -38,9 +38,12 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
+ protected:
+ static const unsigned AnonymousSlotCount = 1 + JSObject::AnonymousSlotCount;
+
private:
virtual void markChildren(MarkStack&);
@@ -50,7 +53,6 @@ namespace JSC {
inline JSWrapperObject::JSWrapperObject(NonNullPassRefPtr<Structure> structure)
: JSObject(structure)
{
- addAnonymousSlots(1);
putAnonymousValue(0, jsNull());
}
diff --git a/JavaScriptCore/runtime/LiteralParser.cpp b/JavaScriptCore/runtime/LiteralParser.cpp
index d242282..aa1e5ed 100644
--- a/JavaScriptCore/runtime/LiteralParser.cpp
+++ b/JavaScriptCore/runtime/LiteralParser.cpp
@@ -29,6 +29,7 @@
#include "JSArray.h"
#include "JSString.h"
#include "Lexer.h"
+#include "StringBuilder.h"
#include <wtf/ASCIICType.h>
#include <wtf/dtoa.h>
@@ -134,48 +135,48 @@ template <LiteralParser::ParserMode mode> inline LiteralParser::TokenType Litera
{
++m_ptr;
const UChar* runStart;
- token.stringToken = UString();
+ StringBuilder builder;
do {
runStart = m_ptr;
while (m_ptr < m_end && isSafeStringCharacter<mode>(*m_ptr))
++m_ptr;
if (runStart < m_ptr)
- token.stringToken.append(runStart, m_ptr - runStart);
+ builder.append(runStart, m_ptr - runStart);
if ((mode == StrictJSON) && m_ptr < m_end && *m_ptr == '\\') {
++m_ptr;
if (m_ptr >= m_end)
return TokError;
switch (*m_ptr) {
case '"':
- token.stringToken.append('"');
+ builder.append('"');
m_ptr++;
break;
case '\\':
- token.stringToken.append('\\');
+ builder.append('\\');
m_ptr++;
break;
case '/':
- token.stringToken.append('/');
+ builder.append('/');
m_ptr++;
break;
case 'b':
- token.stringToken.append('\b');
+ builder.append('\b');
m_ptr++;
break;
case 'f':
- token.stringToken.append('\f');
+ builder.append('\f');
m_ptr++;
break;
case 'n':
- token.stringToken.append('\n');
+ builder.append('\n');
m_ptr++;
break;
case 'r':
- token.stringToken.append('\r');
+ builder.append('\r');
m_ptr++;
break;
case 't':
- token.stringToken.append('\t');
+ builder.append('\t');
m_ptr++;
break;
@@ -186,7 +187,7 @@ template <LiteralParser::ParserMode mode> inline LiteralParser::TokenType Litera
if (!isASCIIHexDigit(m_ptr[i]))
return TokError;
}
- token.stringToken.append(JSC::Lexer::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4]));
+ builder.append(JSC::Lexer::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4]));
m_ptr += 5;
break;
@@ -199,6 +200,7 @@ template <LiteralParser::ParserMode mode> inline LiteralParser::TokenType Litera
if (m_ptr >= m_end || *m_ptr != '"')
return TokError;
+ token.stringToken = builder.release();
token.type = TokString;
token.end = ++m_ptr;
return TokString;
diff --git a/JavaScriptCore/runtime/Lookup.cpp b/JavaScriptCore/runtime/Lookup.cpp
index 8359ff7..4e9e086 100644
--- a/JavaScriptCore/runtime/Lookup.cpp
+++ b/JavaScriptCore/runtime/Lookup.cpp
@@ -34,7 +34,7 @@ void HashTable::createTable(JSGlobalData* globalData) const
entries[i].setKey(0);
for (int i = 0; values[i].key; ++i) {
UString::Rep* identifier = Identifier::add(globalData, values[i].key).releaseRef();
- int hashIndex = identifier->computedHash() & compactHashSizeMask;
+ int hashIndex = identifier->existingHash() & compactHashSizeMask;
HashEntry* entry = &entries[hashIndex];
if (entry->key()) {
diff --git a/JavaScriptCore/runtime/Lookup.h b/JavaScriptCore/runtime/Lookup.h
index 4d70689..e673c09 100644
--- a/JavaScriptCore/runtime/Lookup.h
+++ b/JavaScriptCore/runtime/Lookup.h
@@ -144,7 +144,7 @@ namespace JSC {
{
ASSERT(table);
- const HashEntry* entry = &table[identifier.ustring().rep()->computedHash() & compactHashSizeMask];
+ const HashEntry* entry = &table[identifier.ustring().rep()->existingHash() & compactHashSizeMask];
if (!entry->key())
return 0;
diff --git a/JavaScriptCore/runtime/MarkStack.h b/JavaScriptCore/runtime/MarkStack.h
index a114ae0..c551bac 100644
--- a/JavaScriptCore/runtime/MarkStack.h
+++ b/JavaScriptCore/runtime/MarkStack.h
@@ -153,7 +153,7 @@ namespace JSC {
ASSERT(0 == (size % MarkStack::pageSize()));
if (size == m_allocated)
return;
-#if PLATFORM(WIN_OS) || PLATFORM(SYMBIAN)
+#if OS(WINDOWS) || OS(SYMBIAN) || PLATFORM(BREWMP)
// We cannot release a part of a region with VirtualFree. To get around this,
// we'll release the entire region and reallocate the size that we want.
releaseStack(m_data, m_allocated);
diff --git a/JavaScriptCore/runtime/MarkStackNone.cpp b/JavaScriptCore/runtime/MarkStackNone.cpp
new file mode 100644
index 0000000..b1ff48b
--- /dev/null
+++ b/JavaScriptCore/runtime/MarkStackNone.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009 Company 100, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "MarkStack.h"
+
+#include "FastMalloc.h"
+
+namespace JSC {
+
+void MarkStack::initializePagesize()
+{
+ MarkStack::s_pageSize = 4096;
+}
+
+void* MarkStack::allocateStack(size_t size)
+{
+ return fastMalloc(size);
+}
+
+void MarkStack::releaseStack(void* addr, size_t)
+{
+ return fastFree(addr);
+}
+
+}
diff --git a/JavaScriptCore/runtime/MarkStackPosix.cpp b/JavaScriptCore/runtime/MarkStackPosix.cpp
index 8e78ff3..c28bc0d 100644
--- a/JavaScriptCore/runtime/MarkStackPosix.cpp
+++ b/JavaScriptCore/runtime/MarkStackPosix.cpp
@@ -24,10 +24,10 @@
*/
#include "config.h"
-
-
#include "MarkStack.h"
+#if OS(UNIX) && !OS(SYMBIAN)
+
#include <unistd.h>
#include <sys/mman.h>
@@ -48,3 +48,5 @@ void MarkStack::releaseStack(void* addr, size_t size)
}
}
+
+#endif
diff --git a/JavaScriptCore/runtime/MarkStackSymbian.cpp b/JavaScriptCore/runtime/MarkStackSymbian.cpp
index a0ce8f6..bda14ac 100644
--- a/JavaScriptCore/runtime/MarkStackSymbian.cpp
+++ b/JavaScriptCore/runtime/MarkStackSymbian.cpp
@@ -20,6 +20,8 @@
#include "config.h"
#include "MarkStack.h"
+#if OS(SYMBIAN)
+
#include <e32hal.h>
namespace JSC {
@@ -42,3 +44,5 @@ void MarkStack::releaseStack(void* addr, size_t size)
}
}
+
+#endif
diff --git a/JavaScriptCore/runtime/MarkStackWin.cpp b/JavaScriptCore/runtime/MarkStackWin.cpp
index 1fdd06a..a171c78 100644
--- a/JavaScriptCore/runtime/MarkStackWin.cpp
+++ b/JavaScriptCore/runtime/MarkStackWin.cpp
@@ -24,10 +24,10 @@
*/
#include "config.h"
-
-
#include "MarkStack.h"
+#if OS(WINDOWS)
+
#include "windows.h"
namespace JSC {
@@ -51,3 +51,5 @@ void MarkStack::releaseStack(void* addr, size_t)
}
}
+
+#endif
diff --git a/JavaScriptCore/runtime/MathObject.h b/JavaScriptCore/runtime/MathObject.h
index 7f474b8..a9f7031 100644
--- a/JavaScriptCore/runtime/MathObject.h
+++ b/JavaScriptCore/runtime/MathObject.h
@@ -37,7 +37,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
protected:
diff --git a/JavaScriptCore/runtime/NumberConstructor.h b/JavaScriptCore/runtime/NumberConstructor.h
index cf19b6f..723c4b2 100644
--- a/JavaScriptCore/runtime/NumberConstructor.h
+++ b/JavaScriptCore/runtime/NumberConstructor.h
@@ -39,7 +39,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue proto)
{
- return Structure::create(proto, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
enum { NaNValue, NegInfinity, PosInfinity, MaxValue, MinValue };
diff --git a/JavaScriptCore/runtime/NumberObject.h b/JavaScriptCore/runtime/NumberObject.h
index 8223a90..6c18cdd 100644
--- a/JavaScriptCore/runtime/NumberObject.h
+++ b/JavaScriptCore/runtime/NumberObject.h
@@ -33,7 +33,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
protected:
diff --git a/JavaScriptCore/runtime/NumberPrototype.cpp b/JavaScriptCore/runtime/NumberPrototype.cpp
index df31404..67210fa 100644
--- a/JavaScriptCore/runtime/NumberPrototype.cpp
+++ b/JavaScriptCore/runtime/NumberPrototype.cpp
@@ -25,9 +25,10 @@
#include "Error.h"
#include "JSFunction.h"
#include "JSString.h"
+#include "Operations.h"
#include "PrototypeFunction.h"
+#include "StringBuilder.h"
#include "dtoa.h"
-#include "Operations.h"
#include <wtf/Assertions.h>
#include <wtf/MathExtras.h>
#include <wtf/Vector.h>
@@ -73,11 +74,12 @@ static UString integerPartNoExp(double d)
bool resultIsInfOrNan = (decimalPoint == 9999);
size_t length = strlen(result);
- UString str = sign ? "-" : "";
+ StringBuilder builder;
+ builder.append(sign ? "-" : "");
if (resultIsInfOrNan)
- str += result;
+ builder.append((const char*)result);
else if (decimalPoint <= 0)
- str += "0";
+ builder.append("0");
else {
Vector<char, 1024> buf(decimalPoint + 1);
@@ -89,10 +91,10 @@ static UString integerPartNoExp(double d)
strncpy(buf.data(), result, decimalPoint);
buf[decimalPoint] = '\0';
- str.append(buf.data());
+ builder.append((const char*)(buf.data()));
}
- return str;
+ return builder.release();
}
static UString charSequence(char c, int count)
@@ -236,13 +238,16 @@ JSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec, JSObject*, JSValue
UString s;
if (x < 0) {
- s.append('-');
+ s = "-";
x = -x;
- } else if (x == -0.0)
- x = 0;
+ } else {
+ s = "";
+ if (x == -0.0)
+ x = 0;
+ }
if (x >= pow(10.0, 21.0))
- return jsString(exec, s + UString::from(x));
+ return jsString(exec, makeString(s, UString::from(x)));
const double tenToTheF = pow(10.0, f);
double n = floor(x * tenToTheF);
@@ -253,17 +258,19 @@ JSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec, JSObject*, JSValue
int k = m.size();
if (k <= f) {
- UString z;
+ StringBuilder z;
for (int i = 0; i < f + 1 - k; i++)
z.append('0');
- m = z + m;
+ z.append(m);
+ m = z.release();
k = f + 1;
ASSERT(k == m.size());
}
int kMinusf = k - f;
+
if (kMinusf < m.size())
- return jsString(exec, s + m.substr(0, kMinusf) + "." + m.substr(kMinusf));
- return jsString(exec, s + m.substr(0, kMinusf));
+ return jsString(exec, makeString(s, m.substr(0, kMinusf), ".", m.substr(kMinusf)));
+ return jsString(exec, makeString(s, m.substr(0, kMinusf)));
}
static void fractionalPartToString(char* buf, int& i, const char* result, int resultLength, int fractionalDigits)
@@ -391,7 +398,8 @@ JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSV
if (x < 0) {
s = "-";
x = -x;
- }
+ } else
+ s = "";
if (!(doublePrecision >= 1 && doublePrecision <= 21)) // true for NaN
return throwError(exec, RangeError, "toPrecision() argument must be between 1 and 21");
@@ -422,10 +430,10 @@ JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSV
m = integerPartNoExp(n);
if (e < -6 || e >= precision) {
if (m.size() > 1)
- m = m.substr(0, 1) + "." + m.substr(1);
+ m = makeString(m.substr(0, 1), ".", m.substr(1));
if (e >= 0)
- return jsNontrivialString(exec, s + m + "e+" + UString::from(e));
- return jsNontrivialString(exec, s + m + "e-" + UString::from(-e));
+ return jsNontrivialString(exec, makeString(s, m, "e+", UString::from(e)));
+ return jsNontrivialString(exec, makeString(s, m, "e-", UString::from(-e)));
}
} else {
m = charSequence('0', precision);
@@ -433,13 +441,13 @@ JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSV
}
if (e == precision - 1)
- return jsString(exec, s + m);
+ return jsString(exec, makeString(s, m));
if (e >= 0) {
if (e + 1 < m.size())
- return jsString(exec, s + m.substr(0, e + 1) + "." + m.substr(e + 1));
- return jsString(exec, s + m);
+ return jsString(exec, makeString(s, m.substr(0, e + 1), ".", m.substr(e + 1)));
+ return jsString(exec, makeString(s, m));
}
- return jsNontrivialString(exec, s + "0." + charSequence('0', -(e + 1)) + m);
+ return jsNontrivialString(exec, makeString(s, "0.", charSequence('0', -(e + 1)), m));
}
} // namespace JSC
diff --git a/JavaScriptCore/runtime/ObjectConstructor.cpp b/JavaScriptCore/runtime/ObjectConstructor.cpp
index 693efc3..0838eb4 100644
--- a/JavaScriptCore/runtime/ObjectConstructor.cpp
+++ b/JavaScriptCore/runtime/ObjectConstructor.cpp
@@ -36,6 +36,7 @@ ASSERT_CLASS_FITS_IN_CELL(ObjectConstructor);
static JSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*, JSObject*, JSValue, const ArgList&);
static JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState*, JSObject*, JSValue, const ArgList&);
+static JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState*, JSObject*, JSValue, const ArgList&);
static JSValue JSC_HOST_CALL objectConstructorKeys(ExecState*, JSObject*, JSValue, const ArgList&);
static JSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState*, JSObject*, JSValue, const ArgList&);
static JSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState*, JSObject*, JSValue, const ArgList&);
@@ -52,6 +53,7 @@ ObjectConstructor::ObjectConstructor(ExecState* exec, NonNullPassRefPtr<Structur
putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().getPrototypeOf, objectConstructorGetPrototypeOf), DontEnum);
putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().getOwnPropertyDescriptor, objectConstructorGetOwnPropertyDescriptor), DontEnum);
+ putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().getOwnPropertyNames, objectConstructorGetOwnPropertyNames), DontEnum);
putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().keys, objectConstructorKeys), DontEnum);
putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 3, exec->propertyNames().defineProperty, objectConstructorDefineProperty), DontEnum);
putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().defineProperties, objectConstructorDefineProperties), DontEnum);
@@ -126,6 +128,20 @@ JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec,
}
// FIXME: Use the enumeration cache.
+JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exec, JSObject*, JSValue, const ArgList& args)
+{
+ if (!args.at(0).isObject())
+ return throwError(exec, TypeError, "Requested property names of a value that is not an object.");
+ PropertyNameArray properties(exec);
+ asObject(args.at(0))->getOwnPropertyNames(exec, properties, IncludeDontEnumProperties);
+ JSArray* names = constructEmptyArray(exec);
+ size_t numProperties = properties.size();
+ for (size_t i = 0; i < numProperties; i++)
+ names->push(exec, jsOwnedString(exec, properties[i].ustring()));
+ return names;
+}
+
+// FIXME: Use the enumeration cache.
JSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec, JSObject*, JSValue, const ArgList& args)
{
if (!args.at(0).isObject())
diff --git a/JavaScriptCore/runtime/ObjectPrototype.cpp b/JavaScriptCore/runtime/ObjectPrototype.cpp
index 0970b7c..3065c6d 100644
--- a/JavaScriptCore/runtime/ObjectPrototype.cpp
+++ b/JavaScriptCore/runtime/ObjectPrototype.cpp
@@ -148,7 +148,7 @@ JSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState* exec, JSObject*,
JSValue JSC_HOST_CALL objectProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
{
- return jsNontrivialString(exec, "[object " + thisValue.toThisObject(exec)->className() + "]");
+ return jsNontrivialString(exec, makeString("[object ", thisValue.toThisObject(exec)->className(), "]"));
}
} // namespace JSC
diff --git a/JavaScriptCore/runtime/Operations.h b/JavaScriptCore/runtime/Operations.h
index 1cab06d..5a905e3 100644
--- a/JavaScriptCore/runtime/Operations.h
+++ b/JavaScriptCore/runtime/Operations.h
@@ -87,6 +87,43 @@ namespace JSC {
return new (globalData) JSString(globalData, rope.release());
}
+ ALWAYS_INLINE JSValue jsString(ExecState* exec, JSValue thisValue, const ArgList& args)
+ {
+ unsigned ropeLength = 0;
+ if (LIKELY(thisValue.isString()))
+ ropeLength += asString(thisValue)->ropeLength();
+ else
+ ++ropeLength;
+ for (unsigned i = 0; i < args.size(); ++i) {
+ JSValue v = args.at(i);
+ if (LIKELY(v.isString()))
+ ropeLength += asString(v)->ropeLength();
+ else
+ ++ropeLength;
+ }
+
+ RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength);
+ if (UNLIKELY(!rope))
+ return throwOutOfMemoryError(exec);
+
+ unsigned index = 0;
+ if (LIKELY(thisValue.isString()))
+ rope->append(index, asString(thisValue));
+ else
+ rope->append(index, thisValue.toString(exec));
+ for (unsigned i = 0; i < args.size(); ++i) {
+ JSValue v = args.at(i);
+ if (LIKELY(v.isString()))
+ rope->append(index, asString(v));
+ else
+ rope->append(index, v.toString(exec));
+ }
+ ASSERT(index == ropeLength);
+
+ JSGlobalData* globalData = &exec->globalData();
+ return new (globalData) JSString(globalData, rope.release());
+ }
+
// ECMA 11.9.3
inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2)
{
@@ -186,7 +223,7 @@ namespace JSC {
return strictEqualSlowCaseInline(exec, v1, v2);
}
- inline bool jsLess(CallFrame* callFrame, JSValue v1, JSValue v2)
+ ALWAYS_INLINE bool jsLess(CallFrame* callFrame, JSValue v1, JSValue v2)
{
if (v1.isInt32() && v2.isInt32())
return v1.asInt32() < v2.asInt32();
@@ -247,6 +284,7 @@ namespace JSC {
ALWAYS_INLINE JSValue jsAdd(CallFrame* callFrame, JSValue v1, JSValue v2)
{
+<<<<<<< HEAD
double left;
double right = 0.0;
@@ -271,13 +309,23 @@ namespace JSC {
if (!value)
return throwOutOfMemoryError(callFrame);
return jsString(callFrame, value.release());
+=======
+ double left = 0.0, right;
+ if (v1.getNumber(left) && v2.getNumber(right))
+ return jsNumber(callFrame, left + right);
+
+ if (v1.isString()) {
+ return v2.isString()
+ ? jsString(callFrame, asString(v1), asString(v2))
+ : jsString(callFrame, asString(v1), v2.toPrimitiveString(callFrame));
+>>>>>>> webkit.org at r54127
}
// All other cases are pretty uncommon
return jsAddSlowCase(callFrame, v1, v2);
}
- inline size_t normalizePrototypeChain(CallFrame* callFrame, JSValue base, JSValue slotBase)
+ inline size_t normalizePrototypeChain(CallFrame* callFrame, JSValue base, JSValue slotBase, const Identifier& propertyName, size_t& slotOffset)
{
JSCell* cell = asCell(base);
size_t count = 0;
@@ -295,8 +343,11 @@ namespace JSC {
// Since we're accessing a prototype in a loop, it's a good bet that it
// should not be treated as a dictionary.
- if (cell->structure()->isDictionary())
+ if (cell->structure()->isDictionary()) {
asObject(cell)->flattenDictionaryObject();
+ if (slotBase == cell)
+ slotOffset = cell->structure()->get(propertyName);
+ }
++count;
}
diff --git a/JavaScriptCore/runtime/PropertyNameArray.cpp b/JavaScriptCore/runtime/PropertyNameArray.cpp
index c28b6a4..5108272 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::null() || identifier == &UString::Rep::empty() || identifier->identifierTable());
+ ASSERT(identifier == &UString::Rep::null() || identifier == &UString::Rep::empty() || identifier->isIdentifier());
size_t size = m_data->propertyNameVector().size();
if (size < setThreshold) {
diff --git a/JavaScriptCore/runtime/RegExp.cpp b/JavaScriptCore/runtime/RegExp.cpp
index 7dd4a8f..4e958f4 100644
--- a/JavaScriptCore/runtime/RegExp.cpp
+++ b/JavaScriptCore/runtime/RegExp.cpp
@@ -65,7 +65,6 @@ inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern)
inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern, const UString& flags)
: m_pattern(pattern)
- , m_flags(flags)
, m_flagBits(0)
, m_constructionError(0)
, m_numSubpatterns(0)
diff --git a/JavaScriptCore/runtime/RegExp.h b/JavaScriptCore/runtime/RegExp.h
index 24d4199..61ab0bc 100644
--- a/JavaScriptCore/runtime/RegExp.h
+++ b/JavaScriptCore/runtime/RegExp.h
@@ -49,7 +49,6 @@ namespace JSC {
bool multiline() const { return m_flagBits & Multiline; }
const UString& pattern() const { return m_pattern; }
- const UString& flags() const { return m_flags; }
bool isValid() const { return !m_constructionError; }
const char* errorMessage() const { return m_constructionError; }
@@ -66,7 +65,6 @@ namespace JSC {
enum FlagBits { Global = 1, IgnoreCase = 2, Multiline = 4 };
UString m_pattern; // FIXME: Just decompile m_regExp instead of storing this.
- UString m_flags; // FIXME: Just decompile m_regExp instead of storing this.
int m_flagBits;
const char* m_constructionError;
unsigned m_numSubpatterns;
diff --git a/JavaScriptCore/runtime/RegExpConstructor.cpp b/JavaScriptCore/runtime/RegExpConstructor.cpp
index e5c6909..6f00142 100644
--- a/JavaScriptCore/runtime/RegExpConstructor.cpp
+++ b/JavaScriptCore/runtime/RegExpConstructor.cpp
@@ -302,7 +302,7 @@ JSObject* constructRegExp(ExecState* exec, const ArgList& args)
RefPtr<RegExp> regExp = RegExp::create(&exec->globalData(), pattern, flags);
if (!regExp->isValid())
- return throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage()));
+ return throwError(exec, SyntaxError, makeString("Invalid regular expression: ", regExp->errorMessage()));
return new (exec) RegExpObject(exec->lexicalGlobalObject()->regExpStructure(), regExp.release());
}
diff --git a/JavaScriptCore/runtime/RegExpConstructor.h b/JavaScriptCore/runtime/RegExpConstructor.h
index f9ca9cf..8f4be71 100644
--- a/JavaScriptCore/runtime/RegExpConstructor.h
+++ b/JavaScriptCore/runtime/RegExpConstructor.h
@@ -59,7 +59,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
diff --git a/JavaScriptCore/runtime/RegExpMatchesArray.h b/JavaScriptCore/runtime/RegExpMatchesArray.h
index 829f7cf..38d3cb4 100644
--- a/JavaScriptCore/runtime/RegExpMatchesArray.h
+++ b/JavaScriptCore/runtime/RegExpMatchesArray.h
@@ -79,11 +79,11 @@ namespace JSC {
return JSArray::deleteProperty(exec, propertyName);
}
- virtual void getOwnPropertyNames(ExecState* exec, PropertyNameArray& arr)
+ virtual void getOwnPropertyNames(ExecState* exec, PropertyNameArray& arr, EnumerationMode mode = ExcludeDontEnumProperties)
{
if (lazyCreationData())
fillArrayInstance(exec);
- JSArray::getOwnPropertyNames(exec, arr);
+ JSArray::getOwnPropertyNames(exec, arr, mode);
}
void fillArrayInstance(ExecState*);
diff --git a/JavaScriptCore/runtime/RegExpObject.cpp b/JavaScriptCore/runtime/RegExpObject.cpp
index 679d072..42bfcef 100644
--- a/JavaScriptCore/runtime/RegExpObject.cpp
+++ b/JavaScriptCore/runtime/RegExpObject.cpp
@@ -142,7 +142,7 @@ bool RegExpObject::match(ExecState* exec, const ArgList& args)
UString input = args.isEmpty() ? regExpConstructor->input() : args.at(0).toString(exec);
if (input.isNull()) {
- throwError(exec, GeneralError, "No input to " + toString(exec) + ".");
+ throwError(exec, GeneralError, makeString("No input to ", toString(exec), "."));
return false;
}
diff --git a/JavaScriptCore/runtime/RegExpObject.h b/JavaScriptCore/runtime/RegExpObject.h
index 3117c86..4ad11ef 100644
--- a/JavaScriptCore/runtime/RegExpObject.h
+++ b/JavaScriptCore/runtime/RegExpObject.h
@@ -49,7 +49,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
protected:
diff --git a/JavaScriptCore/runtime/RegExpPrototype.cpp b/JavaScriptCore/runtime/RegExpPrototype.cpp
index bbc9e85..5f9d357 100644
--- a/JavaScriptCore/runtime/RegExpPrototype.cpp
+++ b/JavaScriptCore/runtime/RegExpPrototype.cpp
@@ -91,7 +91,7 @@ JSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec, JSObject*, JSValue
}
if (!regExp->isValid())
- return throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage()));
+ return throwError(exec, SyntaxError, makeString("Invalid regular expression: ", regExp->errorMessage()));
asRegExpObject(thisValue)->setRegExp(regExp.release());
asRegExpObject(thisValue)->setLastIndex(0);
@@ -106,15 +106,17 @@ JSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec, JSObject*, JSValu
return throwError(exec, TypeError);
}
- UString result = "/" + asRegExpObject(thisValue)->get(exec, exec->propertyNames().source).toString(exec);
- result.append('/');
+ char postfix[5] = { '/', 0, 0, 0, 0 };
+ int index = 1;
if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().global).toBoolean(exec))
- result.append('g');
+ postfix[index++] = 'g';
if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().ignoreCase).toBoolean(exec))
- result.append('i');
+ postfix[index++] = 'i';
if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().multiline).toBoolean(exec))
- result.append('m');
- return jsNontrivialString(exec, result);
+ postfix[index] = 'm';
+ UString source = asRegExpObject(thisValue)->get(exec, exec->propertyNames().source).toString(exec);
+ // If source is empty, use "/(?:)/" to avoid colliding with comment syntax
+ return jsNontrivialString(exec, makeString("/", source.size() ? source : UString("(?:)"), postfix));
}
} // namespace JSC
diff --git a/JavaScriptCore/runtime/SmallStrings.cpp b/JavaScriptCore/runtime/SmallStrings.cpp
index 04701cb..ac71735 100644
--- a/JavaScriptCore/runtime/SmallStrings.cpp
+++ b/JavaScriptCore/runtime/SmallStrings.cpp
@@ -41,30 +41,16 @@ public:
UString::Rep* rep(unsigned char character) { return &m_reps[character]; }
private:
- UChar m_characters[numCharactersToStore];
- UString::BaseString m_base;
UString::Rep m_reps[numCharactersToStore];
};
SmallStringsStorage::SmallStringsStorage()
- : m_base(m_characters, numCharactersToStore)
{
- m_base.rc = numCharactersToStore + 1;
- // make sure UString doesn't try to reuse the buffer by pretending we have one more character in it
- m_base.usedCapacity = numCharactersToStore + 1;
- m_base.capacity = numCharactersToStore + 1;
- m_base.checkConsistency();
-
- for (unsigned i = 0; i < numCharactersToStore; ++i)
- m_characters[i] = i;
-
- memset(&m_reps, 0, sizeof(m_reps));
+ UChar* characterBuffer = 0;
+ RefPtr<UStringImpl> baseString = UStringImpl::createUninitialized(numCharactersToStore, characterBuffer);
for (unsigned i = 0; i < numCharactersToStore; ++i) {
- m_reps[i].offset = i;
- m_reps[i].len = 1;
- m_reps[i].rc = 1;
- m_reps[i].setBaseString(&m_base);
- m_reps[i].checkConsistency();
+ characterBuffer[i] = i;
+ new (&m_reps[i]) UString::Rep(&characterBuffer[i], 1, PassRefPtr<UStringImpl>(baseString));
}
}
diff --git a/JavaScriptCore/runtime/StringBuilder.h b/JavaScriptCore/runtime/StringBuilder.h
new file mode 100644
index 0000000..8e18d37
--- /dev/null
+++ b/JavaScriptCore/runtime/StringBuilder.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StringBuilder_h
+#define StringBuilder_h
+
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+class StringBuilder {
+public:
+ void append(const UChar u)
+ {
+ buffer.append(u);
+ }
+
+ void append(const char* str)
+ {
+ buffer.append(str, strlen(str));
+ }
+
+ void append(const char* str, size_t len)
+ {
+ buffer.reserveCapacity(buffer.size() + len);
+ for (size_t i = 0; i < len; i++)
+ buffer.append(static_cast<unsigned char>(str[i]));
+ }
+
+ void append(const UChar* str, size_t len)
+ {
+ buffer.append(str, len);
+ }
+
+ void append(const UString& str)
+ {
+ buffer.append(str.data(), str.size());
+ }
+
+ bool isEmpty() { return buffer.isEmpty(); }
+ void reserveCapacity(size_t newCapacity) { buffer.reserveCapacity(newCapacity); }
+ void resize(size_t size) { buffer.resize(size); }
+ size_t size() const { return buffer.size(); }
+
+ UChar operator[](size_t i) const { return buffer.at(i); }
+
+ UString release()
+ {
+ buffer.shrinkToFit();
+ return UString::adopt(buffer);
+ }
+
+private:
+ Vector<UChar, 64> buffer;
+};
+
+}
+
+#endif
diff --git a/JavaScriptCore/runtime/StringConstructor.cpp b/JavaScriptCore/runtime/StringConstructor.cpp
index 2f3adbe..c7b62bf 100644
--- a/JavaScriptCore/runtime/StringConstructor.cpp
+++ b/JavaScriptCore/runtime/StringConstructor.cpp
@@ -30,12 +30,12 @@ namespace JSC {
static NEVER_INLINE JSValue stringFromCharCodeSlowCase(ExecState* exec, const ArgList& args)
{
- UChar* buf = static_cast<UChar*>(fastMalloc(args.size() * sizeof(UChar)));
- UChar* p = buf;
- ArgList::const_iterator end = args.end();
- for (ArgList::const_iterator it = args.begin(); it != end; ++it)
- *p++ = static_cast<UChar>((*it).toUInt32(exec));
- return jsString(exec, UString(buf, p - buf, false));
+ unsigned length = args.size();
+ UChar* buf;
+ PassRefPtr<UStringImpl> impl = UStringImpl::createUninitialized(length, buf);
+ for (unsigned i = 0; i < length; ++i)
+ buf[i] = static_cast<UChar>(args.at(i).toUInt32(exec));
+ return jsString(exec, impl);
}
static JSValue JSC_HOST_CALL stringFromCharCode(ExecState* exec, JSObject*, JSValue, const ArgList& args)
diff --git a/JavaScriptCore/runtime/StringObject.cpp b/JavaScriptCore/runtime/StringObject.cpp
index f23a20d..f8e0e87 100644
--- a/JavaScriptCore/runtime/StringObject.cpp
+++ b/JavaScriptCore/runtime/StringObject.cpp
@@ -86,12 +86,14 @@ bool StringObject::deleteProperty(ExecState* exec, const Identifier& propertyNam
return JSObject::deleteProperty(exec, propertyName);
}
-void StringObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
+void StringObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
int size = internalValue()->length();
for (int i = 0; i < size; ++i)
propertyNames.add(Identifier(exec, UString::from(i)));
- return JSObject::getOwnPropertyNames(exec, propertyNames);
+ if (mode == IncludeDontEnumProperties)
+ propertyNames.add(exec->propertyNames().length);
+ return JSObject::getOwnPropertyNames(exec, propertyNames, mode);
}
} // namespace JSC
diff --git a/JavaScriptCore/runtime/StringObject.h b/JavaScriptCore/runtime/StringObject.h
index 84e1ad2..e3add77 100644
--- a/JavaScriptCore/runtime/StringObject.h
+++ b/JavaScriptCore/runtime/StringObject.h
@@ -39,7 +39,7 @@ namespace JSC {
virtual void put(ExecState* exec, const Identifier& propertyName, JSValue, PutPropertySlot&);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
- virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&);
+ virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
virtual const ClassInfo* classInfo() const { return &info; }
static const JS_EXPORTDATA ClassInfo info;
@@ -48,7 +48,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
- return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
protected:
diff --git a/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h b/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h
index 69e1939..43c3e38 100644
--- a/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h
+++ b/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h
@@ -44,7 +44,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue proto)
{
- return Structure::create(proto, TypeInfo(ObjectType, StructureFlags));
+ return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
}
static const unsigned StructureFlags = OverridesGetOwnPropertySlot | MasqueradesAsUndefined | OverridesGetPropertyNames | StringObject::StructureFlags;
diff --git a/JavaScriptCore/runtime/StringPrototype.cpp b/JavaScriptCore/runtime/StringPrototype.cpp
index 32f9e6b..d002e07 100644
--- a/JavaScriptCore/runtime/StringPrototype.cpp
+++ b/JavaScriptCore/runtime/StringPrototype.cpp
@@ -29,6 +29,7 @@
#include "JSArray.h"
#include "JSFunction.h"
#include "ObjectPrototype.h"
+#include "Operations.h"
#include "PropertyNameArray.h"
#include "RegExpConstructor.h"
#include "RegExpObject.h"
@@ -148,12 +149,11 @@ bool StringPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier
// ------------------------------ Functions --------------------------
-static inline UString substituteBackreferences(const UString& replacement, const UString& source, const int* ovector, RegExp* reg)
+static NEVER_INLINE UString substituteBackreferencesSlow(const UString& replacement, const UString& source, const int* ovector, RegExp* reg, int i)
{
- UString substitutedReplacement;
+ Vector<UChar> substitutedReplacement;
int offset = 0;
- int i = -1;
- while ((i = replacement.find('$', i + 1)) != -1) {
+ do {
if (i + 1 == replacement.size())
break;
@@ -205,15 +205,21 @@ static inline UString substituteBackreferences(const UString& replacement, const
i += 1 + advance;
offset = i + 1;
substitutedReplacement.append(source.data() + backrefStart, backrefLength);
- }
-
- if (!offset)
- return replacement;
+ } while ((i = replacement.find('$', i + 1)) != -1);
if (replacement.size() - offset)
substitutedReplacement.append(replacement.data() + offset, replacement.size() - offset);
- return substitutedReplacement;
+ substitutedReplacement.shrinkToFit();
+ return UString::adopt(substitutedReplacement);
+}
+
+static inline UString substituteBackreferences(const UString& replacement, const UString& source, const int* ovector, RegExp* reg)
+{
+ int i = replacement.find('$', 0);
+ if (UNLIKELY(i != -1))
+ return substituteBackreferencesSlow(replacement, source, ovector, reg, i);
+ return replacement;
}
static inline int localeCompare(const UString& a, const UString& b)
@@ -423,12 +429,14 @@ JSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState* exec, JSObject*, JSVa
JSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
{
- UString s = thisValue.toThisString(exec);
+ if (thisValue.isString() && (args.size() == 1)) {
+ JSValue v = args.at(0);
+ return v.isString()
+ ? jsString(exec, asString(thisValue), asString(v))
+ : jsString(exec, asString(thisValue), v.toString(exec));
+ }
- ArgList::const_iterator end = args.end();
- for (ArgList::const_iterator it = args.begin(); it != end; ++it)
- s += (*it).toString(exec);
- return jsString(exec, s);
+ return jsString(exec, thisValue, args);
}
JSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
@@ -470,7 +478,7 @@ JSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec, JSObject*, JSV
dpos = 0;
else if (!(dpos <= len)) // true for NaN
dpos = len;
-#if PLATFORM(SYMBIAN)
+#if OS(SYMBIAN)
// Work around for broken NaN compare operator
else if (isnan(dpos))
dpos = len;
@@ -713,7 +721,7 @@ JSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec, JSObject*, JSV
buffer[i] = toASCIILower(c);
}
if (!(ored & ~0x7f))
- return jsString(exec, UString(buffer.releaseBuffer(), sSize, false));
+ return jsString(exec, UString::adopt(buffer));
bool error;
int length = Unicode::toLower(buffer.data(), sSize, sData, sSize, &error);
@@ -723,9 +731,12 @@ JSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec, JSObject*, JSV
if (error)
return sVal;
}
- if (length == sSize && memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0)
- return sVal;
- return jsString(exec, UString(buffer.releaseBuffer(), length, false));
+ if (length == sSize) {
+ if (memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0)
+ return sVal;
+ } else
+ buffer.resize(length);
+ return jsString(exec, UString::adopt(buffer));
}
JSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
@@ -747,7 +758,7 @@ JSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec, JSObject*, JSV
buffer[i] = toASCIIUpper(c);
}
if (!(ored & ~0x7f))
- return jsString(exec, UString(buffer.releaseBuffer(), sSize, false));
+ return jsString(exec, UString::adopt(buffer));
bool error;
int length = Unicode::toUpper(buffer.data(), sSize, sData, sSize, &error);
@@ -757,9 +768,12 @@ JSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec, JSObject*, JSV
if (error)
return sVal;
}
- if (length == sSize && memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0)
- return sVal;
- return jsString(exec, UString(buffer.releaseBuffer(), length, false));
+ if (length == sSize) {
+ if (memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0)
+ return sVal;
+ } else
+ buffer.resize(length);
+ return jsString(exec, UString::adopt(buffer));
}
JSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
@@ -775,62 +789,62 @@ JSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec, JSObject*, J
JSValue JSC_HOST_CALL stringProtoFuncBig(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
{
UString s = thisValue.toThisString(exec);
- return jsNontrivialString(exec, "<big>" + s + "</big>");
+ return jsNontrivialString(exec, makeString("<big>", s, "</big>"));
}
JSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
{
UString s = thisValue.toThisString(exec);
- return jsNontrivialString(exec, "<small>" + s + "</small>");
+ return jsNontrivialString(exec, makeString("<small>", s, "</small>"));
}
JSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
{
UString s = thisValue.toThisString(exec);
- return jsNontrivialString(exec, "<blink>" + s + "</blink>");
+ return jsNontrivialString(exec, makeString("<blink>", s, "</blink>"));
}
JSValue JSC_HOST_CALL stringProtoFuncBold(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
{
UString s = thisValue.toThisString(exec);
- return jsNontrivialString(exec, "<b>" + s + "</b>");
+ return jsNontrivialString(exec, makeString("<b>", s, "</b>"));
}
JSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
{
UString s = thisValue.toThisString(exec);
- return jsString(exec, "<tt>" + s + "</tt>");
+ return jsString(exec, makeString("<tt>", s, "</tt>"));
}
JSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
{
UString s = thisValue.toThisString(exec);
- return jsNontrivialString(exec, "<i>" + s + "</i>");
+ return jsNontrivialString(exec, makeString("<i>", s, "</i>"));
}
JSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
{
UString s = thisValue.toThisString(exec);
- return jsNontrivialString(exec, "<strike>" + s + "</strike>");
+ return jsNontrivialString(exec, makeString("<strike>", s, "</strike>"));
}
JSValue JSC_HOST_CALL stringProtoFuncSub(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
{
UString s = thisValue.toThisString(exec);
- return jsNontrivialString(exec, "<sub>" + s + "</sub>");
+ return jsNontrivialString(exec, makeString("<sub>", s, "</sub>"));
}
JSValue JSC_HOST_CALL stringProtoFuncSup(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
{
UString s = thisValue.toThisString(exec);
- return jsNontrivialString(exec, "<sup>" + s + "</sup>");
+ return jsNontrivialString(exec, makeString("<sup>", s, "</sup>"));
}
JSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
{
UString s = thisValue.toThisString(exec);
JSValue a0 = args.at(0);
- return jsNontrivialString(exec, "<font color=\"" + a0.toString(exec) + "\">" + s + "</font>");
+ return jsNontrivialString(exec, makeString("<font color=\"", a0.toString(exec), "\">", s, "</font>"));
}
JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
@@ -843,7 +857,8 @@ JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec, JSObject*, JSValu
unsigned stringSize = s.size();
unsigned bufferSize = 22 + stringSize;
UChar* buffer;
- if (!tryFastMalloc(bufferSize * sizeof(UChar)).getValue(buffer))
+ PassRefPtr<UStringImpl> impl = UStringImpl::tryCreateUninitialized(bufferSize, buffer);
+ if (!impl)
return jsUndefined();
buffer[0] = '<';
buffer[1] = 'f';
@@ -868,17 +883,17 @@ JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec, JSObject*, JSValu
buffer[19 + stringSize] = 'n';
buffer[20 + stringSize] = 't';
buffer[21 + stringSize] = '>';
- return jsNontrivialString(exec, UString(buffer, bufferSize, false));
+ return jsNontrivialString(exec, impl);
}
- return jsNontrivialString(exec, "<font size=\"" + a0.toString(exec) + "\">" + s + "</font>");
+ return jsNontrivialString(exec, makeString("<font size=\"", a0.toString(exec), "\">", s, "</font>"));
}
JSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
{
UString s = thisValue.toThisString(exec);
JSValue a0 = args.at(0);
- return jsNontrivialString(exec, "<a name=\"" + a0.toString(exec) + "\">" + s + "</a>");
+ return jsNontrivialString(exec, makeString("<a name=\"", a0.toString(exec), "\">", s, "</a>"));
}
JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
@@ -891,7 +906,8 @@ JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec, JSObject*, JSValue th
unsigned stringSize = s.size();
unsigned bufferSize = 15 + linkTextSize + stringSize;
UChar* buffer;
- if (!tryFastMalloc(bufferSize * sizeof(UChar)).getValue(buffer))
+ PassRefPtr<UStringImpl> impl = UStringImpl::tryCreateUninitialized(bufferSize, buffer);
+ if (!impl)
return jsUndefined();
buffer[0] = '<';
buffer[1] = 'a';
@@ -910,7 +926,7 @@ JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec, JSObject*, JSValue th
buffer[12 + linkTextSize + stringSize] = '/';
buffer[13 + linkTextSize + stringSize] = 'a';
buffer[14 + linkTextSize + stringSize] = '>';
- return jsNontrivialString(exec, UString(buffer, bufferSize, false));
+ return jsNontrivialString(exec, impl);
}
enum {
diff --git a/JavaScriptCore/runtime/Structure.cpp b/JavaScriptCore/runtime/Structure.cpp
index e4c9ac3..77330aa 100644
--- a/JavaScriptCore/runtime/Structure.cpp
+++ b/JavaScriptCore/runtime/Structure.cpp
@@ -134,6 +134,7 @@ Structure::Structure(JSValue prototype, const TypeInfo& typeInfo)
, m_isPinnedPropertyTable(false)
, m_hasGetterSetterProperties(false)
, m_attributesInPrevious(0)
+ , m_specificFunctionThrashCount(0)
{
ASSERT(m_prototype);
ASSERT(m_prototype.isObject() || m_prototype.isNull());
@@ -156,10 +157,8 @@ Structure::Structure(JSValue prototype, const TypeInfo& typeInfo)
Structure::~Structure()
{
if (m_previous) {
- if (m_nameInPrevious)
- m_previous->table.remove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious);
- else
- m_previous->table.removeAnonymousSlotTransition(m_anonymousSlotsInPrevious);
+ ASSERT(m_nameInPrevious);
+ m_previous->table.remove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious);
}
@@ -275,10 +274,6 @@ void Structure::materializePropertyMap()
for (ptrdiff_t i = structures.size() - 2; i >= 0; --i) {
structure = structures[i];
- if (!structure->m_nameInPrevious) {
- m_propertyTable->anonymousSlotCount += structure->m_anonymousSlotsInPrevious;
- continue;
- }
structure->m_nameInPrevious->ref();
PropertyMapEntry entry(structure->m_nameInPrevious.get(), structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious, ++m_propertyTable->lastIndexUsed);
insertIntoPropertyMapHashTable(entry);
@@ -302,7 +297,7 @@ void Structure::despecifyDictionaryFunction(const Identifier& propertyName)
ASSERT(isDictionary());
ASSERT(m_propertyTable);
- unsigned i = rep->computedHash();
+ unsigned i = rep->existingHash();
#if DUMP_PROPERTYMAP_STATS
++numProbes;
@@ -320,7 +315,7 @@ void Structure::despecifyDictionaryFunction(const Identifier& propertyName)
++numCollisions;
#endif
- unsigned k = 1 | doubleHash(rep->computedHash());
+ unsigned k = 1 | doubleHash(rep->existingHash());
while (1) {
i += k;
@@ -358,6 +353,9 @@ PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, con
ASSERT(!structure->isDictionary());
ASSERT(structure->typeInfo().type() == ObjectType);
ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset));
+
+ if (structure->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
+ specificValue = 0;
if (structure->transitionCount() > s_maxTransitionLength) {
RefPtr<Structure> transition = toCacheableDictionaryTransition(structure);
@@ -378,6 +376,7 @@ PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, con
transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
+ transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount;
if (structure->m_propertyTable) {
if (structure->m_isPinnedPropertyTable)
@@ -421,6 +420,7 @@ PassRefPtr<Structure> Structure::changePrototypeTransition(Structure* structure,
transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
+ transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount;
// Don't set m_offset, as one can not transition to this.
@@ -433,11 +433,13 @@ PassRefPtr<Structure> Structure::changePrototypeTransition(Structure* structure,
PassRefPtr<Structure> Structure::despecifyFunctionTransition(Structure* structure, const Identifier& replaceFunction)
{
+ ASSERT(structure->m_specificFunctionThrashCount < maxSpecificFunctionThrashCount);
RefPtr<Structure> transition = create(structure->storedPrototype(), structure->typeInfo());
transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
+ transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount + 1;
// Don't set m_offset, as one can not transition to this.
@@ -445,52 +447,14 @@ PassRefPtr<Structure> Structure::despecifyFunctionTransition(Structure* structur
transition->m_propertyTable = structure->copyPropertyTable();
transition->m_isPinnedPropertyTable = true;
- bool removed = transition->despecifyFunction(replaceFunction);
- ASSERT_UNUSED(removed, removed);
-
- return transition.release();
-}
-
-PassRefPtr<Structure> Structure::addAnonymousSlotsTransition(Structure* structure, unsigned count)
-{
- if (Structure* transition = structure->table.getAnonymousSlotTransition(count)) {
- ASSERT(transition->storedPrototype() == structure->storedPrototype());
- return transition;
- }
- ASSERT(count);
- ASSERT(count < ((1<<6) - 2));
- RefPtr<Structure> transition = create(structure->m_prototype, structure->typeInfo());
-
- transition->m_cachedPrototypeChain = structure->m_cachedPrototypeChain;
- transition->m_previous = structure;
- transition->m_nameInPrevious = 0;
- transition->m_attributesInPrevious = 0;
- transition->m_anonymousSlotsInPrevious = count;
- transition->m_specificValueInPrevious = 0;
- transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
- transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
- transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
-
- if (structure->m_propertyTable) {
- if (structure->m_isPinnedPropertyTable)
- transition->m_propertyTable = structure->copyPropertyTable();
- else {
- transition->m_propertyTable = structure->m_propertyTable;
- structure->m_propertyTable = 0;
- }
- } else {
- if (structure->m_previous)
- transition->materializePropertyMap();
- else
- transition->createPropertyMapHashTable();
+ if (transition->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
+ transition->despecifyAllFunctions();
+ else {
+ bool removed = transition->despecifyFunction(replaceFunction);
+ ASSERT_UNUSED(removed, removed);
}
- transition->addAnonymousSlots(count);
- if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
- transition->growPropertyStorageCapacity();
-
- structure->table.addAnonymousSlotTransition(count, transition.get());
- return transition.release();
+ return transition.release();
}
PassRefPtr<Structure> Structure::getterSetterTransition(Structure* structure)
@@ -499,6 +463,7 @@ PassRefPtr<Structure> Structure::getterSetterTransition(Structure* structure)
transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
transition->m_hasGetterSetterProperties = transition->m_hasGetterSetterProperties;
transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
+ transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount;
// Don't set m_offset, as one can not transition to this.
@@ -518,6 +483,7 @@ PassRefPtr<Structure> Structure::toDictionaryTransition(Structure* structure, Di
transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
+ transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount;
structure->materializePropertyMapIfNecessary();
transition->m_propertyTable = structure->copyPropertyTable();
@@ -582,6 +548,10 @@ PassRefPtr<Structure> Structure::flattenDictionaryStructure(JSObject* object)
size_t Structure::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
{
ASSERT(!m_enumerationCache);
+
+ if (m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
+ specificValue = 0;
+
materializePropertyMapIfNecessary();
m_isPinnedPropertyTable = true;
@@ -667,7 +637,7 @@ size_t Structure::get(const UString::Rep* rep, unsigned& attributes, JSCell*& sp
if (!m_propertyTable)
return notFound;
- unsigned i = rep->computedHash();
+ unsigned i = rep->existingHash();
#if DUMP_PROPERTYMAP_STATS
++numProbes;
@@ -687,7 +657,7 @@ size_t Structure::get(const UString::Rep* rep, unsigned& attributes, JSCell*& sp
++numCollisions;
#endif
- unsigned k = 1 | doubleHash(rep->computedHash());
+ unsigned k = 1 | doubleHash(rep->existingHash());
while (1) {
i += k;
@@ -718,7 +688,7 @@ bool Structure::despecifyFunction(const Identifier& propertyName)
UString::Rep* rep = propertyName._ustring.rep();
- unsigned i = rep->computedHash();
+ unsigned i = rep->existingHash();
#if DUMP_PROPERTYMAP_STATS
++numProbes;
@@ -738,7 +708,7 @@ bool Structure::despecifyFunction(const Identifier& propertyName)
++numCollisions;
#endif
- unsigned k = 1 | doubleHash(rep->computedHash());
+ unsigned k = 1 | doubleHash(rep->existingHash());
while (1) {
i += k;
@@ -759,6 +729,17 @@ bool Structure::despecifyFunction(const Identifier& propertyName)
}
}
+void Structure::despecifyAllFunctions()
+{
+ materializePropertyMapIfNecessary();
+ if (!m_propertyTable)
+ return;
+
+ unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
+ for (unsigned i = 1; i <= entryCount; ++i)
+ m_propertyTable->entries()[i].specificValue = 0;
+}
+
size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
{
ASSERT(!propertyName.isNull());
@@ -776,7 +757,7 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel
// FIXME: Consider a fast case for tables with no deleted sentinels.
- unsigned i = rep->computedHash();
+ unsigned i = rep->existingHash();
unsigned k = 0;
bool foundDeletedElement = false;
unsigned deletedElementIndex = 0; // initialize to make the compiler happy
@@ -799,7 +780,7 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel
}
if (k == 0) {
- k = 1 | doubleHash(rep->computedHash());
+ k = 1 | doubleHash(rep->existingHash());
#if DUMP_PROPERTYMAP_STATS
++numCollisions;
#endif
@@ -852,11 +833,6 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel
return newOffset;
}
-void Structure::addAnonymousSlots(unsigned count)
-{
- m_propertyTable->anonymousSlotCount += count;
-}
-
bool Structure::hasTransition(UString::Rep* rep, unsigned attributes)
{
return table.hasTransition(make_pair(rep, attributes));
@@ -879,7 +855,7 @@ size_t Structure::remove(const Identifier& propertyName)
#endif
// Find the thing to remove.
- unsigned i = rep->computedHash();
+ unsigned i = rep->existingHash();
unsigned k = 0;
unsigned entryIndex;
UString::Rep* key = 0;
@@ -893,7 +869,7 @@ size_t Structure::remove(const Identifier& propertyName)
break;
if (k == 0) {
- k = 1 | doubleHash(rep->computedHash());
+ k = 1 | doubleHash(rep->existingHash());
#if DUMP_PROPERTYMAP_STATS
++numCollisions;
#endif
@@ -937,7 +913,7 @@ void Structure::insertIntoPropertyMapHashTable(const PropertyMapEntry& entry)
{
ASSERT(m_propertyTable);
- unsigned i = entry.key->computedHash();
+ unsigned i = entry.key->existingHash();
unsigned k = 0;
#if DUMP_PROPERTYMAP_STATS
@@ -950,7 +926,7 @@ void Structure::insertIntoPropertyMapHashTable(const PropertyMapEntry& entry)
break;
if (k == 0) {
- k = 1 | doubleHash(entry.key->computedHash());
+ k = 1 | doubleHash(entry.key->existingHash());
#if DUMP_PROPERTYMAP_STATS
++numCollisions;
#endif
@@ -1044,7 +1020,7 @@ int comparePropertyMapEntryIndices(const void* a, const void* b)
return 0;
}
-void Structure::getEnumerablePropertyNames(PropertyNameArray& propertyNames)
+void Structure::getPropertyNames(PropertyNameArray& propertyNames, EnumerationMode mode)
{
materializePropertyMapIfNecessary();
if (!m_propertyTable)
@@ -1056,7 +1032,7 @@ void Structure::getEnumerablePropertyNames(PropertyNameArray& propertyNames)
unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
for (unsigned k = 1; k <= entryCount; k++) {
ASSERT(m_hasNonEnumerableProperties || !(m_propertyTable->entries()[k].attributes & DontEnum));
- if (m_propertyTable->entries()[k].key && !(m_propertyTable->entries()[k].attributes & DontEnum)) {
+ if (m_propertyTable->entries()[k].key && (!(m_propertyTable->entries()[k].attributes & DontEnum) || (mode == IncludeDontEnumProperties))) {
PropertyMapEntry* value = &m_propertyTable->entries()[k];
int j;
for (j = i - 1; j >= 0 && a[j]->index > value->index; --j)
@@ -1083,7 +1059,7 @@ void Structure::getEnumerablePropertyNames(PropertyNameArray& propertyNames)
PropertyMapEntry** p = sortedEnumerables.data();
unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
for (unsigned i = 1; i <= entryCount; i++) {
- if (m_propertyTable->entries()[i].key && !(m_propertyTable->entries()[i].attributes & DontEnum))
+ if (m_propertyTable->entries()[i].key && (!(m_propertyTable->entries()[i].attributes & DontEnum) || (mode == IncludeDontEnumProperties)))
*p++ = &m_propertyTable->entries()[i];
}
@@ -1148,7 +1124,7 @@ void Structure::checkConsistency()
if (!rep)
continue;
++nonEmptyEntryCount;
- unsigned i = rep->computedHash();
+ unsigned i = rep->existingHash();
unsigned k = 0;
unsigned entryIndex;
while (1) {
@@ -1157,7 +1133,7 @@ void Structure::checkConsistency()
if (rep == m_propertyTable->entries()[entryIndex - 1].key)
break;
if (k == 0)
- k = 1 | doubleHash(rep->computedHash());
+ k = 1 | doubleHash(rep->existingHash());
i += k;
}
ASSERT(entryIndex == c + 1);
diff --git a/JavaScriptCore/runtime/Structure.h b/JavaScriptCore/runtime/Structure.h
index c6b7d91..f73f9b8 100644
--- a/JavaScriptCore/runtime/Structure.h
+++ b/JavaScriptCore/runtime/Structure.h
@@ -51,13 +51,26 @@ namespace JSC {
class PropertyNameArray;
class PropertyNameArrayData;
+ enum EnumerationMode {
+ ExcludeDontEnumProperties,
+ IncludeDontEnumProperties
+ };
+
class Structure : public RefCounted<Structure> {
public:
friend class JIT;
friend class StructureTransitionTable;
- static PassRefPtr<Structure> create(JSValue prototype, const TypeInfo& typeInfo)
+ static PassRefPtr<Structure> create(JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount)
{
- return adoptRef(new Structure(prototype, typeInfo));
+ Structure* structure = (new Structure(prototype, typeInfo));
+ if (anonymousSlotCount) {
+ structure->materializePropertyMap();
+ structure->m_isPinnedPropertyTable = true;
+ structure->m_propertyTable->anonymousSlotCount = anonymousSlotCount;
+ // Currently we don't allow more anonymous slots than fit in the inline capacity
+ ASSERT(structure->propertyStorageSize() <= structure->propertyStorageCapacity());
+ }
+ return adoptRef(structure);
}
static void startIgnoringLeaks();
@@ -70,7 +83,6 @@ namespace JSC {
static PassRefPtr<Structure> removePropertyTransition(Structure*, const Identifier& propertyName, size_t& offset);
static PassRefPtr<Structure> changePrototypeTransition(Structure*, JSValue prototype);
static PassRefPtr<Structure> despecifyFunctionTransition(Structure*, const Identifier&);
- static PassRefPtr<Structure> addAnonymousSlotsTransition(Structure*, unsigned count);
static PassRefPtr<Structure> getterSetterTransition(Structure*);
static PassRefPtr<Structure> toCacheableDictionaryTransition(Structure*);
static PassRefPtr<Structure> toUncacheableDictionaryTransition(Structure*);
@@ -123,17 +135,23 @@ namespace JSC {
bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
bool hasAnonymousSlots() const { return m_propertyTable && m_propertyTable->anonymousSlotCount; }
+ unsigned anonymousSlotCount() const { return m_propertyTable ? m_propertyTable->anonymousSlotCount : 0; }
bool isEmpty() const { return m_propertyTable ? !m_propertyTable->keyCount : m_offset == noOffset; }
- JSCell* specificValue() { return m_specificValueInPrevious; }
void despecifyDictionaryFunction(const Identifier& propertyName);
+ void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
void setEnumerationCache(JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
JSPropertyNameIterator* enumerationCache() { return m_enumerationCache.get(); }
- void getEnumerablePropertyNames(PropertyNameArray&);
-
+ void getPropertyNames(PropertyNameArray&, EnumerationMode mode);
+
private:
+ static PassRefPtr<Structure> create(JSValue prototype, const TypeInfo& typeInfo)
+ {
+ return adoptRef(new Structure(prototype, typeInfo));
+ }
+
Structure(JSValue prototype, const TypeInfo&);
typedef enum {
@@ -145,7 +163,6 @@ namespace JSC {
size_t put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
size_t remove(const Identifier& propertyName);
- void addAnonymousSlots(unsigned slotCount);
void expandPropertyMapHashTable();
void rehashPropertyMapHashTable();
@@ -156,6 +173,7 @@ namespace JSC {
void checkConsistency();
bool despecifyFunction(const Identifier&);
+ void despecifyAllFunctions();
PropertyMapHashTable* copyPropertyTable();
void materializePropertyMap();
@@ -180,6 +198,8 @@ namespace JSC {
static const signed char noOffset = -1;
+ static const unsigned maxSpecificFunctionThrashCount = 3;
+
TypeInfo m_typeInfo;
JSValue m_prototype;
@@ -210,7 +230,8 @@ namespace JSC {
#else
unsigned m_attributesInPrevious : 7;
#endif
- unsigned m_anonymousSlotsInPrevious : 6;
+ unsigned m_specificFunctionThrashCount : 2;
+ // 10 free bits
};
inline size_t Structure::get(const Identifier& propertyName)
@@ -223,7 +244,7 @@ namespace JSC {
UString::Rep* rep = propertyName._ustring.rep();
- unsigned i = rep->computedHash();
+ unsigned i = rep->existingHash();
#if DUMP_PROPERTYMAP_STATS
++numProbes;
@@ -240,7 +261,7 @@ namespace JSC {
++numCollisions;
#endif
- unsigned k = 1 | WTF::doubleHash(rep->computedHash());
+ unsigned k = 1 | WTF::doubleHash(rep->existingHash());
while (1) {
i += k;
diff --git a/JavaScriptCore/runtime/StructureTransitionTable.h b/JavaScriptCore/runtime/StructureTransitionTable.h
index 0fa7b73..320dbdd 100644
--- a/JavaScriptCore/runtime/StructureTransitionTable.h
+++ b/JavaScriptCore/runtime/StructureTransitionTable.h
@@ -42,7 +42,7 @@ namespace JSC {
typedef std::pair<RefPtr<UString::Rep>, unsigned> Key;
static unsigned hash(const Key& p)
{
- return p.first->computedHash();
+ return p.first->existingHash();
}
static bool equal(const Key& a, const Key& b)
@@ -69,36 +69,7 @@ namespace JSC {
class StructureTransitionTable {
typedef std::pair<Structure*, Structure*> Transition;
- struct TransitionTable : public HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> {
- typedef HashMap<unsigned, Structure*> AnonymousSlotMap;
-
- void addSlotTransition(unsigned count, Structure* structure)
- {
- ASSERT(!getSlotTransition(count));
- if (!m_anonymousSlotTable)
- m_anonymousSlotTable.set(new AnonymousSlotMap);
- m_anonymousSlotTable->add(count, structure);
- }
-
- void removeSlotTransition(unsigned count)
- {
- ASSERT(getSlotTransition(count));
- m_anonymousSlotTable->remove(count);
- }
-
- Structure* getSlotTransition(unsigned count)
- {
- if (!m_anonymousSlotTable)
- return 0;
-
- AnonymousSlotMap::iterator find = m_anonymousSlotTable->find(count);
- if (find == m_anonymousSlotTable->end())
- return 0;
- return find->second;
- }
- private:
- OwnPtr<AnonymousSlotMap> m_anonymousSlotTable;
- };
+ typedef HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> TransitionTable;
public:
StructureTransitionTable() {
m_transitions.m_singleTransition.set(0);
@@ -154,26 +125,6 @@ namespace JSC {
}
}
- Structure* getAnonymousSlotTransition(unsigned count)
- {
- if (usingSingleTransitionSlot())
- return 0;
- return table()->getSlotTransition(count);
- }
-
- void addAnonymousSlotTransition(unsigned count, Structure* structure)
- {
- if (usingSingleTransitionSlot())
- reifySingleTransition();
- ASSERT(!table()->getSlotTransition(count));
- table()->addSlotTransition(count, structure);
- }
-
- void removeAnonymousSlotTransition(unsigned count)
- {
- ASSERT(!usingSingleTransitionSlot());
- table()->removeSlotTransition(count);
- }
private:
TransitionTable* table() const { ASSERT(!usingSingleTransitionSlot()); return m_transitions.m_table; }
Structure* singleTransition() const {
diff --git a/JavaScriptCore/runtime/TimeoutChecker.cpp b/JavaScriptCore/runtime/TimeoutChecker.cpp
index 2a056c9..250fdaf 100644
--- a/JavaScriptCore/runtime/TimeoutChecker.cpp
+++ b/JavaScriptCore/runtime/TimeoutChecker.cpp
@@ -33,14 +33,18 @@
#include "CallFrame.h"
#include "JSGlobalObject.h"
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
#include <mach/mach.h>
-#elif PLATFORM(WIN_OS)
+#elif OS(WINDOWS)
#include <windows.h>
#else
#include "CurrentTime.h"
#endif
+#if PLATFORM(BREWMP)
+#include <AEEStdLib.h>
+#endif
+
using namespace std;
namespace JSC {
@@ -54,7 +58,7 @@ static const int intervalBetweenChecks = 1000;
// Returns the time the current thread has spent executing, in milliseconds.
static inline unsigned getCPUTime()
{
-#if PLATFORM(DARWIN)
+#if OS(DARWIN)
mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
thread_basic_info_data_t info;
@@ -67,7 +71,7 @@ static inline unsigned getCPUTime()
time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
return time;
-#elif PLATFORM(WIN_OS)
+#elif OS(WINDOWS)
union {
FILETIME fileTime;
unsigned long long fileTimeAsLong;
@@ -80,6 +84,11 @@ static inline unsigned getCPUTime()
GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
+#elif PLATFORM(BREWMP)
+ // This function returns a continuously and linearly increasing millisecond
+ // timer from the time the device was powered on.
+ // There is only one thread in BREW, so this is enough.
+ return GETUPTIMEMS();
#else
// FIXME: We should return the time the current thread has spent executing.
return currentTime() * 1000;
diff --git a/JavaScriptCore/runtime/Tracing.d b/JavaScriptCore/runtime/Tracing.d
index b9efaff..da854b9 100644
--- a/JavaScriptCore/runtime/Tracing.d
+++ b/JavaScriptCore/runtime/Tracing.d
@@ -27,7 +27,7 @@ provider JavaScriptCore
{
probe gc__begin();
probe gc__marked();
- probe gc__end(int, int);
+ probe gc__end();
probe profile__will_execute(int, char*, char*, int);
probe profile__did_execute(int, char*, char*, int);
diff --git a/JavaScriptCore/runtime/Tracing.h b/JavaScriptCore/runtime/Tracing.h
index e544f66..c28c85f 100644
--- a/JavaScriptCore/runtime/Tracing.h
+++ b/JavaScriptCore/runtime/Tracing.h
@@ -33,7 +33,7 @@
#define JAVASCRIPTCORE_GC_BEGIN()
#define JAVASCRIPTCORE_GC_BEGIN_ENABLED() 0
-#define JAVASCRIPTCORE_GC_END(arg0, arg1)
+#define JAVASCRIPTCORE_GC_END()
#define JAVASCRIPTCORE_GC_END_ENABLED() 0
#define JAVASCRIPTCORE_GC_MARKED()
diff --git a/JavaScriptCore/runtime/UString.cpp b/JavaScriptCore/runtime/UString.cpp
index 50d23c4..e75a05c 100644
--- a/JavaScriptCore/runtime/UString.cpp
+++ b/JavaScriptCore/runtime/UString.cpp
@@ -52,52 +52,11 @@ using namespace WTF;
using namespace WTF::Unicode;
using namespace std;
-// This can be tuned differently per platform by putting platform #ifs right here.
-// If you don't define this macro at all, then copyChars will just call directly
-// to memcpy.
-#define USTRING_COPY_CHARS_INLINE_CUTOFF 20
-
namespace JSC {
extern const double NaN;
extern const double Inf;
-// This number must be at least 2 to avoid sharing empty, null as well as 1 character strings from SmallStrings.
-static const int minLengthToShare = 10;
-
-static inline size_t overflowIndicator() { return std::numeric_limits<size_t>::max(); }
-static inline size_t maxUChars() { return std::numeric_limits<size_t>::max() / sizeof(UChar); }
-
-static inline PossiblyNull<UChar*> allocChars(size_t length)
-{
- ASSERT(length);
- if (length > maxUChars())
- return 0;
- return tryFastMalloc(sizeof(UChar) * length);
-}
-
-static inline PossiblyNull<UChar*> reallocChars(UChar* buffer, size_t length)
-{
- ASSERT(length);
- if (length > maxUChars())
- return 0;
- return tryFastRealloc(buffer, sizeof(UChar) * length);
-}
-
-static inline void copyChars(UChar* destination, const UChar* source, unsigned numCharacters)
-{
-#ifdef USTRING_COPY_CHARS_INLINE_CUTOFF
- if (numCharacters <= USTRING_COPY_CHARS_INLINE_CUTOFF) {
- for (unsigned i = 0; i < numCharacters; ++i)
- destination[i] = source[i];
- return;
- }
-#endif
- memcpy(destination, source, numCharacters * sizeof(UChar));
-}
-
-COMPILE_ASSERT(sizeof(UChar) == 2, uchar_is_2_bytes);
-
CString::CString(const char* c)
: m_length(strlen(c))
, m_data(new char[m_length + 1])
@@ -190,371 +149,17 @@ bool operator==(const CString& c1, const CString& c2)
// These static strings are immutable, except for rc, whose initial value is chosen to
// reduce the possibility of it becoming zero due to ref/deref not being thread-safe.
static UChar sharedEmptyChar;
-UString::BaseString* UString::Rep::nullBaseString;
-UString::BaseString* UString::Rep::emptyBaseString;
+UStringImpl* UStringImpl::s_null;
+UStringImpl* UStringImpl::s_empty;
UString* UString::nullUString;
-static void initializeStaticBaseString(UString::BaseString& base)
-{
- base.rc = INT_MAX / 2;
- base.m_identifierTableAndFlags.setFlag(UString::Rep::StaticFlag);
- base.checkConsistency();
-}
-
void initializeUString()
{
- UString::Rep::nullBaseString = new UString::BaseString(0, 0);
- initializeStaticBaseString(*UString::Rep::nullBaseString);
-
- UString::Rep::emptyBaseString = new UString::BaseString(&sharedEmptyChar, 0);
- initializeStaticBaseString(*UString::Rep::emptyBaseString);
-
+ UStringImpl::s_null = new UStringImpl(0, 0, UStringImpl::ConstructStaticString);
+ UStringImpl::s_empty = new UStringImpl(&sharedEmptyChar, 0, UStringImpl::ConstructStaticString);
UString::nullUString = new UString;
}
-static char* statBuffer = 0; // Only used for debugging via UString::ascii().
-
-PassRefPtr<UString::Rep> UString::Rep::createCopying(const UChar* d, int l)
-{
- UChar* copyD = static_cast<UChar*>(fastMalloc(l * sizeof(UChar)));
- copyChars(copyD, d, l);
- return create(copyD, l);
-}
-
-PassRefPtr<UString::Rep> UString::Rep::createFromUTF8(const char* string)
-{
- if (!string)
- return &UString::Rep::null();
-
- size_t length = strlen(string);
- Vector<UChar, 1024> buffer(length);
- UChar* p = buffer.data();
- if (conversionOK != convertUTF8ToUTF16(&string, string + length, &p, p + length))
- return &UString::Rep::null();
-
- return UString::Rep::createCopying(buffer.data(), p - buffer.data());
-}
-
-PassRefPtr<UString::Rep> UString::Rep::create(UChar* string, int length, PassRefPtr<UString::SharedUChar> sharedBuffer)
-{
- PassRefPtr<UString::Rep> rep = create(string, length);
- rep->baseString()->setSharedBuffer(sharedBuffer);
- rep->checkConsistency();
- return rep;
-}
-
-UString::SharedUChar* UString::Rep::sharedBuffer()
-{
- UString::BaseString* base = baseString();
- if (len < minLengthToShare)
- return 0;
-
- return base->sharedBuffer();
-}
-
-void UString::Rep::destroy()
-{
- checkConsistency();
-
- // Static null and empty strings can never be destroyed, but we cannot rely on
- // reference counting, because ref/deref are not thread-safe.
- if (!isStatic()) {
- if (identifierTable())
- Identifier::remove(this);
-
- UString::BaseString* base = baseString();
- if (base == this) {
- if (m_sharedBuffer)
- m_sharedBuffer->deref();
- else
- fastFree(base->buf);
- } else
- base->deref();
-
- delete this;
- }
-}
-
-// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
-// or anything like that.
-const unsigned PHI = 0x9e3779b9U;
-
-// Paul Hsieh's SuperFastHash
-// http://www.azillionmonkeys.com/qed/hash.html
-unsigned UString::Rep::computeHash(const UChar* s, int len)
-{
- unsigned l = len;
- uint32_t hash = PHI;
- uint32_t tmp;
-
- int rem = l & 1;
- l >>= 1;
-
- // Main loop
- for (; l > 0; l--) {
- hash += s[0];
- tmp = (s[1] << 11) ^ hash;
- hash = (hash << 16) ^ tmp;
- s += 2;
- hash += hash >> 11;
- }
-
- // Handle end case
- if (rem) {
- hash += s[0];
- hash ^= hash << 11;
- hash += hash >> 17;
- }
-
- // Force "avalanching" of final 127 bits
- hash ^= hash << 3;
- hash += hash >> 5;
- hash ^= hash << 2;
- hash += hash >> 15;
- hash ^= hash << 10;
-
- // this avoids ever returning a hash code of 0, since that is used to
- // signal "hash not computed yet", using a value that is likely to be
- // effectively the same as 0 when the low bits are masked
- if (hash == 0)
- hash = 0x80000000;
-
- return hash;
-}
-
-// Paul Hsieh's SuperFastHash
-// http://www.azillionmonkeys.com/qed/hash.html
-unsigned UString::Rep::computeHash(const char* s, int l)
-{
- // This hash is designed to work on 16-bit chunks at a time. But since the normal case
- // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
- // were 16-bit chunks, which should give matching results
-
- uint32_t hash = PHI;
- uint32_t tmp;
-
- size_t rem = l & 1;
- l >>= 1;
-
- // Main loop
- for (; l > 0; l--) {
- hash += static_cast<unsigned char>(s[0]);
- tmp = (static_cast<unsigned char>(s[1]) << 11) ^ hash;
- hash = (hash << 16) ^ tmp;
- s += 2;
- hash += hash >> 11;
- }
-
- // Handle end case
- if (rem) {
- hash += static_cast<unsigned char>(s[0]);
- hash ^= hash << 11;
- hash += hash >> 17;
- }
-
- // Force "avalanching" of final 127 bits
- hash ^= hash << 3;
- hash += hash >> 5;
- hash ^= hash << 2;
- hash += hash >> 15;
- hash ^= hash << 10;
-
- // this avoids ever returning a hash code of 0, since that is used to
- // signal "hash not computed yet", using a value that is likely to be
- // effectively the same as 0 when the low bits are masked
- if (hash == 0)
- hash = 0x80000000;
-
- return hash;
-}
-
-#ifndef NDEBUG
-void UString::Rep::checkConsistency() const
-{
- const UString::BaseString* base = baseString();
-
- // There is no recursion for base strings.
- ASSERT(base == base->baseString());
-
- if (isStatic()) {
- // There are only two static strings: null and empty.
- ASSERT(!len);
-
- // Static strings cannot get in identifier tables, because they are globally shared.
- ASSERT(!identifierTable());
- }
-
- // The string fits in buffer.
- ASSERT(base->usedPreCapacity <= base->preCapacity);
- ASSERT(base->usedCapacity <= base->capacity);
- ASSERT(-offset <= base->usedPreCapacity);
- ASSERT(offset + len <= base->usedCapacity);
-}
-#endif
-
-UString::SharedUChar* UString::BaseString::sharedBuffer()
-{
- if (!m_sharedBuffer)
- setSharedBuffer(SharedUChar::create(new OwnFastMallocPtr<UChar>(buf)));
- return m_sharedBuffer;
-}
-
-void UString::BaseString::setSharedBuffer(PassRefPtr<UString::SharedUChar> sharedBuffer)
-{
- // The manual steps below are because m_sharedBuffer can't be a RefPtr. m_sharedBuffer
- // is in a union with another variable to avoid making BaseString any larger.
- if (m_sharedBuffer)
- m_sharedBuffer->deref();
- m_sharedBuffer = sharedBuffer.releaseRef();
-}
-
-bool UString::BaseString::slowIsBufferReadOnly()
-{
- // The buffer may not be modified as soon as the underlying data has been shared with another class.
- if (m_sharedBuffer->isShared())
- return true;
-
- // At this point, we know it that the underlying buffer isn't shared outside of this base class,
- // so get rid of m_sharedBuffer.
- OwnPtr<OwnFastMallocPtr<UChar> > mallocPtr(m_sharedBuffer->release());
- UChar* unsharedBuf = const_cast<UChar*>(mallocPtr->release());
- setSharedBuffer(0);
- preCapacity += (buf - unsharedBuf);
- buf = unsharedBuf;
- return false;
-}
-
-// Put these early so they can be inlined.
-static inline size_t expandedSize(size_t capacitySize, size_t precapacitySize)
-{
- // Combine capacitySize & precapacitySize to produce a single size to allocate,
- // check that doing so does not result in overflow.
- size_t size = capacitySize + precapacitySize;
- if (size < capacitySize)
- return overflowIndicator();
-
- // Small Strings (up to 4 pages):
- // Expand the allocation size to 112.5% of the amount requested. This is largely sicking
- // to our previous policy, however 112.5% is cheaper to calculate.
- if (size < 0x4000) {
- size_t expandedSize = ((size + (size >> 3)) | 15) + 1;
- // Given the limited range within which we calculate the expansion in this
- // fashion the above calculation should never overflow.
- ASSERT(expandedSize >= size);
- ASSERT(expandedSize < maxUChars());
- return expandedSize;
- }
-
- // Medium Strings (up to 128 pages):
- // For pages covering multiple pages over-allocation is less of a concern - any unused
- // space will not be paged in if it is not used, so this is purely a VM overhead. For
- // these strings allocate 2x the requested size.
- if (size < 0x80000) {
- size_t expandedSize = ((size + size) | 0xfff) + 1;
- // Given the limited range within which we calculate the expansion in this
- // fashion the above calculation should never overflow.
- ASSERT(expandedSize >= size);
- ASSERT(expandedSize < maxUChars());
- return expandedSize;
- }
-
- // Large Strings (to infinity and beyond!):
- // Revert to our 112.5% policy - probably best to limit the amount of unused VM we allow
- // any individual string be responsible for.
- size_t expandedSize = ((size + (size >> 3)) | 0xfff) + 1;
-
- // Check for overflow - any result that is at least as large as requested (but
- // still below the limit) is okay.
- if ((expandedSize >= size) && (expandedSize < maxUChars()))
- return expandedSize;
- return overflowIndicator();
-}
-
-static inline bool expandCapacity(UString::Rep* rep, int requiredLength)
-{
- rep->checkConsistency();
- ASSERT(!rep->baseString()->isBufferReadOnly());
-
- UString::BaseString* base = rep->baseString();
-
- if (requiredLength > base->capacity) {
- size_t newCapacity = expandedSize(requiredLength, base->preCapacity);
- UChar* oldBuf = base->buf;
- if (!reallocChars(base->buf, newCapacity).getValue(base->buf)) {
- base->buf = oldBuf;
- return false;
- }
- base->capacity = newCapacity - base->preCapacity;
- }
- if (requiredLength > base->usedCapacity)
- base->usedCapacity = requiredLength;
-
- rep->checkConsistency();
- return true;
-}
-
-bool UString::Rep::reserveCapacity(int capacity)
-{
- // If this is an empty string there is no point 'growing' it - just allocate a new one.
- // If the BaseString is shared with another string that is using more capacity than this
- // string is, then growing the buffer won't help.
- // If the BaseString's buffer is readonly, then it isn't allowed to grow.
- UString::BaseString* base = baseString();
- if (!base->buf || !base->capacity || (offset + len) != base->usedCapacity || base->isBufferReadOnly())
- return false;
-
- // If there is already sufficient capacity, no need to grow!
- if (capacity <= base->capacity)
- return true;
-
- checkConsistency();
-
- size_t newCapacity = expandedSize(capacity, base->preCapacity);
- UChar* oldBuf = base->buf;
- if (!reallocChars(base->buf, newCapacity).getValue(base->buf)) {
- base->buf = oldBuf;
- return false;
- }
- base->capacity = newCapacity - base->preCapacity;
-
- checkConsistency();
- return true;
-}
-
-void UString::expandCapacity(int requiredLength)
-{
- if (!JSC::expandCapacity(m_rep.get(), requiredLength))
- makeNull();
-}
-
-void UString::expandPreCapacity(int requiredPreCap)
-{
- m_rep->checkConsistency();
- ASSERT(!m_rep->baseString()->isBufferReadOnly());
-
- BaseString* base = m_rep->baseString();
-
- if (requiredPreCap > base->preCapacity) {
- size_t newCapacity = expandedSize(requiredPreCap, base->capacity);
- int delta = newCapacity - base->capacity - base->preCapacity;
-
- UChar* newBuf;
- if (!allocChars(newCapacity).getValue(newBuf)) {
- makeNull();
- return;
- }
- copyChars(newBuf + delta, base->buf, base->capacity + base->preCapacity);
- fastFree(base->buf);
- base->buf = newBuf;
-
- base->preCapacity = newCapacity - base->capacity;
- }
- if (requiredPreCap > base->usedPreCapacity)
- base->usedPreCapacity = requiredPreCap;
-
- m_rep->checkConsistency();
-}
-
static PassRefPtr<UString::Rep> createRep(const char* c)
{
if (!c)
@@ -565,14 +170,13 @@ static PassRefPtr<UString::Rep> createRep(const char* c)
size_t length = strlen(c);
UChar* d;
- if (!allocChars(length).getValue(d))
+ PassRefPtr<UStringImpl> result = UStringImpl::tryCreateUninitialized(length, d);
+ if (!result)
return &UString::Rep::null();
- else {
- for (size_t i = 0; i < length; i++)
- d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend
- return UString::Rep::create(d, static_cast<int>(length));
- }
+ for (size_t i = 0; i < length; i++)
+ d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend
+ return result;
}
static inline PassRefPtr<UString::Rep> createRep(const char* c, int length)
@@ -584,12 +188,13 @@ static inline PassRefPtr<UString::Rep> createRep(const char* c, int length)
return &UString::Rep::empty();
UChar* d;
- if (!allocChars(length).getValue(d))
+ PassRefPtr<UStringImpl> result = UStringImpl::tryCreateUninitialized(length, d);
+ if (!result)
return &UString::Rep::null();
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 UString::Rep::create(d, length);
+ return result;
}
UString::UString(const char* c)
@@ -607,330 +212,21 @@ UString::UString(const UChar* c, int length)
if (length == 0)
m_rep = &Rep::empty();
else
- m_rep = Rep::createCopying(c, length);
-}
-
-UString::UString(UChar* c, int length, bool copy)
-{
- if (length == 0)
- m_rep = &Rep::empty();
- else if (copy)
- m_rep = Rep::createCopying(c, length);
- else
m_rep = Rep::create(c, length);
}
-UString::UString(const Vector<UChar>& buffer)
+UString UString::createFromUTF8(const char* string)
{
- if (!buffer.size())
- m_rep = &Rep::empty();
- else
- m_rep = Rep::createCopying(buffer.data(), buffer.size());
-}
-
-static ALWAYS_INLINE int newCapacityWithOverflowCheck(const int currentCapacity, const int extendLength, const bool plusOne = false)
-{
- ASSERT_WITH_MESSAGE(extendLength >= 0, "extendedLength = %d", extendLength);
-
- const int plusLength = plusOne ? 1 : 0;
- if (currentCapacity > std::numeric_limits<int>::max() - extendLength - plusLength)
- CRASH();
-
- return currentCapacity + extendLength + plusLength;
-}
-
-static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Rep> r, const UChar* tData, int tSize)
-{
- RefPtr<UString::Rep> rep = r;
-
- rep->checkConsistency();
-
- int thisSize = rep->size();
- int thisOffset = rep->offset;
- int length = thisSize + tSize;
- UString::BaseString* base = rep->baseString();
-
- // possible cases:
- if (tSize == 0) {
- // t is empty
- } else if (thisSize == 0) {
- // this is empty
- rep = UString::Rep::createCopying(tData, tSize);
- } else if (rep == base && !base->isShared()) {
- // this is direct and has refcount of 1 (so we can just alter it directly)
- if (!expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length)))
- rep = &UString::Rep::null();
- if (rep->data()) {
- copyChars(rep->data() + thisSize, tData, tSize);
- rep->len = length;
- rep->_hash = 0;
- }
- } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize && !base->isBufferReadOnly()) {
- // this reaches the end of the buffer - extend it if it's long enough to append to
- if (!expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length)))
- rep = &UString::Rep::null();
- if (rep->data()) {
- copyChars(rep->data() + thisSize, tData, tSize);
- rep = UString::Rep::create(rep, 0, length);
- }
- } else {
- // This is shared in some way that prevents us from modifying base, so we must make a whole new string.
- size_t newCapacity = expandedSize(length, 0);
- UChar* d;
- if (!allocChars(newCapacity).getValue(d))
- rep = &UString::Rep::null();
- else {
- copyChars(d, rep->data(), thisSize);
- copyChars(d + thisSize, tData, tSize);
- rep = UString::Rep::create(d, length);
- rep->baseString()->capacity = newCapacity;
- }
- }
-
- rep->checkConsistency();
-
- return rep.release();
-}
-
-static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Rep> r, const char* t)
-{
- RefPtr<UString::Rep> rep = r;
-
- rep->checkConsistency();
-
- int thisSize = rep->size();
- int thisOffset = rep->offset;
- int tSize = static_cast<int>(strlen(t));
- int length = thisSize + tSize;
- UString::BaseString* base = rep->baseString();
-
- // possible cases:
- if (thisSize == 0) {
- // this is empty
- rep = createRep(t);
- } else if (tSize == 0) {
- // t is empty, we'll just return *this below.
- } else if (rep == base && !base->isShared()) {
- // this is direct and has refcount of 1 (so we can just alter it directly)
- expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length));
- UChar* d = rep->data();
- if (d) {
- for (int i = 0; i < tSize; ++i)
- d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend
- rep->len = length;
- rep->_hash = 0;
- }
- } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize && !base->isBufferReadOnly()) {
- // this string reaches the end of the buffer - extend it
- expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length));
- UChar* d = rep->data();
- if (d) {
- for (int i = 0; i < tSize; ++i)
- d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend
- rep = UString::Rep::create(rep, 0, length);
- }
- } else {
- // This is shared in some way that prevents us from modifying base, so we must make a whole new string.
- size_t newCapacity = expandedSize(length, 0);
- UChar* d;
- if (!allocChars(newCapacity).getValue(d))
- rep = &UString::Rep::null();
- else {
- copyChars(d, rep->data(), thisSize);
- for (int i = 0; i < tSize; ++i)
- d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend
- rep = UString::Rep::create(d, length);
- rep->baseString()->capacity = newCapacity;
- }
- }
-
- rep->checkConsistency();
-
- return rep.release();
-}
-
-PassRefPtr<UString::Rep> concatenate(UString::Rep* a, UString::Rep* b)
-{
- a->checkConsistency();
- b->checkConsistency();
-
- int aSize = a->size();
- int bSize = b->size();
- int aOffset = a->offset;
-
- // possible cases:
-
- UString::BaseString* aBase = a->baseString();
- if (bSize == 1 && aOffset + aSize == aBase->usedCapacity && aOffset + aSize < aBase->capacity && !aBase->isBufferReadOnly()) {
- // b is a single character (common fast case)
- ++aBase->usedCapacity;
- a->data()[aSize] = b->data()[0];
- return UString::Rep::create(a, 0, aSize + 1);
- }
-
- // a is empty
- if (aSize == 0)
- return b;
- // b is empty
- if (bSize == 0)
- return a;
-
- int bOffset = b->offset;
- int length = aSize + bSize;
-
- UString::BaseString* bBase = b->baseString();
- if (aOffset + aSize == aBase->usedCapacity && aSize >= minShareSize && 4 * aSize >= bSize
- && (-bOffset != bBase->usedPreCapacity || aSize >= bSize) && !aBase->isBufferReadOnly()) {
- // - a reaches the end of its buffer so it qualifies for shared append
- // - also, it's at least a quarter the length of b - appending to a much shorter
- // string does more harm than good
- // - however, if b qualifies for prepend and is longer than a, we'd rather prepend
-
- UString x(a);
- x.expandCapacity(newCapacityWithOverflowCheck(aOffset, length));
- if (!a->data() || !x.data())
- return 0;
- copyChars(a->data() + aSize, b->data(), bSize);
- PassRefPtr<UString::Rep> result = UString::Rep::create(a, 0, length);
-
- a->checkConsistency();
- b->checkConsistency();
- result->checkConsistency();
-
- return result;
- }
-
- if (-bOffset == bBase->usedPreCapacity && bSize >= minShareSize && 4 * bSize >= aSize && !bBase->isBufferReadOnly()) {
- // - b reaches the beginning of its buffer so it qualifies for shared prepend
- // - also, it's at least a quarter the length of a - prepending to a much shorter
- // string does more harm than good
- UString y(b);
- y.expandPreCapacity(-bOffset + aSize);
- if (!b->data() || !y.data())
- return 0;
- copyChars(b->data() - aSize, a->data(), aSize);
- PassRefPtr<UString::Rep> result = UString::Rep::create(b, -aSize, length);
-
- a->checkConsistency();
- b->checkConsistency();
- result->checkConsistency();
-
- return result;
- }
-
- // a does not qualify for append, and b does not qualify for prepend, gotta make a whole new string
- size_t newCapacity = expandedSize(length, 0);
- UChar* d;
- if (!allocChars(newCapacity).getValue(d))
- return 0;
- copyChars(d, a->data(), aSize);
- copyChars(d + aSize, b->data(), bSize);
- PassRefPtr<UString::Rep> result = UString::Rep::create(d, length);
- result->baseString()->capacity = newCapacity;
-
- a->checkConsistency();
- b->checkConsistency();
- result->checkConsistency();
-
- return result;
-}
-
-PassRefPtr<UString::Rep> concatenate(UString::Rep* rep, int i)
-{
- UChar buf[1 + sizeof(i) * 3];
- UChar* end = buf + sizeof(buf) / sizeof(UChar);
- UChar* p = end;
-
- if (i == 0)
- *--p = '0';
- else if (i == INT_MIN) {
- char minBuf[1 + sizeof(i) * 3];
- sprintf(minBuf, "%d", INT_MIN);
- return concatenate(rep, minBuf);
- } else {
- bool negative = false;
- if (i < 0) {
- negative = true;
- i = -i;
- }
- while (i) {
- *--p = static_cast<unsigned short>((i % 10) + '0');
- i /= 10;
- }
- if (negative)
- *--p = '-';
- }
+ if (!string)
+ return null();
- return concatenate(rep, p, static_cast<int>(end - p));
+ size_t length = strlen(string);
+ Vector<UChar, 1024> buffer(length);
+ UChar* p = buffer.data();
+ if (conversionOK != convertUTF8ToUTF16(&string, string + length, &p, p + length))
+ return null();
-}
-
-PassRefPtr<UString::Rep> concatenate(UString::Rep* rep, double d)
-{
- // avoid ever printing -NaN, in JS conceptually there is only one NaN value
- if (isnan(d))
- return concatenate(rep, "NaN");
-
- if (d == 0.0) // stringify -0 as 0
- d = 0.0;
-
- char buf[80];
- int decimalPoint;
- int sign;
-
- char result[80];
- WTF::dtoa(result, d, 0, &decimalPoint, &sign, NULL);
- int length = static_cast<int>(strlen(result));
-
- int i = 0;
- if (sign)
- buf[i++] = '-';
-
- if (decimalPoint <= 0 && decimalPoint > -6) {
- buf[i++] = '0';
- buf[i++] = '.';
- for (int j = decimalPoint; j < 0; j++)
- buf[i++] = '0';
- strcpy(buf + i, result);
- } else if (decimalPoint <= 21 && decimalPoint > 0) {
- if (length <= decimalPoint) {
- strcpy(buf + i, result);
- i += length;
- for (int j = 0; j < decimalPoint - length; j++)
- buf[i++] = '0';
- buf[i] = '\0';
- } else {
- strncpy(buf + i, result, decimalPoint);
- i += decimalPoint;
- buf[i++] = '.';
- strcpy(buf + i, result + decimalPoint);
- }
- } else if (result[0] < '0' || result[0] > '9')
- strcpy(buf + i, result);
- else {
- buf[i++] = result[0];
- if (length > 1) {
- buf[i++] = '.';
- strcpy(buf + i, result + 1);
- i += length - 1;
- }
-
- buf[i++] = 'e';
- buf[i++] = (decimalPoint >= 0) ? '+' : '-';
- // decimalPoint can't be more than 3 digits decimal given the
- // nature of float representation
- int exponential = decimalPoint - 1;
- if (exponential < 0)
- exponential = -exponential;
- if (exponential >= 100)
- buf[i++] = static_cast<char>('0' + exponential / 100);
- if (exponential >= 10)
- buf[i++] = static_cast<char>('0' + (exponential % 100) / 10);
- buf[i++] = static_cast<char>('0' + exponential % 10);
- buf[i++] = '\0';
- }
-
- return concatenate(rep, buf);
+ return UString(buffer.data(), p - buffer.data());
}
UString UString::from(int i)
@@ -972,7 +268,7 @@ UString UString::from(long long i)
*--p = '0';
else if (i == std::numeric_limits<long long>::min()) {
char minBuf[1 + sizeof(i) * 3];
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
snprintf(minBuf, sizeof(minBuf) - 1, "%I64d", std::numeric_limits<long long>::min());
#else
snprintf(minBuf, sizeof(minBuf) - 1, "%lld", std::numeric_limits<long long>::min());
@@ -1073,23 +369,24 @@ UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, in
return "";
UChar* buffer;
- if (!allocChars(totalLength).getValue(buffer))
+ PassRefPtr<Rep> rep = Rep::tryCreateUninitialized(totalLength, buffer);
+ if (!rep)
return null();
int maxCount = max(rangeCount, separatorCount);
int bufferPos = 0;
for (int i = 0; i < maxCount; i++) {
if (i < rangeCount) {
- copyChars(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length);
+ UStringImpl::copyChars(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length);
bufferPos += substringRanges[i].length;
}
if (i < separatorCount) {
- copyChars(buffer + bufferPos, separators[i].data(), separators[i].size());
+ UStringImpl::copyChars(buffer + bufferPos, separators[i].data(), separators[i].size());
bufferPos += separators[i].size();
}
}
- return UString::Rep::create(buffer, totalLength);
+ return rep;
}
UString UString::replaceRange(int rangeStart, int rangeLength, const UString& replacement) const
@@ -1102,136 +399,16 @@ UString UString::replaceRange(int rangeStart, int rangeLength, const UString& re
return "";
UChar* buffer;
- if (!allocChars(totalLength).getValue(buffer))
+ PassRefPtr<Rep> rep = Rep::tryCreateUninitialized(totalLength, buffer);
+ if (!rep)
return null();
- copyChars(buffer, data(), rangeStart);
- copyChars(buffer + rangeStart, replacement.data(), replacementLength);
+ UStringImpl::copyChars(buffer, data(), rangeStart);
+ UStringImpl::copyChars(buffer + rangeStart, replacement.data(), replacementLength);
int rangeEnd = rangeStart + rangeLength;
- copyChars(buffer + rangeStart + replacementLength, data() + rangeEnd, size() - rangeEnd);
-
- return UString::Rep::create(buffer, totalLength);
-}
-
-
-UString& UString::append(const UString &t)
-{
- m_rep->checkConsistency();
- t.rep()->checkConsistency();
-
- int thisSize = size();
- int thisOffset = m_rep->offset;
- int tSize = t.size();
- int length = thisSize + tSize;
- BaseString* base = m_rep->baseString();
-
- // possible cases:
- if (thisSize == 0) {
- // this is empty
- *this = t;
- } else if (tSize == 0) {
- // t is empty
- } else if (m_rep == base && !base->isShared()) {
- // this is direct and has refcount of 1 (so we can just alter it directly)
- expandCapacity(newCapacityWithOverflowCheck(thisOffset, length));
- if (data()) {
- copyChars(m_rep->data() + thisSize, t.data(), tSize);
- m_rep->len = length;
- m_rep->_hash = 0;
- }
- } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize && !base->isBufferReadOnly()) {
- // this reaches the end of the buffer - extend it if it's long enough to append to
- expandCapacity(newCapacityWithOverflowCheck(thisOffset, length));
- if (data()) {
- copyChars(m_rep->data() + thisSize, t.data(), tSize);
- m_rep = Rep::create(m_rep, 0, length);
- }
- } else {
- // This is shared in some way that prevents us from modifying base, so we must make a whole new string.
- size_t newCapacity = expandedSize(length, 0);
- UChar* d;
- if (!allocChars(newCapacity).getValue(d))
- makeNull();
- else {
- copyChars(d, data(), thisSize);
- copyChars(d + thisSize, t.data(), tSize);
- m_rep = Rep::create(d, length);
- m_rep->baseString()->capacity = newCapacity;
- }
- }
-
- m_rep->checkConsistency();
- t.rep()->checkConsistency();
+ UStringImpl::copyChars(buffer + rangeStart + replacementLength, data() + rangeEnd, size() - rangeEnd);
- return *this;
-}
-
-UString& UString::append(const UChar* tData, int tSize)
-{
- m_rep = concatenate(m_rep.release(), tData, tSize);
- return *this;
-}
-
-UString& UString::append(const char* t)
-{
- m_rep = concatenate(m_rep.release(), t);
- return *this;
-}
-
-UString& UString::append(UChar c)
-{
- m_rep->checkConsistency();
-
- int thisOffset = m_rep->offset;
- int length = size();
- BaseString* base = m_rep->baseString();
-
- // possible cases:
- if (length == 0) {
- // this is empty - must make a new m_rep because we don't want to pollute the shared empty one
- size_t newCapacity = expandedSize(1, 0);
- UChar* d;
- if (!allocChars(newCapacity).getValue(d))
- makeNull();
- else {
- d[0] = c;
- m_rep = Rep::create(d, 1);
- m_rep->baseString()->capacity = newCapacity;
- }
- } else if (m_rep == base && !base->isShared()) {
- // this is direct and has refcount of 1 (so we can just alter it directly)
- expandCapacity(newCapacityWithOverflowCheck(thisOffset, length, true));
- UChar* d = m_rep->data();
- if (d) {
- d[length] = c;
- m_rep->len = length + 1;
- m_rep->_hash = 0;
- }
- } else if (thisOffset + length == base->usedCapacity && length >= minShareSize && !base->isBufferReadOnly()) {
- // this reaches the end of the string - extend it and share
- expandCapacity(newCapacityWithOverflowCheck(thisOffset, length, true));
- UChar* d = m_rep->data();
- if (d) {
- d[length] = c;
- m_rep = Rep::create(m_rep, 0, length + 1);
- }
- } else {
- // This is shared in some way that prevents us from modifying base, so we must make a whole new string.
- size_t newCapacity = expandedSize(length + 1, 0);
- UChar* d;
- if (!allocChars(newCapacity).getValue(d))
- makeNull();
- else {
- copyChars(d, data(), length);
- d[length] = c;
- m_rep = Rep::create(d, length + 1);
- m_rep->baseString()->capacity = newCapacity;
- }
- }
-
- m_rep->checkConsistency();
-
- return *this;
+ return rep;
}
bool UString::getCString(CStringBuffer& buffer) const
@@ -1259,13 +436,15 @@ bool UString::getCString(CStringBuffer& buffer) const
char* UString::ascii() const
{
+ static char* asciiBuffer = 0;
+
int length = size();
int neededSize = length + 1;
- delete[] statBuffer;
- statBuffer = new char[neededSize];
+ delete[] asciiBuffer;
+ asciiBuffer = new char[neededSize];
const UChar* p = data();
- char* q = statBuffer;
+ char* q = asciiBuffer;
const UChar* limit = p + length;
while (p != limit) {
*q = static_cast<char>(p[0]);
@@ -1274,7 +453,7 @@ char* UString::ascii() const
}
*q = '\0';
- return statBuffer;
+ return asciiBuffer;
}
UString& UString::operator=(const char* c)
@@ -1290,21 +469,13 @@ UString& UString::operator=(const char* c)
}
int l = static_cast<int>(strlen(c));
- UChar* d;
- BaseString* base = m_rep->baseString();
- if (!base->isShared() && l <= base->capacity && m_rep == base && m_rep->offset == 0 && base->preCapacity == 0) {
- d = base->buf;
- m_rep->_hash = 0;
- m_rep->len = l;
- } else {
- if (!allocChars(l).getValue(d)) {
- makeNull();
- return *this;
- }
- m_rep = Rep::create(d, l);
- }
- for (int i = 0; i < l; i++)
- d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend
+ UChar* d = 0;
+ m_rep = Rep::tryCreateUninitialized(l, d);
+ if (m_rep) {
+ for (int i = 0; i < l; i++)
+ d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend
+ } else
+ makeNull();
return *this;
}
@@ -1462,7 +633,7 @@ uint32_t UString::toStrictUInt32(bool* ok) const
*ok = false;
// Empty string is not OK.
- int len = m_rep->len;
+ int len = m_rep->size();
if (len == 0)
return 0;
const UChar* p = m_rep->data();
@@ -1689,8 +860,8 @@ int compare(const UString& s1, const UString& s2)
bool equal(const UString::Rep* r, const UString::Rep* b)
{
- int length = r->len;
- if (length != b->len)
+ int length = r->size();
+ if (length != b->size())
return false;
const UChar* d = r->data();
const UChar* s = b->data();
diff --git a/JavaScriptCore/runtime/UString.h b/JavaScriptCore/runtime/UString.h
index 9b046f2..0c13689 100644
--- a/JavaScriptCore/runtime/UString.h
+++ b/JavaScriptCore/runtime/UString.h
@@ -24,6 +24,7 @@
#define UString_h
#include "Collector.h"
+#include "UStringImpl.h"
#include <stdint.h>
#include <string.h>
#include <wtf/Assertions.h>
@@ -40,8 +41,6 @@ namespace JSC {
using WTF::PlacementNewAdoptType;
using WTF::PlacementNewAdopt;
- class IdentifierTable;
-
class CString {
public:
CString()
@@ -71,194 +70,47 @@ namespace JSC {
char* m_data;
};
+ bool operator==(const CString&, const CString&);
+
typedef Vector<char, 32> CStringBuffer;
class UString {
friend class JIT;
public:
- typedef CrossThreadRefCounted<OwnFastMallocPtr<UChar> > SharedUChar;
- struct BaseString;
- struct Rep : Noncopyable {
- friend class JIT;
-
- static PassRefPtr<Rep> create(UChar* buffer, int length)
- {
- return adoptRef(new BaseString(buffer, length));
- }
-
- static PassRefPtr<Rep> createEmptyBuffer(size_t size)
- {
- // Guard against integer overflow
- if (size < (std::numeric_limits<size_t>::max() / sizeof(UChar))) {
- void* buf = 0;
- if (tryFastMalloc(size * sizeof(UChar)).getValue(buf))
- return adoptRef(new BaseString(static_cast<UChar*>(buf), 0, size));
- }
- return adoptRef(new BaseString(0, 0, 0));
- }
-
- static PassRefPtr<Rep> createCopying(const UChar*, int);
- static PassRefPtr<Rep> create(PassRefPtr<Rep> base, int offset, int length);
-
- // Constructs a string from a UTF-8 string, using strict conversion (see comments in UTF8.h).
- // Returns UString::Rep::null for null input or conversion failure.
- static PassRefPtr<Rep> createFromUTF8(const char*);
-
- // Uses SharedUChar to have joint ownership over the UChar*.
- static PassRefPtr<Rep> create(UChar*, int, PassRefPtr<SharedUChar>);
-
- SharedUChar* sharedBuffer();
- void destroy();
-
- bool baseIsSelf() const { return m_identifierTableAndFlags.isFlagSet(BaseStringFlag); }
- UChar* data() const;
- int size() const { return len; }
-
- unsigned hash() const { if (_hash == 0) _hash = computeHash(data(), len); return _hash; }
- unsigned computedHash() const { ASSERT(_hash); return _hash; } // fast path for Identifiers
-
- static unsigned computeHash(const UChar*, int length);
- static unsigned computeHash(const char*, int length);
- static unsigned computeHash(const char* s) { return computeHash(s, strlen(s)); }
-
- IdentifierTable* identifierTable() const { return m_identifierTableAndFlags.get(); }
- void setIdentifierTable(IdentifierTable* table) { ASSERT(!isStatic()); m_identifierTableAndFlags.set(table); }
-
- bool isStatic() const { return m_identifierTableAndFlags.isFlagSet(StaticFlag); }
- void setStatic(bool);
- void setBaseString(PassRefPtr<BaseString>);
- BaseString* baseString();
- const BaseString* baseString() const;
-
- Rep* ref() { ++rc; return this; }
- ALWAYS_INLINE void deref() { if (--rc == 0) destroy(); }
-
- void checkConsistency() const;
- enum UStringFlags {
- StaticFlag,
- BaseStringFlag
- };
-
- // unshared data
- int offset;
- int len;
- int rc; // For null and empty static strings, this field does not reflect a correct count, because ref/deref are not thread-safe. A special case in destroy() guarantees that these do not get deleted.
- mutable unsigned _hash;
- PtrAndFlags<IdentifierTable, UStringFlags> m_identifierTableAndFlags;
-
- static BaseString& null() { return *nullBaseString; }
- static BaseString& empty() { return *emptyBaseString; }
-
- bool reserveCapacity(int capacity);
-
- protected:
- // Constructor for use by BaseString subclass; they use the union with m_baseString for another purpose.
- Rep(int length)
- : offset(0)
- , len(length)
- , rc(1)
- , _hash(0)
- , m_baseString(0)
- {
- }
-
- Rep(PassRefPtr<BaseString> base, int offsetInBase, int length)
- : offset(offsetInBase)
- , len(length)
- , rc(1)
- , _hash(0)
- , m_baseString(base.releaseRef())
- {
- checkConsistency();
- }
-
- union {
- // If !baseIsSelf()
- BaseString* m_baseString;
- // If baseIsSelf()
- SharedUChar* m_sharedBuffer;
- };
-
- private:
- // For SmallStringStorage which allocates an array and does initialization manually.
- Rep() { }
-
- friend class SmallStringsStorage;
- friend void initializeUString();
- JS_EXPORTDATA static BaseString* nullBaseString;
- JS_EXPORTDATA static BaseString* emptyBaseString;
- };
-
-
- struct BaseString : public Rep {
- bool isShared() { return rc != 1 || isBufferReadOnly(); }
- void setSharedBuffer(PassRefPtr<SharedUChar>);
-
- bool isBufferReadOnly()
- {
- if (!m_sharedBuffer)
- return false;
- return slowIsBufferReadOnly();
- }
-
- // potentially shared data.
- UChar* buf;
- int preCapacity;
- int usedPreCapacity;
- int capacity;
- int usedCapacity;
-
- size_t reportedCost;
-
- private:
- BaseString(UChar* buffer, int length, int additionalCapacity = 0)
- : Rep(length)
- , buf(buffer)
- , preCapacity(0)
- , usedPreCapacity(0)
- , capacity(length + additionalCapacity)
- , usedCapacity(length)
- , reportedCost(0)
- {
- m_identifierTableAndFlags.setFlag(BaseStringFlag);
- checkConsistency();
- }
-
- SharedUChar* sharedBuffer();
- bool slowIsBufferReadOnly();
-
- friend struct Rep;
- friend class SmallStringsStorage;
- friend void initializeUString();
- };
-
+ typedef UStringImpl Rep;
+
public:
+ // UString constructors passed char*s assume ISO Latin-1 encoding; for UTF8 use 'createFromUTF8', below.
UString();
- // Constructor for null-terminated ASCII string.
- UString(const char*);
- // Constructor for non-null-terminated ASCII string.
+ UString(const char*); // Constructor for null-terminated string.
UString(const char*, int length);
UString(const UChar*, int length);
- UString(UChar*, int length, bool copy);
+ UString(const Vector<UChar>& buffer);
UString(const UString& s)
: m_rep(s.m_rep)
{
}
- UString(const Vector<UChar>& buffer);
+ // Special constructor for cases where we overwrite an object in place.
+ UString(PlacementNewAdoptType)
+ : m_rep(PlacementNewAdopt)
+ {
+ }
~UString()
{
}
- // Special constructor for cases where we overwrite an object in place.
- UString(PlacementNewAdoptType)
- : m_rep(PlacementNewAdopt)
+ template<size_t inlineCapacity>
+ static PassRefPtr<UStringImpl> adopt(Vector<UChar, inlineCapacity>& vector)
{
+ return Rep::adopt(vector);
}
+ static UString createFromUTF8(const char*);
+
static UString from(int);
static UString from(long long);
static UString from(unsigned int);
@@ -285,12 +137,6 @@ namespace JSC {
UString replaceRange(int rangeStart, int RangeEnd, const UString& replacement) const;
- UString& append(const UString&);
- UString& append(const char*);
- UString& append(UChar);
- UString& append(char c) { return append(static_cast<UChar>(static_cast<unsigned char>(c))); }
- UString& append(const UChar*, int size);
-
bool getCString(CStringBuffer&) const;
// NOTE: This method should only be used for *debugging* purposes as it
@@ -309,13 +155,10 @@ namespace JSC {
UString& operator=(const char*c);
- UString& operator+=(const UString& s) { return append(s); }
- UString& operator+=(const char* s) { return append(s); }
-
const UChar* data() const { return m_rep->data(); }
- bool isNull() const { return (m_rep == &Rep::null()); }
- bool isEmpty() const { return (!m_rep->len); }
+ bool isNull() const { return m_rep == &Rep::null(); }
+ bool isEmpty() const { return !m_rep->size(); }
bool is8Bit() const;
@@ -351,22 +194,9 @@ namespace JSC {
ASSERT(m_rep);
}
- size_t cost() const;
-
- // Attempt to grow this string such that it can grow to a total length of 'capacity'
- // without reallocation. This may fail a number of reasons - if the BasicString is
- // shared and another string is using part of the capacity beyond our end point, if
- // the realloc fails, or if this string is empty and has no storage.
- //
- // This method returns a boolean indicating success.
- bool reserveCapacity(int capacity)
- {
- return m_rep->reserveCapacity(capacity);
- }
+ size_t cost() const { return m_rep->cost(); }
private:
- void expandCapacity(int requiredLength);
- void expandPreCapacity(int requiredPreCap);
void makeNull();
RefPtr<Rep> m_rep;
@@ -374,13 +204,9 @@ namespace JSC {
friend void initializeUString();
friend bool operator==(const UString&, const UString&);
- friend PassRefPtr<Rep> concatenate(Rep*, Rep*); // returns 0 if out of memory
};
- PassRefPtr<UString::Rep> concatenate(UString::Rep*, UString::Rep*);
- PassRefPtr<UString::Rep> concatenate(UString::Rep*, int);
- PassRefPtr<UString::Rep> concatenate(UString::Rep*, double);
- inline bool operator==(const UString& s1, const UString& s2)
+ ALWAYS_INLINE bool operator==(const UString& s1, const UString& s2)
{
int size = s1.size();
switch (size) {
@@ -426,117 +252,310 @@ namespace JSC {
return !JSC::operator==(s1, s2);
}
- bool operator==(const CString&, const CString&);
+ int compare(const UString&, const UString&);
- inline UString operator+(const UString& s1, const UString& s2)
+ inline UString::UString()
+ : m_rep(&Rep::null())
{
- RefPtr<UString::Rep> result = concatenate(s1.rep(), s2.rep());
- return UString(result ? result.release() : UString::nullRep());
}
- int compare(const UString&, const UString&);
+ // 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
+ {
+ unsigned i = toStrictUInt32(ok);
+ if (ok && i >= 0xFFFFFFFFU)
+ *ok = false;
+ return i;
+ }
- bool equal(const UString::Rep*, const UString::Rep*);
+ // 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);
- inline PassRefPtr<UString::Rep> UString::Rep::create(PassRefPtr<UString::Rep> rep, int offset, int length)
- {
- ASSERT(rep);
- rep->checkConsistency();
+ struct IdentifierRepHash : PtrHash<RefPtr<JSC::UString::Rep> > {
+ static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->existingHash(); }
+ static unsigned hash(JSC::UString::Rep* key) { return key->existingHash(); }
+ };
- int repOffset = rep->offset;
+ void initializeUString();
- PassRefPtr<BaseString> base = rep->baseString();
+ template<typename StringType>
+ class StringTypeAdapter {
+ };
- ASSERT(-(offset + repOffset) <= base->usedPreCapacity);
- ASSERT(offset + repOffset + length <= base->usedCapacity);
+ template<>
+ class StringTypeAdapter<char*> {
+ public:
+ StringTypeAdapter<char*>(char* buffer)
+ : m_buffer((unsigned char*)buffer)
+ , m_length(strlen(buffer))
+ {
+ }
- // Steal the single reference this Rep was created with.
- return adoptRef(new Rep(base, repOffset + offset, length));
- }
+ unsigned length() { return m_length; }
- inline UChar* UString::Rep::data() const
- {
- const BaseString* base = baseString();
- return base->buf + base->preCapacity + offset;
- }
+ void writeTo(UChar* destination)
+ {
+ for (unsigned i = 0; i < m_length; ++i)
+ destination[i] = m_buffer[i];
+ }
- inline void UString::Rep::setStatic(bool v)
- {
- ASSERT(!identifierTable());
- if (v)
- m_identifierTableAndFlags.setFlag(StaticFlag);
- else
- m_identifierTableAndFlags.clearFlag(StaticFlag);
- }
+ private:
+ const unsigned char* m_buffer;
+ unsigned m_length;
+ };
+
+ template<>
+ class StringTypeAdapter<const char*> {
+ public:
+ StringTypeAdapter<const char*>(const char* buffer)
+ : m_buffer((unsigned char*)buffer)
+ , m_length(strlen(buffer))
+ {
+ }
+
+ unsigned length() { return m_length; }
- inline void UString::Rep::setBaseString(PassRefPtr<BaseString> base)
+ void writeTo(UChar* destination)
+ {
+ for (unsigned i = 0; i < m_length; ++i)
+ destination[i] = m_buffer[i];
+ }
+
+ private:
+ const unsigned char* m_buffer;
+ unsigned m_length;
+ };
+
+ template<>
+ class StringTypeAdapter<UString> {
+ public:
+ StringTypeAdapter<UString>(UString& string)
+ : m_data(string.data())
+ , m_length(string.size())
+ {
+ }
+
+ unsigned length() { return m_length; }
+
+ void writeTo(UChar* destination)
+ {
+ for (unsigned i = 0; i < m_length; ++i)
+ destination[i] = m_data[i];
+ }
+
+ private:
+ const UChar* m_data;
+ unsigned m_length;
+ };
+
+ template<typename StringType1, typename StringType2>
+ UString makeString(StringType1 string1, StringType2 string2)
{
- ASSERT(base != this);
- ASSERT(!baseIsSelf());
- m_baseString = base.releaseRef();
+ StringTypeAdapter<StringType1> adapter1(string1);
+ StringTypeAdapter<StringType2> adapter2(string2);
+
+ UChar* buffer;
+ unsigned length = adapter1.length() + adapter2.length();
+ PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return UString();
+
+ UChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+
+ return resultImpl;
}
- inline UString::BaseString* UString::Rep::baseString()
+ template<typename StringType1, typename StringType2, typename StringType3>
+ UString makeString(StringType1 string1, StringType2 string2, StringType3 string3)
{
- return !baseIsSelf() ? m_baseString : reinterpret_cast<BaseString*>(this) ;
+ StringTypeAdapter<StringType1> adapter1(string1);
+ StringTypeAdapter<StringType2> adapter2(string2);
+ StringTypeAdapter<StringType3> adapter3(string3);
+
+ UChar* buffer;
+ unsigned length = adapter1.length() + adapter2.length() + adapter3.length();
+ PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return UString();
+
+ UChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+ result += adapter2.length();
+ adapter3.writeTo(result);
+
+ return resultImpl;
}
- inline const UString::BaseString* UString::Rep::baseString() const
+ template<typename StringType1, typename StringType2, typename StringType3, typename StringType4>
+ UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4)
{
- return const_cast<Rep*>(this)->baseString();
+ StringTypeAdapter<StringType1> adapter1(string1);
+ StringTypeAdapter<StringType2> adapter2(string2);
+ StringTypeAdapter<StringType3> adapter3(string3);
+ StringTypeAdapter<StringType4> adapter4(string4);
+
+ UChar* buffer;
+ unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length();
+ PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return UString();
+
+ UChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+ result += adapter2.length();
+ adapter3.writeTo(result);
+ result += adapter3.length();
+ adapter4.writeTo(result);
+
+ return resultImpl;
}
-#ifdef NDEBUG
- inline void UString::Rep::checkConsistency() const
+ template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5>
+ UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5)
{
+ StringTypeAdapter<StringType1> adapter1(string1);
+ StringTypeAdapter<StringType2> adapter2(string2);
+ StringTypeAdapter<StringType3> adapter3(string3);
+ StringTypeAdapter<StringType4> adapter4(string4);
+ StringTypeAdapter<StringType5> adapter5(string5);
+
+ UChar* buffer;
+ unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length();
+ PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return UString();
+
+ UChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+ result += adapter2.length();
+ adapter3.writeTo(result);
+ result += adapter3.length();
+ adapter4.writeTo(result);
+ result += adapter4.length();
+ adapter5.writeTo(result);
+
+ return resultImpl;
}
-#endif
- inline UString::UString()
- : m_rep(&Rep::null())
+ template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6>
+ UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6)
{
+ StringTypeAdapter<StringType1> adapter1(string1);
+ StringTypeAdapter<StringType2> adapter2(string2);
+ StringTypeAdapter<StringType3> adapter3(string3);
+ StringTypeAdapter<StringType4> adapter4(string4);
+ StringTypeAdapter<StringType5> adapter5(string5);
+ StringTypeAdapter<StringType6> adapter6(string6);
+
+ UChar* buffer;
+ unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length();
+ PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return UString();
+
+ UChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+ result += adapter2.length();
+ adapter3.writeTo(result);
+ result += adapter3.length();
+ adapter4.writeTo(result);
+ result += adapter4.length();
+ adapter5.writeTo(result);
+ result += adapter5.length();
+ adapter6.writeTo(result);
+
+ return resultImpl;
}
- // 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
+ template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7>
+ UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7)
{
- unsigned i = toStrictUInt32(ok);
- if (ok && i >= 0xFFFFFFFFU)
- *ok = false;
- return i;
+ StringTypeAdapter<StringType1> adapter1(string1);
+ StringTypeAdapter<StringType2> adapter2(string2);
+ StringTypeAdapter<StringType3> adapter3(string3);
+ StringTypeAdapter<StringType4> adapter4(string4);
+ StringTypeAdapter<StringType5> adapter5(string5);
+ StringTypeAdapter<StringType6> adapter6(string6);
+ StringTypeAdapter<StringType7> adapter7(string7);
+
+ UChar* buffer;
+ unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length() + adapter7.length();
+ PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return UString();
+
+ UChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+ result += adapter2.length();
+ adapter3.writeTo(result);
+ result += adapter3.length();
+ adapter4.writeTo(result);
+ result += adapter4.length();
+ adapter5.writeTo(result);
+ result += adapter5.length();
+ adapter6.writeTo(result);
+ result += adapter6.length();
+ adapter7.writeTo(result);
+
+ return resultImpl;
}
- // 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::minExtraCostSize / sizeof(UChar);
-
- inline size_t UString::cost() const
+ template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8>
+ UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8)
{
- BaseString* base = m_rep->baseString();
- size_t capacity = (base->capacity + base->preCapacity) * sizeof(UChar);
- size_t reportedCost = base->reportedCost;
- ASSERT(capacity >= reportedCost);
-
- size_t capacityDelta = capacity - reportedCost;
-
- if (capacityDelta < static_cast<size_t>(minShareSize))
- return 0;
-
- base->reportedCost = capacity;
-
- return capacityDelta;
+ StringTypeAdapter<StringType1> adapter1(string1);
+ StringTypeAdapter<StringType2> adapter2(string2);
+ StringTypeAdapter<StringType3> adapter3(string3);
+ StringTypeAdapter<StringType4> adapter4(string4);
+ StringTypeAdapter<StringType5> adapter5(string5);
+ StringTypeAdapter<StringType6> adapter6(string6);
+ StringTypeAdapter<StringType7> adapter7(string7);
+ StringTypeAdapter<StringType8> adapter8(string8);
+
+ UChar* buffer;
+ unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length() + adapter7.length() + adapter8.length();
+ PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer);
+ if (!resultImpl)
+ return UString();
+
+ UChar* result = buffer;
+ adapter1.writeTo(result);
+ result += adapter1.length();
+ adapter2.writeTo(result);
+ result += adapter2.length();
+ adapter3.writeTo(result);
+ result += adapter3.length();
+ adapter4.writeTo(result);
+ result += adapter4.length();
+ adapter5.writeTo(result);
+ result += adapter5.length();
+ adapter6.writeTo(result);
+ result += adapter6.length();
+ adapter7.writeTo(result);
+ result += adapter7.length();
+ adapter8.writeTo(result);
+
+ return resultImpl;
}
- struct IdentifierRepHash : PtrHash<RefPtr<JSC::UString::Rep> > {
- static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->computedHash(); }
- static unsigned hash(JSC::UString::Rep* key) { return key->computedHash(); }
- };
-
- void initializeUString();
} // namespace JSC
namespace WTF {
diff --git a/JavaScriptCore/runtime/UStringImpl.cpp b/JavaScriptCore/runtime/UStringImpl.cpp
new file mode 100644
index 0000000..4b0d1c9
--- /dev/null
+++ b/JavaScriptCore/runtime/UStringImpl.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "UStringImpl.h"
+
+#include "Identifier.h"
+#include "UString.h"
+#include <wtf/unicode/UTF8.h>
+
+using namespace WTF::Unicode;
+using namespace std;
+
+namespace JSC {
+
+SharedUChar* UStringImpl::baseSharedBuffer()
+{
+ ASSERT((bufferOwnership() == BufferShared)
+ || ((bufferOwnership() == BufferOwned) && !m_dataBuffer.asPtr<void*>()));
+
+ if (bufferOwnership() != BufferShared)
+ m_dataBuffer = UntypedPtrAndBitfield(SharedUChar::create(new OwnFastMallocPtr<UChar>(m_data)).releaseRef(), BufferShared);
+
+ return m_dataBuffer.asPtr<SharedUChar*>();
+}
+
+SharedUChar* UStringImpl::sharedBuffer()
+{
+ if (m_length < s_minLengthToShare)
+ return 0;
+ ASSERT(!isStatic());
+
+ UStringImpl* owner = bufferOwnerString();
+ if (owner->bufferOwnership() == BufferInternal)
+ return 0;
+
+ return owner->baseSharedBuffer();
+}
+
+UStringImpl::~UStringImpl()
+{
+ ASSERT(!isStatic());
+ checkConsistency();
+
+ if (isIdentifier())
+ Identifier::remove(this);
+
+ if (bufferOwnership() != BufferInternal) {
+ if (bufferOwnership() == BufferOwned)
+ fastFree(m_data);
+ else if (bufferOwnership() == BufferSubstring)
+ m_dataBuffer.asPtr<UStringImpl*>()->deref();
+ else {
+ ASSERT(bufferOwnership() == BufferShared);
+ m_dataBuffer.asPtr<SharedUChar*>()->deref();
+ }
+ }
+}
+
+}
diff --git a/JavaScriptCore/runtime/UStringImpl.h b/JavaScriptCore/runtime/UStringImpl.h
new file mode 100644
index 0000000..abed637
--- /dev/null
+++ b/JavaScriptCore/runtime/UStringImpl.h
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UStringImpl_h
+#define UStringImpl_h
+
+#include <limits>
+#include <wtf/CrossThreadRefCounted.h>
+#include <wtf/OwnFastMallocPtr.h>
+#include <wtf/PossiblyNull.h>
+#include <wtf/StringHashFunctions.h>
+#include <wtf/Vector.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace JSC {
+
+class IdentifierTable;
+
+typedef CrossThreadRefCounted<OwnFastMallocPtr<UChar> > SharedUChar;
+
+class UntypedPtrAndBitfield {
+public:
+ UntypedPtrAndBitfield() {}
+
+ UntypedPtrAndBitfield(void* ptrValue, uintptr_t bitValue)
+ : m_value(reinterpret_cast<uintptr_t>(ptrValue) | bitValue)
+#ifndef NDEBUG
+ , m_leaksPtr(ptrValue)
+#endif
+ {
+ ASSERT(ptrValue == asPtr<void*>());
+ ASSERT((*this & ~s_alignmentMask) == bitValue);
+ }
+
+ template<typename T>
+ T asPtr() const { return reinterpret_cast<T>(m_value & s_alignmentMask); }
+
+ UntypedPtrAndBitfield& operator&=(uintptr_t bits)
+ {
+ m_value &= bits | s_alignmentMask;
+ return *this;
+ }
+
+ UntypedPtrAndBitfield& operator|=(uintptr_t bits)
+ {
+ m_value |= bits & ~s_alignmentMask;
+ return *this;
+ }
+
+ uintptr_t operator&(uintptr_t mask) const
+ {
+ return m_value & mask & ~s_alignmentMask;
+ }
+
+private:
+ static const uintptr_t s_alignmentMask = ~static_cast<uintptr_t>(0x7);
+ uintptr_t m_value;
+#ifndef NDEBUG
+ void* m_leaksPtr; // Only used to allow tools like leaks on OSX to detect that the memory is referenced.
+#endif
+};
+
+class UStringImpl : Noncopyable {
+public:
+ template<size_t inlineCapacity>
+ static PassRefPtr<UStringImpl> adopt(Vector<UChar, inlineCapacity>& vector)
+ {
+ if (unsigned length = vector.size())
+ return adoptRef(new UStringImpl(vector.releaseBuffer(), length, BufferOwned));
+ return &empty();
+ }
+
+ static PassRefPtr<UStringImpl> create(const UChar* buffer, int length)
+ {
+ UChar* newBuffer;
+ if (PassRefPtr<UStringImpl> impl = tryCreateUninitialized(length, newBuffer)) {
+ copyChars(newBuffer, buffer, length);
+ return impl;
+ }
+ return &null();
+ }
+
+ static PassRefPtr<UStringImpl> create(PassRefPtr<UStringImpl> rep, int offset, int length)
+ {
+ ASSERT(rep);
+ rep->checkConsistency();
+ return adoptRef(new UStringImpl(rep->m_data + offset, length, rep->bufferOwnerString()));
+ }
+
+ static PassRefPtr<UStringImpl> create(PassRefPtr<SharedUChar> sharedBuffer, UChar* buffer, int length)
+ {
+ return adoptRef(new UStringImpl(buffer, length, sharedBuffer));
+ }
+
+ static PassRefPtr<UStringImpl> createUninitialized(unsigned length, UChar*& output)
+ {
+ if (!length) {
+ output = 0;
+ return &empty();
+ }
+
+ if (length > ((std::numeric_limits<size_t>::max() - sizeof(UStringImpl)) / sizeof(UChar)))
+ CRASH();
+ UStringImpl* resultImpl = static_cast<UStringImpl*>(fastMalloc(sizeof(UChar) * length + sizeof(UStringImpl)));
+ output = reinterpret_cast<UChar*>(resultImpl + 1);
+ return adoptRef(new(resultImpl) UStringImpl(output, length, BufferInternal));
+ }
+
+ static PassRefPtr<UStringImpl> tryCreateUninitialized(unsigned length, UChar*& output)
+ {
+ if (!length) {
+ output = 0;
+ return &empty();
+ }
+
+ if (length > ((std::numeric_limits<size_t>::max() - sizeof(UStringImpl)) / sizeof(UChar)))
+ return 0;
+ UStringImpl* resultImpl;
+ if (!tryFastMalloc(sizeof(UChar) * length + sizeof(UStringImpl)).getValue(resultImpl))
+ return 0;
+ output = reinterpret_cast<UChar*>(resultImpl + 1);
+ return adoptRef(new(resultImpl) UStringImpl(output, length, BufferInternal));
+ }
+
+ SharedUChar* sharedBuffer();
+ UChar* data() const { return m_data; }
+ int size() const { return m_length; }
+ size_t cost()
+ {
+ // For substrings, return the cost of the base string.
+ if (bufferOwnership() == BufferSubstring)
+ return m_dataBuffer.asPtr<UStringImpl*>()->cost();
+
+ if (m_dataBuffer & s_reportedCostBit)
+ return 0;
+ m_dataBuffer |= s_reportedCostBit;
+ return m_length;
+ }
+ unsigned hash() const { if (!m_hash) m_hash = computeHash(data(), m_length); return m_hash; }
+ unsigned existingHash() const { ASSERT(m_hash); return m_hash; } // fast path for Identifiers
+ void setHash(unsigned hash) { ASSERT(hash == computeHash(data(), m_length)); m_hash = hash; } // fast path for Identifiers
+ bool isIdentifier() const { return m_isIdentifier; }
+ void setIsIdentifier(bool isIdentifier) { m_isIdentifier = isIdentifier; }
+
+ UStringImpl* ref() { m_refCount += s_refCountIncrement; return this; }
+ ALWAYS_INLINE void deref() { if (!(m_refCount -= s_refCountIncrement)) delete this; }
+
+ static void copyChars(UChar* destination, const UChar* source, unsigned numCharacters)
+ {
+ if (numCharacters <= s_copyCharsInlineCutOff) {
+ for (unsigned i = 0; i < numCharacters; ++i)
+ destination[i] = source[i];
+ } else
+ memcpy(destination, source, numCharacters * sizeof(UChar));
+ }
+
+ static unsigned computeHash(const UChar* s, int length) { ASSERT(length >= 0); return WTF::stringHash(s, length); }
+ static unsigned computeHash(const char* s, int length) { ASSERT(length >= 0); return WTF::stringHash(s, length); }
+ static unsigned computeHash(const char* s) { return WTF::stringHash(s); }
+
+ static UStringImpl& null() { return *s_null; }
+ static UStringImpl& empty() { return *s_empty; }
+
+ ALWAYS_INLINE void checkConsistency() const
+ {
+ // There is no recursion of substrings.
+ ASSERT(bufferOwnerString()->bufferOwnership() != BufferSubstring);
+ // Static strings cannot be put in identifier tables, because they are globally shared.
+ ASSERT(!isStatic() || !isIdentifier());
+ }
+
+private:
+ enum BufferOwnership {
+ BufferInternal,
+ BufferOwned,
+ BufferSubstring,
+ BufferShared,
+ };
+
+ // For SmallStringStorage, which allocates an array and uses an in-place new.
+ UStringImpl() { }
+
+ // Used to construct normal strings with an internal or external buffer.
+ UStringImpl(UChar* data, int length, BufferOwnership ownership)
+ : m_data(data)
+ , m_length(length)
+ , m_refCount(s_refCountIncrement)
+ , m_hash(0)
+ , m_isIdentifier(false)
+ , m_dataBuffer(0, ownership)
+ {
+ ASSERT((ownership == BufferInternal) || (ownership == BufferOwned));
+ checkConsistency();
+ }
+
+ // Used to construct static strings, which have an special refCount that can never hit zero.
+ // This means that the static string will never be destroyed, which is important because
+ // static strings will be shared across threads & ref-counted in a non-threadsafe manner.
+ enum StaticStringConstructType { ConstructStaticString };
+ UStringImpl(UChar* data, int length, StaticStringConstructType)
+ : m_data(data)
+ , m_length(length)
+ , m_refCount(s_staticRefCountInitialValue)
+ , m_hash(0)
+ , m_isIdentifier(false)
+ , m_dataBuffer(0, BufferOwned)
+ {
+ checkConsistency();
+ }
+
+ // Used to create new strings that are a substring of an existing string.
+ UStringImpl(UChar* data, int length, PassRefPtr<UStringImpl> base)
+ : m_data(data)
+ , m_length(length)
+ , m_refCount(s_refCountIncrement)
+ , m_hash(0)
+ , m_isIdentifier(false)
+ , m_dataBuffer(base.releaseRef(), BufferSubstring)
+ {
+ // Do use static strings as a base for substrings; UntypedPtrAndBitfield assumes
+ // that all pointers will be at least 8-byte aligned, we cannot guarantee that of
+ // UStringImpls that are not heap allocated.
+ ASSERT(m_dataBuffer.asPtr<UStringImpl*>()->size());
+ ASSERT(!m_dataBuffer.asPtr<UStringImpl*>()->isStatic());
+ checkConsistency();
+ }
+
+ // Used to construct new strings sharing an existing shared buffer.
+ UStringImpl(UChar* data, int length, PassRefPtr<SharedUChar> sharedBuffer)
+ : m_data(data)
+ , m_length(length)
+ , m_refCount(s_refCountIncrement)
+ , m_hash(0)
+ , m_isIdentifier(false)
+ , m_dataBuffer(sharedBuffer.releaseRef(), BufferShared)
+ {
+ checkConsistency();
+ }
+
+ 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_null;
+ JS_EXPORTDATA static UStringImpl* s_empty;
+
+ friend class JIT;
+ friend class SmallStringsStorage;
+ friend void initializeUString();
+};
+
+bool equal(const UStringImpl*, const UStringImpl*);
+
+}
+
+#endif
diff --git a/JavaScriptCore/runtime/WeakGCMap.h b/JavaScriptCore/runtime/WeakGCMap.h
new file mode 100644
index 0000000..39a91c5
--- /dev/null
+++ b/JavaScriptCore/runtime/WeakGCMap.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WeakGCMap_h
+#define WeakGCMap_h
+
+#include "Collector.h"
+#include <wtf/HashMap.h>
+
+namespace JSC {
+
+class JSCell;
+
+// A HashMap whose get() function returns emptyValue() for cells awaiting destruction.
+template<typename KeyType, typename MappedType>
+class WeakGCMap : public FastAllocBase {
+ /*
+ Invariants:
+ * A value enters the WeakGCMap marked. (Guaranteed by set().)
+ * A value that becomes unmarked leaves the WeakGCMap before being recycled. (Guaranteed by the value's destructor removing it from the WeakGCMap.)
+ * A value that becomes unmarked leaves the WeakGCMap before becoming marked again. (Guaranteed by all destructors running before the mark phase begins.)
+ * During the mark phase, all values in the WeakGCMap are valid. (Guaranteed by all destructors running before the mark phase begins.)
+ */
+
+public:
+ typedef typename HashMap<KeyType, MappedType>::iterator iterator;
+ typedef typename HashMap<KeyType, MappedType>::const_iterator const_iterator;
+
+ bool isEmpty() { return m_map.isEmpty(); }
+
+ MappedType get(const KeyType& key) const;
+ pair<iterator, bool> set(const KeyType&, const MappedType&);
+ MappedType take(const KeyType& key);
+
+ // These unchecked functions provide access to a value even if the value's
+ // mark bit is not set. This is used, among other things, to retrieve values
+ // during the GC mark phase, which begins by clearing all mark bits.
+
+ MappedType uncheckedGet(const KeyType& key) const { return m_map.get(key); }
+ bool uncheckedRemove(const KeyType&, const MappedType&);
+
+ iterator uncheckedBegin() { return m_map.begin(); }
+ iterator uncheckedEnd() { return m_map.end(); }
+
+ const_iterator uncheckedBegin() const { return m_map.begin(); }
+ const_iterator uncheckedEnd() const { return m_map.end(); }
+
+private:
+ HashMap<KeyType, MappedType> m_map;
+};
+
+template<typename KeyType, typename MappedType>
+inline MappedType WeakGCMap<KeyType, MappedType>::get(const KeyType& key) const
+{
+ MappedType result = m_map.get(key);
+ if (result == HashTraits<MappedType>::emptyValue())
+ return result;
+ if (!Heap::isCellMarked(result))
+ return HashTraits<MappedType>::emptyValue();
+ return result;
+}
+
+template<typename KeyType, typename MappedType>
+MappedType WeakGCMap<KeyType, MappedType>::take(const KeyType& key)
+{
+ MappedType result = m_map.take(key);
+ if (result == HashTraits<MappedType>::emptyValue())
+ return result;
+ if (!Heap::isCellMarked(result))
+ return HashTraits<MappedType>::emptyValue();
+ return result;
+}
+
+template<typename KeyType, typename MappedType>
+pair<typename HashMap<KeyType, MappedType>::iterator, bool> WeakGCMap<KeyType, MappedType>::set(const KeyType& key, const MappedType& value)
+{
+ Heap::markCell(value); // If value is newly allocated, it's not marked, so mark it now.
+ pair<iterator, bool> result = m_map.add(key, value);
+ if (!result.second) { // pre-existing entry
+ result.second = !Heap::isCellMarked(result.first->second);
+ result.first->second = value;
+ }
+ return result;
+}
+
+template<typename KeyType, typename MappedType>
+bool WeakGCMap<KeyType, MappedType>::uncheckedRemove(const KeyType& key, const MappedType& value)
+{
+ iterator it = m_map.find(key);
+ if (it == m_map.end())
+ return false;
+ if (it->second != value)
+ return false;
+ m_map.remove(it);
+ return true;
+}
+
+} // namespace JSC
+
+#endif // WeakGCMap_h
diff --git a/JavaScriptCore/runtime/WeakGCPtr.h b/JavaScriptCore/runtime/WeakGCPtr.h
new file mode 100644
index 0000000..8653721
--- /dev/null
+++ b/JavaScriptCore/runtime/WeakGCPtr.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WeakGCPtr_h
+#define WeakGCPtr_h
+
+#include "Collector.h"
+#include <wtf/Noncopyable.h>
+
+namespace JSC {
+
+// A smart pointer whose get() function returns 0 for cells awaiting destruction.
+template <typename T> class WeakGCPtr : Noncopyable {
+public:
+ WeakGCPtr() : m_ptr(0) { }
+ WeakGCPtr(T* ptr) { assign(ptr); }
+
+ T* get() const
+ {
+ if (!m_ptr || !Heap::isCellMarked(m_ptr))
+ return 0;
+ return m_ptr;
+ }
+
+ void clear() { m_ptr = 0; }
+
+ T& operator*() const { return *get(); }
+ T* operator->() const { return get(); }
+
+ bool operator!() const { return !get(); }
+
+ // This conversion operator allows implicit conversion to bool but not to other integer types.
+#if COMPILER(WINSCW)
+ operator bool() const { return m_ptr; }
+#else
+ typedef T* WeakGCPtr::*UnspecifiedBoolType;
+ operator UnspecifiedBoolType() const { return get() ? &WeakGCPtr::m_ptr : 0; }
+#endif
+
+ WeakGCPtr& operator=(T*);
+
+private:
+ void assign(T* ptr)
+ {
+ if (ptr)
+ Heap::markCell(ptr);
+ m_ptr = ptr;
+ }
+
+ T* m_ptr;
+};
+
+template <typename T> inline WeakGCPtr<T>& WeakGCPtr<T>::operator=(T* optr)
+{
+ assign(optr);
+ return *this;
+}
+
+template <typename T, typename U> inline bool operator==(const WeakGCPtr<T>& a, const WeakGCPtr<U>& b)
+{
+ return a.get() == b.get();
+}
+
+template <typename T, typename U> inline bool operator==(const WeakGCPtr<T>& a, U* b)
+{
+ return a.get() == b;
+}
+
+template <typename T, typename U> inline bool operator==(T* a, const WeakGCPtr<U>& b)
+{
+ return a == b.get();
+}
+
+template <typename T, typename U> inline bool operator!=(const WeakGCPtr<T>& a, const WeakGCPtr<U>& b)
+{
+ return a.get() != b.get();
+}
+
+template <typename T, typename U> inline bool operator!=(const WeakGCPtr<T>& a, U* b)
+{
+ return a.get() != b;
+}
+
+template <typename T, typename U> inline bool operator!=(T* a, const WeakGCPtr<U>& b)
+{
+ return a != b.get();
+}
+
+template <typename T, typename U> inline WeakGCPtr<T> static_pointer_cast(const WeakGCPtr<U>& p)
+{
+ return WeakGCPtr<T>(static_cast<T*>(p.get()));
+}
+
+template <typename T, typename U> inline WeakGCPtr<T> const_pointer_cast(const WeakGCPtr<U>& p)
+{
+ return WeakGCPtr<T>(const_cast<T*>(p.get()));
+}
+
+template <typename T> inline T* getPtr(const WeakGCPtr<T>& p)
+{
+ return p.get();
+}
+
+} // namespace JSC
+
+#endif // WeakGCPtr_h