summaryrefslogtreecommitdiffstats
path: root/Source/JavaScriptCore/runtime
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-05-13 16:23:25 +0100
committerBen Murdoch <benm@google.com>2011-05-16 11:35:02 +0100
commit65f03d4f644ce73618e5f4f50dd694b26f55ae12 (patch)
treef478babb801e720de7bfaee23443ffe029f58731 /Source/JavaScriptCore/runtime
parent47de4a2fb7262c7ebdb9cd133ad2c54c187454d0 (diff)
downloadexternal_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.zip
external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.tar.gz
external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.tar.bz2
Merge WebKit at r75993: Initial merge by git.
Change-Id: I602bbdc3974787a3b0450456a30a7868286921c3
Diffstat (limited to 'Source/JavaScriptCore/runtime')
-rw-r--r--Source/JavaScriptCore/runtime/Collector.cpp1100
-rw-r--r--Source/JavaScriptCore/runtime/CollectorHeapIterator.h2
-rw-r--r--Source/JavaScriptCore/runtime/ExceptionHelpers.cpp9
-rw-r--r--Source/JavaScriptCore/runtime/ExceptionHelpers.h1
-rw-r--r--Source/JavaScriptCore/runtime/Executable.cpp28
-rw-r--r--Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/Heap.cpp434
-rw-r--r--Source/JavaScriptCore/runtime/Heap.h165
-rw-r--r--Source/JavaScriptCore/runtime/InitializeThreading.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/JSCell.h5
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalData.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalData.h7
-rw-r--r--Source/JavaScriptCore/runtime/JSLock.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/JSNumberCell.h2
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.cpp35
-rw-r--r--Source/JavaScriptCore/runtime/JSString.h17
-rw-r--r--Source/JavaScriptCore/runtime/JSValue.h3
-rw-r--r--Source/JavaScriptCore/runtime/MachineStackMarker.cpp403
-rw-r--r--Source/JavaScriptCore/runtime/MachineStackMarker.h73
-rw-r--r--Source/JavaScriptCore/runtime/MarkedSpace.cpp367
-rw-r--r--Source/JavaScriptCore/runtime/MarkedSpace.h (renamed from Source/JavaScriptCore/runtime/Collector.h)167
-rw-r--r--Source/JavaScriptCore/runtime/MemoryStatistics.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/MemoryStatistics.h4
-rw-r--r--Source/JavaScriptCore/runtime/Protect.h2
-rw-r--r--Source/JavaScriptCore/runtime/RegExp.cpp22
-rw-r--r--Source/JavaScriptCore/runtime/RegExpConstructor.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/RegExpPrototype.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/UString.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/WeakGCMap.h2
-rw-r--r--Source/JavaScriptCore/runtime/WeakGCPtr.h2
31 files changed, 1574 insertions, 1296 deletions
diff --git a/Source/JavaScriptCore/runtime/Collector.cpp b/Source/JavaScriptCore/runtime/Collector.cpp
deleted file mode 100644
index 38845ce..0000000
--- a/Source/JavaScriptCore/runtime/Collector.cpp
+++ /dev/null
@@ -1,1100 +0,0 @@
-/*
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#include "config.h"
-#include "Collector.h"
-
-#include "ArgList.h"
-#include "CallFrame.h"
-#include "CodeBlock.h"
-#include "CollectorHeapIterator.h"
-#include "GCActivityCallback.h"
-#include "Interpreter.h"
-#include "JSArray.h"
-#include "JSGlobalObject.h"
-#include "JSLock.h"
-#include "JSONObject.h"
-#include "JSString.h"
-#include "JSValue.h"
-#include "JSZombie.h"
-#include "MarkStack.h"
-#include "Nodes.h"
-#include "Tracing.h"
-#include <algorithm>
-#include <limits.h>
-#include <setjmp.h>
-#include <stdlib.h>
-#include <wtf/FastMalloc.h>
-#include <wtf/HashCountedSet.h>
-#include <wtf/WTFThreadData.h>
-#include <wtf/UnusedParam.h>
-#include <wtf/VMTags.h>
-
-#if OS(DARWIN)
-
-#include <mach/mach_init.h>
-#include <mach/mach_port.h>
-#include <mach/task.h>
-#include <mach/thread_act.h>
-#include <mach/vm_map.h>
-
-#elif OS(WINDOWS)
-
-#include <windows.h>
-#include <malloc.h>
-
-#elif OS(HAIKU)
-
-#include <OS.h>
-
-#elif OS(UNIX)
-
-#include <stdlib.h>
-#if !OS(HAIKU)
-#include <sys/mman.h>
-#endif
-#include <unistd.h>
-
-#if OS(SOLARIS)
-#include <thread.h>
-#else
-#include <pthread.h>
-#endif
-
-#if HAVE(PTHREAD_NP_H)
-#include <pthread_np.h>
-#endif
-
-#if OS(QNX)
-#include <fcntl.h>
-#include <sys/procfs.h>
-#include <stdio.h>
-#include <errno.h>
-#endif
-
-#endif
-
-#define COLLECT_ON_EVERY_ALLOCATION 0
-
-using std::max;
-
-namespace JSC {
-
-// tunable parameters
-
-const size_t GROWTH_FACTOR = 2;
-const size_t LOW_WATER_FACTOR = 4;
-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 ENABLE(JSC_MULTIPLE_THREADS)
-
-#if OS(DARWIN)
-typedef mach_port_t PlatformThread;
-#elif OS(WINDOWS)
-typedef HANDLE PlatformThread;
-#endif
-
-class Heap::Thread {
-public:
- Thread(pthread_t pthread, const PlatformThread& platThread, void* base)
- : posixThread(pthread)
- , platformThread(platThread)
- , stackBase(base)
- {
- }
-
- Thread* next;
- pthread_t posixThread;
- PlatformThread platformThread;
- void* stackBase;
-};
-
-#endif
-
-Heap::Heap(JSGlobalData* globalData)
- : m_markListSet(0)
-#if ENABLE(JSC_MULTIPLE_THREADS)
- , m_registeredThreads(0)
- , m_currentThreadRegistrar(0)
-#endif
- , m_globalData(globalData)
-{
- ASSERT(globalData);
- memset(&m_heap, 0, sizeof(CollectorHeap));
- allocateBlock();
- m_activityCallback = DefaultGCActivityCallback::create(this);
- (*m_activityCallback)();
-}
-
-Heap::~Heap()
-{
- // The destroy function must already have been called, so assert this.
- ASSERT(!m_globalData);
-}
-
-void Heap::destroy()
-{
- JSLock lock(SilenceAssertionsOnly);
-
- 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);
-
- delete m_markListSet;
- m_markListSet = 0;
-
- freeBlocks();
-
-#if ENABLE(JSC_MULTIPLE_THREADS)
- if (m_currentThreadRegistrar) {
- int error = pthread_key_delete(m_currentThreadRegistrar);
- ASSERT_UNUSED(error, !error);
- }
-
- MutexLocker registeredThreadsLock(m_registeredThreadsMutex);
- for (Heap::Thread* t = m_registeredThreads; t;) {
- Heap::Thread* next = t->next;
- delete t;
- t = next;
- }
-#endif
- m_globalData = 0;
-}
-
-NEVER_INLINE CollectorBlock* Heap::allocateBlock()
-{
- PageAllocationAligned allocation = PageAllocationAligned::allocate(BLOCK_SIZE, BLOCK_SIZE, OSAllocator::JSGCHeapPages);
- CollectorBlock* block = static_cast<CollectorBlock*>(allocation.base());
- if (!block)
- CRASH();
-
- // Initialize block.
-
- block->heap = this;
- clearMarkBits(block);
-
- 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(PageAllocationAligned) / GROWTH_FACTOR;
- if (numBlocks > maxNumBlocks)
- CRASH();
- numBlocks = max(MIN_ARRAY_SIZE, numBlocks * GROWTH_FACTOR);
- m_heap.numBlocks = numBlocks;
- m_heap.blocks = static_cast<PageAllocationAligned*>(fastRealloc(m_heap.blocks, numBlocks * sizeof(PageAllocationAligned)));
- }
- m_heap.blocks[m_heap.usedBlocks++] = allocation;
-
- return block;
-}
-
-NEVER_INLINE void Heap::freeBlock(size_t block)
-{
- m_heap.didShrink = true;
-
- ObjectIterator it(m_heap, block);
- ObjectIterator end(m_heap, block + 1);
- for ( ; it != end; ++it)
- (*it)->~JSCell();
- m_heap.blocks[block].deallocate();
-
- // swap with the last block so we compact as we go
- m_heap.blocks[block] = m_heap.blocks[m_heap.usedBlocks - 1];
- m_heap.usedBlocks--;
-
- 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<PageAllocationAligned*>(fastRealloc(m_heap.blocks, m_heap.numBlocks * sizeof(PageAllocationAligned)));
- }
-}
-
-void Heap::freeBlocks()
-{
- 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)
- m_heap.blocks[block].deallocate();
-
- fastFree(m_heap.blocks);
-
- memset(&m_heap, 0, sizeof(CollectorHeap));
-}
-
-void Heap::recordExtraCost(size_t cost)
-{
- // Our frequency of garbage collection tries to balance memory use against speed
- // by collecting based on the number of newly created values. However, for values
- // that hold on to a great deal of memory that's not in the form of other JS values,
- // that is not good enough - in some cases a lot of those objects can pile up and
- // use crazy amounts of memory without a GC happening. So we track these extra
- // memory costs. Only unusually large objects are noted, and we only keep track
- // of this extra cost until the next GC. In garbage collected languages, most values
- // 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.
-
- 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;
-}
-
-void* Heap::allocate(size_t s)
-{
- ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable());
- typedef HeapConstants::Block Block;
- typedef HeapConstants::Cell Cell;
-
- ASSERT(JSLock::lockCount() > 0);
- ASSERT(JSLock::currentThreadIsHoldingLock());
- ASSERT_UNUSED(s, s <= HeapConstants::cellSize);
-
- ASSERT(m_heap.operationInProgress == NoOperation);
-
-#if COLLECT_ON_EVERY_ALLOCATION
- collectAllGarbage();
- ASSERT(m_heap.operationInProgress == NoOperation);
-#endif
-
-allocate:
-
- // Fast case: find the next garbage cell and recycle it.
-
- do {
- ASSERT(m_heap.nextBlock < m_heap.usedBlocks);
- Block* block = m_heap.collectorBlock(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];
-
- m_heap.operationInProgress = Allocation;
- JSCell* imp = reinterpret_cast<JSCell*>(cell);
- imp->~JSCell();
- m_heap.operationInProgress = NoOperation;
-
- ++m_heap.nextCell;
- return cell;
- }
- block->marked.advanceToNextPossibleFreeCell(m_heap.nextCell);
- } while (m_heap.nextCell != HeapConstants::cellsPerBlock);
- m_heap.nextCell = 0;
- } while (++m_heap.nextBlock != m_heap.usedBlocks);
-
- // Slow case: reached the end of the heap. Mark live objects and start over.
-
- reset();
- goto allocate;
-}
-
-void Heap::resizeBlocks()
-{
- m_heap.didShrink = false;
-
- size_t usedCellCount = markedCells();
- size_t minCellCount = usedCellCount + max(ALLOCATIONS_PER_COLLECTION, usedCellCount);
- size_t minBlockCount = (minCellCount + HeapConstants::cellsPerBlock - 1) / HeapConstants::cellsPerBlock;
-
- size_t maxCellCount = 1.25f * minCellCount;
- size_t maxBlockCount = (maxCellCount + HeapConstants::cellsPerBlock - 1) / HeapConstants::cellsPerBlock;
-
- if (m_heap.usedBlocks < minBlockCount)
- growBlocks(minBlockCount);
- else if (m_heap.usedBlocks > maxBlockCount)
- shrinkBlocks(maxBlockCount);
-}
-
-void Heap::growBlocks(size_t neededBlocks)
-{
- ASSERT(m_heap.usedBlocks < neededBlocks);
- while (m_heap.usedBlocks < neededBlocks)
- allocateBlock();
-}
-
-void Heap::shrinkBlocks(size_t neededBlocks)
-{
- 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.collectorBlock(i)->marked.clear(HeapConstants::cellsPerBlock - 1);
-
- for (size_t i = 0; i != m_heap.usedBlocks && m_heap.usedBlocks != neededBlocks; ) {
- if (m_heap.collectorBlock(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.collectorBlock(i)->marked.set(HeapConstants::cellsPerBlock - 1);
-}
-
-#if ENABLE(JSC_MULTIPLE_THREADS)
-
-static inline PlatformThread getCurrentPlatformThread()
-{
-#if OS(DARWIN)
- return pthread_mach_thread_np(pthread_self());
-#elif OS(WINDOWS)
- return pthread_getw32threadhandle_np(pthread_self());
-#endif
-}
-
-void Heap::makeUsableFromMultipleThreads()
-{
- if (m_currentThreadRegistrar)
- return;
-
- int error = pthread_key_create(&m_currentThreadRegistrar, unregisterThread);
- if (error)
- CRASH();
-}
-
-void Heap::registerThread()
-{
- ASSERT(!m_globalData->exclusiveThread || m_globalData->exclusiveThread == currentThread());
-
- if (!m_currentThreadRegistrar || pthread_getspecific(m_currentThreadRegistrar))
- return;
-
- pthread_setspecific(m_currentThreadRegistrar, this);
- Heap::Thread* thread = new Heap::Thread(pthread_self(), getCurrentPlatformThread(), m_globalData->stack().origin());
-
- MutexLocker lock(m_registeredThreadsMutex);
-
- thread->next = m_registeredThreads;
- m_registeredThreads = thread;
-}
-
-void Heap::unregisterThread(void* p)
-{
- if (p)
- static_cast<Heap*>(p)->unregisterThread();
-}
-
-void Heap::unregisterThread()
-{
- pthread_t currentPosixThread = pthread_self();
-
- MutexLocker lock(m_registeredThreadsMutex);
-
- if (pthread_equal(currentPosixThread, m_registeredThreads->posixThread)) {
- Thread* t = m_registeredThreads;
- m_registeredThreads = m_registeredThreads->next;
- delete t;
- } else {
- Heap::Thread* last = m_registeredThreads;
- Heap::Thread* t;
- for (t = m_registeredThreads->next; t; t = t->next) {
- if (pthread_equal(t->posixThread, currentPosixThread)) {
- last->next = t->next;
- break;
- }
- last = t;
- }
- ASSERT(t); // If t is NULL, we never found ourselves in the list.
- delete t;
- }
-}
-
-#else // ENABLE(JSC_MULTIPLE_THREADS)
-
-void Heap::registerThread()
-{
-}
-
-#endif
-
-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);
-
-static inline bool isCellAligned(void *p)
-{
- return (((intptr_t)(p) & CELL_MASK) == 0);
-}
-
-static inline bool isPossibleCell(void* p)
-{
- return isCellAligned(p) && p;
-}
-
-void Heap::markConservatively(MarkStack& markStack, void* start, void* end)
-{
-#if OS(WINCE)
- if (start > end) {
- void* tmp = start;
- start = end;
- end = tmp;
- }
-#else
- ASSERT(start <= end);
-#endif
-
- ASSERT((static_cast<char*>(end) - static_cast<char*>(start)) < 0x1000000);
- ASSERT(isPointerAligned(start));
- ASSERT(isPointerAligned(end));
-
- char** p = static_cast<char**>(start);
- char** e = static_cast<char**>(end);
-
- while (p != e) {
- char* x = *p++;
- 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);
- usedBlocks = m_heap.usedBlocks;
- for (size_t block = 0; block < usedBlocks; block++) {
- if (m_heap.collectorBlock(block) != blockAddr)
- continue;
- markStack.append(reinterpret_cast<JSCell*>(xAsBits));
- }
- }
- }
-}
-
-void NEVER_INLINE Heap::markCurrentThreadConservativelyInternal(MarkStack& markStack)
-{
- markConservatively(markStack, m_globalData->stack().current(), m_globalData->stack().origin());
- markStack.drain();
-}
-
-#if COMPILER(GCC)
-#define REGISTER_BUFFER_ALIGNMENT __attribute__ ((aligned (sizeof(void*))))
-#else
-#define REGISTER_BUFFER_ALIGNMENT
-#endif
-
-void Heap::markCurrentThreadConservatively(MarkStack& markStack)
-{
- // setjmp forces volatile registers onto the stack
- jmp_buf registers REGISTER_BUFFER_ALIGNMENT;
-#if COMPILER(MSVC)
-#pragma warning(push)
-#pragma warning(disable: 4611)
-#endif
- setjmp(registers);
-#if COMPILER(MSVC)
-#pragma warning(pop)
-#endif
-
- markCurrentThreadConservativelyInternal(markStack);
-}
-
-#if ENABLE(JSC_MULTIPLE_THREADS)
-
-static inline void suspendThread(const PlatformThread& platformThread)
-{
-#if OS(DARWIN)
- thread_suspend(platformThread);
-#elif OS(WINDOWS)
- SuspendThread(platformThread);
-#else
-#error Need a way to suspend threads on this platform
-#endif
-}
-
-static inline void resumeThread(const PlatformThread& platformThread)
-{
-#if OS(DARWIN)
- thread_resume(platformThread);
-#elif OS(WINDOWS)
- ResumeThread(platformThread);
-#else
-#error Need a way to resume threads on this platform
-#endif
-}
-
-typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit
-
-#if OS(DARWIN)
-
-#if CPU(X86)
-typedef i386_thread_state_t PlatformThreadRegisters;
-#elif CPU(X86_64)
-typedef x86_thread_state64_t PlatformThreadRegisters;
-#elif CPU(PPC)
-typedef ppc_thread_state_t PlatformThreadRegisters;
-#elif CPU(PPC64)
-typedef ppc_thread_state64_t PlatformThreadRegisters;
-#elif CPU(ARM)
-typedef arm_thread_state_t PlatformThreadRegisters;
-#else
-#error Unknown Architecture
-#endif
-
-#elif OS(WINDOWS) && CPU(X86)
-typedef CONTEXT PlatformThreadRegisters;
-#else
-#error Need a thread register struct for this platform
-#endif
-
-static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, PlatformThreadRegisters& regs)
-{
-#if OS(DARWIN)
-
-#if CPU(X86)
- unsigned user_count = sizeof(regs)/sizeof(int);
- thread_state_flavor_t flavor = i386_THREAD_STATE;
-#elif CPU(X86_64)
- unsigned user_count = x86_THREAD_STATE64_COUNT;
- thread_state_flavor_t flavor = x86_THREAD_STATE64;
-#elif CPU(PPC)
- unsigned user_count = PPC_THREAD_STATE_COUNT;
- thread_state_flavor_t flavor = PPC_THREAD_STATE;
-#elif CPU(PPC64)
- unsigned user_count = PPC_THREAD_STATE64_COUNT;
- thread_state_flavor_t flavor = PPC_THREAD_STATE64;
-#elif CPU(ARM)
- unsigned user_count = ARM_THREAD_STATE_COUNT;
- thread_state_flavor_t flavor = ARM_THREAD_STATE;
-#else
-#error Unknown Architecture
-#endif
-
- kern_return_t result = thread_get_state(platformThread, flavor, (thread_state_t)&regs, &user_count);
- if (result != KERN_SUCCESS) {
- WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION,
- "JavaScript garbage collection failed because thread_get_state returned an error (%d). This is probably the result of running inside Rosetta, which is not supported.", result);
- CRASH();
- }
- return user_count * sizeof(usword_t);
-// end OS(DARWIN)
-
-#elif OS(WINDOWS) && CPU(X86)
- regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS;
- GetThreadContext(platformThread, &regs);
- return sizeof(CONTEXT);
-#else
-#error Need a way to get thread registers on this platform
-#endif
-}
-
-static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs)
-{
-#if OS(DARWIN)
-
-#if __DARWIN_UNIX03
-
-#if CPU(X86)
- return reinterpret_cast<void*>(regs.__esp);
-#elif CPU(X86_64)
- return reinterpret_cast<void*>(regs.__rsp);
-#elif CPU(PPC) || CPU(PPC64)
- return reinterpret_cast<void*>(regs.__r1);
-#elif CPU(ARM)
- return reinterpret_cast<void*>(regs.__sp);
-#else
-#error Unknown Architecture
-#endif
-
-#else // !__DARWIN_UNIX03
-
-#if CPU(X86)
- return reinterpret_cast<void*>(regs.esp);
-#elif CPU(X86_64)
- return reinterpret_cast<void*>(regs.rsp);
-#elif CPU(PPC) || CPU(PPC64)
- return reinterpret_cast<void*>(regs.r1);
-#else
-#error Unknown Architecture
-#endif
-
-#endif // __DARWIN_UNIX03
-
-// 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
-#endif
-}
-
-void Heap::markOtherThreadConservatively(MarkStack& markStack, Thread* thread)
-{
- suspendThread(thread->platformThread);
-
- PlatformThreadRegisters regs;
- size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs);
-
- // mark the thread's registers
- markConservatively(markStack, static_cast<void*>(&regs), static_cast<void*>(reinterpret_cast<char*>(&regs) + regSize));
- markStack.drain();
-
- void* stackPointer = otherThreadStackPointer(regs);
- markConservatively(markStack, stackPointer, thread->stackBase);
- markStack.drain();
-
- resumeThread(thread->platformThread);
-}
-
-#endif
-
-void Heap::markStackObjectsConservatively(MarkStack& markStack)
-{
- markCurrentThreadConservatively(markStack);
-
-#if ENABLE(JSC_MULTIPLE_THREADS)
-
- if (m_currentThreadRegistrar) {
-
- MutexLocker lock(m_registeredThreadsMutex);
-
-#ifndef NDEBUG
- // Forbid malloc during the mark phase. Marking a thread suspends it, so
- // a malloc inside markChildren() would risk a deadlock with a thread that had been
- // suspended while holding the malloc lock.
- fastMallocForbid();
-#endif
- // It is safe to access the registeredThreads list, because we earlier asserted that locks are being held,
- // and since this is a shared heap, they are real locks.
- for (Thread* thread = m_registeredThreads; thread; thread = thread->next) {
- if (!pthread_equal(thread->posixThread, pthread_self()))
- markOtherThreadConservatively(markStack, thread);
- }
-#ifndef NDEBUG
- fastMallocAllow();
-#endif
- }
-#endif
-}
-
-void Heap::updateWeakGCHandles()
-{
- for (unsigned i = 0; i < m_weakGCHandlePools.size(); ++i)
- weakGCHandlePool(i)->update();
-}
-
-void WeakGCHandlePool::update()
-{
- for (unsigned i = 1; i < WeakGCHandlePool::numPoolEntries; ++i) {
- if (m_entries[i].isValidPtr()) {
- JSCell* cell = m_entries[i].get();
- if (!cell || !Heap::isCellMarked(cell))
- m_entries[i].invalidate();
- }
- }
-}
-
-WeakGCHandle* Heap::addWeakGCHandle(JSCell* ptr)
-{
- for (unsigned i = 0; i < m_weakGCHandlePools.size(); ++i)
- if (!weakGCHandlePool(i)->isFull())
- return weakGCHandlePool(i)->allocate(ptr);
-
- PageAllocationAligned allocation = PageAllocationAligned::allocate(WeakGCHandlePool::poolSize, WeakGCHandlePool::poolSize, OSAllocator::JSGCHeapPages);
- m_weakGCHandlePools.append(allocation);
-
- WeakGCHandlePool* pool = new (allocation.base()) WeakGCHandlePool();
- return pool->allocate(ptr);
-}
-
-void Heap::protect(JSValue k)
-{
- ASSERT(k);
- ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance());
-
- if (!k.isCell())
- return;
-
- m_protectedValues.add(k.asCell());
-}
-
-bool Heap::unprotect(JSValue k)
-{
- ASSERT(k);
- ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance());
-
- if (!k.isCell())
- return false;
-
- return m_protectedValues.remove(k.asCell());
-}
-
-void Heap::markProtectedObjects(MarkStack& markStack)
-{
- ProtectCountSet::iterator end = m_protectedValues.end();
- for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) {
- markStack.append(it->first);
- markStack.drain();
- }
-}
-
-void Heap::pushTempSortVector(Vector<ValueStringPair>* tempVector)
-{
- m_tempSortingVectors.append(tempVector);
-}
-
-void Heap::popTempSortVector(Vector<ValueStringPair>* tempVector)
-{
- ASSERT_UNUSED(tempVector, tempVector == m_tempSortingVectors.last());
- m_tempSortingVectors.removeLast();
-}
-
-void Heap::markTempSortVectors(MarkStack& markStack)
-{
- typedef Vector<Vector<ValueStringPair>* > VectorOfValueStringVectors;
-
- VectorOfValueStringVectors::iterator end = m_tempSortingVectors.end();
- for (VectorOfValueStringVectors::iterator it = m_tempSortingVectors.begin(); it != end; ++it) {
- Vector<ValueStringPair>* tempSortingVector = *it;
-
- Vector<ValueStringPair>::iterator vectorEnd = tempSortingVector->end();
- for (Vector<ValueStringPair>::iterator vectorIt = tempSortingVector->begin(); vectorIt != vectorEnd; ++vectorIt)
- if (vectorIt->first)
- markStack.append(vectorIt->first);
- markStack.drain();
- }
-}
-
-void Heap::clearMarkBits()
-{
- for (size_t i = 0; i < m_heap.usedBlocks; ++i)
- clearMarkBits(m_heap.collectorBlock(i));
-}
-
-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.collectorBlock(startBlock)->marked.count(startCell);
- for (size_t i = startBlock + 1; i < m_heap.usedBlocks; ++i)
- result += m_heap.collectorBlock(i)->marked.count();
-
- return result;
-}
-
-void Heap::sweep()
-{
- ASSERT(m_heap.operationInProgress == NoOperation);
- if (m_heap.operationInProgress != NoOperation)
- CRASH();
- m_heap.operationInProgress = Collection;
-
-#if !ENABLE(JSC_ZOMBIES)
- Structure* dummyMarkableCellStructure = m_globalData->dummyMarkableCellStructure.get();
-#endif
-
- DeadObjectIterator it(m_heap, m_heap.nextBlock, m_heap.nextCell);
- DeadObjectIterator end(m_heap, m_heap.usedBlocks);
- for ( ; it != end; ++it) {
- JSCell* cell = *it;
-#if ENABLE(JSC_ZOMBIES)
- if (!cell->isZombie()) {
- const ClassInfo* info = cell->classInfo();
- cell->~JSCell();
- new (cell) JSZombie(info, JSZombie::leakedZombieStructure());
- Heap::markCell(cell);
- }
-#else
- cell->~JSCell();
- // Callers of sweep assume it's safe to mark any cell in the heap.
- new (cell) JSCell(dummyMarkableCellStructure);
-#endif
- }
-
- m_heap.operationInProgress = NoOperation;
-}
-
-void Heap::markRoots()
-{
-#ifndef NDEBUG
- if (m_globalData->isSharedInstance()) {
- ASSERT(JSLock::lockCount() > 0);
- ASSERT(JSLock::currentThreadIsHoldingLock());
- }
-#endif
-
- ASSERT(m_heap.operationInProgress == NoOperation);
- if (m_heap.operationInProgress != NoOperation)
- CRASH();
-
- m_heap.operationInProgress = Collection;
-
- 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 temporary vector for Array sorting
- markTempSortVectors(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);
- if (m_globalData->firstStringifierToMark)
- JSONObject::markStringifiers(markStack, m_globalData->firstStringifierToMark);
-
- // Mark the small strings cache last, since it will clear itself if nothing
- // else has marked it.
- m_globalData->smallStrings.markChildren(markStack);
-
- markStack.drain();
- markStack.compact();
-
- updateWeakGCHandles();
-
- m_heap.operationInProgress = NoOperation;
-}
-
-size_t Heap::objectCount() const
-{
- 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
-}
-
-void Heap::addToStatistics(Heap::Statistics& statistics) const
-{
- 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 };
- addToStatistics(statistics);
- return statistics;
-}
-
-size_t Heap::size() const
-{
- return m_heap.usedBlocks * BLOCK_SIZE;
-}
-
-size_t Heap::globalObjectCount()
-{
- size_t count = 0;
- if (JSGlobalObject* head = m_globalData->head) {
- JSGlobalObject* o = head;
- do {
- ++count;
- o = o->next();
- } while (o != head);
- }
- return count;
-}
-
-size_t Heap::protectedGlobalObjectCount()
-{
- size_t count = 0;
- if (JSGlobalObject* head = m_globalData->head) {
- JSGlobalObject* o = head;
- do {
- if (m_protectedValues.contains(o))
- ++count;
- o = o->next();
- } while (o != head);
- }
-
- return count;
-}
-
-size_t Heap::protectedObjectCount()
-{
- return m_protectedValues.size();
-}
-
-static const char* typeName(JSCell* cell)
-{
- if (cell->isString())
- return "string";
- if (cell->isGetterSetter())
- return "Getter-Setter";
- if (cell->isAPIValueWrapper())
- return "API wrapper";
- if (cell->isPropertyNameIterator())
- return "For-in iterator";
- if (!cell->isObject())
- return "[empty cell]";
- const ClassInfo* info = cell->classInfo();
- return info ? info->className : "Object";
-}
-
-HashCountedSet<const char*>* Heap::protectedObjectTypeCounts()
-{
- HashCountedSet<const char*>* counts = new HashCountedSet<const char*>;
-
- ProtectCountSet::iterator end = m_protectedValues.end();
- for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
- counts->add(typeName(it->first));
-
- return counts;
-}
-
-HashCountedSet<const char*>* Heap::objectTypeCounts()
-{
- HashCountedSet<const char*>* counts = new HashCountedSet<const char*>;
-
- LiveObjectIterator it = primaryHeapBegin();
- LiveObjectIterator heapEnd = primaryHeapEnd();
- for ( ; it != heapEnd; ++it)
- counts->add(typeName(*it));
-
- return counts;
-}
-
-bool Heap::isBusy()
-{
- return m_heap.operationInProgress != NoOperation;
-}
-
-void Heap::reset()
-{
- ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable());
- 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();
-
- (*m_activityCallback)();
-}
-
-void Heap::collectAllGarbage()
-{
- ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable());
- 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();
-}
-
-LiveObjectIterator Heap::primaryHeapBegin()
-{
- return LiveObjectIterator(m_heap, 0);
-}
-
-LiveObjectIterator Heap::primaryHeapEnd()
-{
- return LiveObjectIterator(m_heap, m_heap.usedBlocks);
-}
-
-void Heap::setActivityCallback(PassOwnPtr<GCActivityCallback> activityCallback)
-{
- m_activityCallback = activityCallback;
-}
-
-GCActivityCallback* Heap::activityCallback()
-{
- return m_activityCallback.get();
-}
-
-} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/CollectorHeapIterator.h b/Source/JavaScriptCore/runtime/CollectorHeapIterator.h
index 9d107b7..7229d77 100644
--- a/Source/JavaScriptCore/runtime/CollectorHeapIterator.h
+++ b/Source/JavaScriptCore/runtime/CollectorHeapIterator.h
@@ -24,7 +24,7 @@
*/
#include "config.h"
-#include "Collector.h"
+#include "Heap.h"
#ifndef CollectorHeapIterator_h
#define CollectorHeapIterator_h
diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
index 1ef264c..4a58800 100644
--- a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
+++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
@@ -130,11 +130,16 @@ JSObject* createNotAnObjectError(ExecState* exec, JSValue value)
JSObject* createErrorForInvalidGlobalAssignment(ExecState* exec, const UString& propertyName)
{
return createReferenceError(exec, makeUString("Strict mode forbids implicit creation of global property '", propertyName, "'"));
-}
+}
+
+JSObject* createOutOfMemoryError(JSGlobalObject* globalObject)
+{
+ return createError(globalObject, "Out of memory");
+}
JSObject* throwOutOfMemoryError(ExecState* exec)
{
- return throwError(exec, createError(exec, "Out of memory"));
+ return throwError(exec, createOutOfMemoryError(exec->lexicalGlobalObject()));
}
JSObject* throwStackOverflowError(ExecState* exec)
diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.h b/Source/JavaScriptCore/runtime/ExceptionHelpers.h
index 7edffad..5f1ec6f 100644
--- a/Source/JavaScriptCore/runtime/ExceptionHelpers.h
+++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.h
@@ -47,6 +47,7 @@ namespace JSC {
JSObject* createTerminatedExecutionException(JSGlobalData*);
JSObject* createStackOverflowError(ExecState*);
JSObject* createStackOverflowError(JSGlobalObject*);
+ JSObject* createOutOfMemoryError(JSGlobalObject*);
JSObject* createUndefinedVariableError(ExecState*, const Identifier&);
JSObject* createNotAnObjectError(ExecState*, JSValue);
JSObject* createInvalidParamError(ExecState*, const char* op, JSValue);
diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp
index c7262be..25c551b 100644
--- a/Source/JavaScriptCore/runtime/Executable.cpp
+++ b/Source/JavaScriptCore/runtime/Executable.cpp
@@ -109,8 +109,12 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scope
ASSERT(!m_evalCodeBlock);
m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth()));
OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(evalNode.get(), scopeChain, m_evalCodeBlock->symbolTable(), m_evalCodeBlock.get())));
- generator->generate();
-
+ if ((exception = generator->generate())) {
+ m_evalCodeBlock.clear();
+ evalNode->destroyData();
+ return exception;
+ }
+
evalNode->destroyData();
#if ENABLE(JIT)
@@ -157,7 +161,11 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* sc
m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider()));
OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(programNode.get(), scopeChain, &globalObject->symbolTable(), m_programCodeBlock.get())));
- generator->generate();
+ if ((exception = generator->generate())) {
+ m_programCodeBlock.clear();
+ programNode->destroyData();
+ return exception;
+ }
programNode->destroyData();
@@ -194,7 +202,12 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain
ASSERT(!m_codeBlockForCall);
m_codeBlockForCall = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), false));
OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChain, m_codeBlockForCall->symbolTable(), m_codeBlockForCall.get())));
- generator->generate();
+ if ((exception = generator->generate())) {
+ m_codeBlockForCall.clear();
+ body->destroyData();
+ return exception;
+ }
+
m_numParametersForCall = m_codeBlockForCall->m_numParameters;
ASSERT(m_numParametersForCall);
m_numCapturedVariables = m_codeBlockForCall->m_numCapturedVars;
@@ -235,7 +248,12 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, Scope
ASSERT(!m_codeBlockForConstruct);
m_codeBlockForConstruct = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), true));
OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChain, m_codeBlockForConstruct->symbolTable(), m_codeBlockForConstruct.get())));
- generator->generate();
+ if ((exception = generator->generate())) {
+ m_codeBlockForConstruct.clear();
+ body->destroyData();
+ return exception;
+ }
+
m_numParametersForConstruct = m_codeBlockForConstruct->m_numParameters;
ASSERT(m_numParametersForConstruct);
m_numCapturedVariables = m_codeBlockForConstruct->m_numCapturedVars;
diff --git a/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp b/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp
index 7168a05..414a0ad 100644
--- a/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp
+++ b/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp
@@ -30,7 +30,7 @@
#include "GCActivityCallback.h"
#include "APIShims.h"
-#include "Collector.h"
+#include "Heap.h"
#include "JSGlobalData.h"
#include "JSLock.h"
#include <wtf/RetainPtr.h>
diff --git a/Source/JavaScriptCore/runtime/Heap.cpp b/Source/JavaScriptCore/runtime/Heap.cpp
new file mode 100644
index 0000000..a224ee0
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Heap.cpp
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "Heap.h"
+
+#include "CollectorHeapIterator.h"
+#include "GCActivityCallback.h"
+#include "GCHandle.h"
+#include "Interpreter.h"
+#include "JSGlobalData.h"
+#include "JSGlobalObject.h"
+#include "JSLock.h"
+#include "JSONObject.h"
+#include "Tracing.h"
+
+#define COLLECT_ON_EVERY_ALLOCATION 0
+
+namespace JSC {
+
+Heap::Heap(JSGlobalData* globalData)
+ : m_markedSpace(globalData)
+ , m_operationInProgress(NoOperation)
+ , m_markListSet(0)
+ , m_activityCallback(DefaultGCActivityCallback::create(this))
+ , m_globalData(globalData)
+ , m_machineStackMarker(&globalData->heap)
+ , m_extraCost(0)
+{
+ (*m_activityCallback)();
+}
+
+Heap::~Heap()
+{
+ // The destroy function must already have been called, so assert this.
+ ASSERT(!m_globalData);
+}
+
+void Heap::destroy()
+{
+ JSLock lock(SilenceAssertionsOnly);
+
+ if (!m_globalData)
+ return;
+
+ ASSERT(!m_globalData->dynamicGlobalObject);
+ ASSERT(m_operationInProgress == NoOperation);
+
+ // 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);
+
+ delete m_markListSet;
+ m_markListSet = 0;
+
+ ProtectCountSet protectedValuesCopy = m_protectedValues;
+ m_markedSpace.destroy(protectedValuesCopy);
+ ASSERT(!protectedObjectCount());
+
+ m_globalData = 0;
+}
+
+void Heap::recordExtraCost(size_t cost)
+{
+ // Our frequency of garbage collection tries to balance memory use against speed
+ // by collecting based on the number of newly created values. However, for values
+ // that hold on to a great deal of memory that's not in the form of other JS values,
+ // that is not good enough - in some cases a lot of those objects can pile up and
+ // use crazy amounts of memory without a GC happening. So we track these extra
+ // memory costs. Only unusually large objects are noted, and we only keep track
+ // of this extra cost until the next GC. In garbage collected languages, most values
+ // 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.
+
+ if (m_extraCost > maxExtraCost && m_extraCost > m_markedSpace.size() / 2) {
+ 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_markedSpace.didShrink())
+ m_markedSpace.sweep();
+
+ markRoots();
+
+ JAVASCRIPTCORE_GC_MARKED();
+
+ m_markedSpace.reset();
+ m_extraCost = 0;
+
+ JAVASCRIPTCORE_GC_END();
+
+ (*m_activityCallback)();
+ }
+ m_extraCost += cost;
+}
+
+void* Heap::allocate(size_t s)
+{
+ ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable());
+ ASSERT(JSLock::lockCount() > 0);
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+ ASSERT_UNUSED(s, s <= HeapConstants::cellSize);
+ ASSERT(m_operationInProgress == NoOperation);
+
+#if COLLECT_ON_EVERY_ALLOCATION
+ collectAllGarbage();
+ ASSERT(m_operationInProgress == NoOperation);
+#endif
+
+ m_operationInProgress = Allocation;
+ void* result = m_markedSpace.allocate(s);
+ m_operationInProgress = NoOperation;
+
+ if (!result) {
+ JAVASCRIPTCORE_GC_BEGIN();
+
+ markRoots();
+
+ JAVASCRIPTCORE_GC_MARKED();
+
+ m_markedSpace.reset();
+ m_extraCost = 0;
+
+ JAVASCRIPTCORE_GC_END();
+
+ (*m_activityCallback)();
+
+ m_operationInProgress = Allocation;
+ result = m_markedSpace.allocate(s);
+ m_operationInProgress = NoOperation;
+ }
+ ASSERT(result);
+ return result;
+}
+
+void Heap::markConservatively(MarkStack& markStack, void* start, void* end)
+{
+ m_markedSpace.markConservatively(markStack, start, end);
+}
+
+void Heap::updateWeakGCHandles()
+{
+ for (unsigned i = 0; i < m_weakGCHandlePools.size(); ++i)
+ weakGCHandlePool(i)->update();
+}
+
+void WeakGCHandlePool::update()
+{
+ for (unsigned i = 1; i < WeakGCHandlePool::numPoolEntries; ++i) {
+ if (m_entries[i].isValidPtr()) {
+ JSCell* cell = m_entries[i].get();
+ if (!cell || !Heap::isCellMarked(cell))
+ m_entries[i].invalidate();
+ }
+ }
+}
+
+WeakGCHandle* Heap::addWeakGCHandle(JSCell* ptr)
+{
+ for (unsigned i = 0; i < m_weakGCHandlePools.size(); ++i)
+ if (!weakGCHandlePool(i)->isFull())
+ return weakGCHandlePool(i)->allocate(ptr);
+
+ PageAllocationAligned allocation = PageAllocationAligned::allocate(WeakGCHandlePool::poolSize, WeakGCHandlePool::poolSize, OSAllocator::JSGCHeapPages);
+ m_weakGCHandlePools.append(allocation);
+
+ WeakGCHandlePool* pool = new (allocation.base()) WeakGCHandlePool();
+ return pool->allocate(ptr);
+}
+
+void Heap::protect(JSValue k)
+{
+ ASSERT(k);
+ ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance());
+
+ if (!k.isCell())
+ return;
+
+ m_protectedValues.add(k.asCell());
+}
+
+bool Heap::unprotect(JSValue k)
+{
+ ASSERT(k);
+ ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance());
+
+ if (!k.isCell())
+ return false;
+
+ return m_protectedValues.remove(k.asCell());
+}
+
+void Heap::markProtectedObjects(MarkStack& markStack)
+{
+ ProtectCountSet::iterator end = m_protectedValues.end();
+ for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) {
+ markStack.append(it->first);
+ markStack.drain();
+ }
+}
+
+void Heap::pushTempSortVector(Vector<ValueStringPair>* tempVector)
+{
+ m_tempSortingVectors.append(tempVector);
+}
+
+void Heap::popTempSortVector(Vector<ValueStringPair>* tempVector)
+{
+ ASSERT_UNUSED(tempVector, tempVector == m_tempSortingVectors.last());
+ m_tempSortingVectors.removeLast();
+}
+
+void Heap::markTempSortVectors(MarkStack& markStack)
+{
+ typedef Vector<Vector<ValueStringPair>* > VectorOfValueStringVectors;
+
+ VectorOfValueStringVectors::iterator end = m_tempSortingVectors.end();
+ for (VectorOfValueStringVectors::iterator it = m_tempSortingVectors.begin(); it != end; ++it) {
+ Vector<ValueStringPair>* tempSortingVector = *it;
+
+ Vector<ValueStringPair>::iterator vectorEnd = tempSortingVector->end();
+ for (Vector<ValueStringPair>::iterator vectorIt = tempSortingVector->begin(); vectorIt != vectorEnd; ++vectorIt)
+ if (vectorIt->first)
+ markStack.append(vectorIt->first);
+ markStack.drain();
+ }
+}
+
+void Heap::markRoots()
+{
+#ifndef NDEBUG
+ if (m_globalData->isSharedInstance()) {
+ ASSERT(JSLock::lockCount() > 0);
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+ }
+#endif
+
+ ASSERT(m_operationInProgress == NoOperation);
+ if (m_operationInProgress != NoOperation)
+ CRASH();
+
+ m_operationInProgress = Collection;
+
+ MarkStack& markStack = m_globalData->markStack;
+
+ // Reset mark bits.
+ m_markedSpace.clearMarkBits();
+
+ // Mark stack roots.
+ m_machineStackMarker.markMachineStackConservatively(markStack);
+ m_globalData->interpreter->registerFile().markCallFrames(markStack, this);
+
+ // Mark explicitly registered roots.
+ markProtectedObjects(markStack);
+
+ // Mark temporary vector for Array sorting
+ markTempSortVectors(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);
+ if (m_globalData->firstStringifierToMark)
+ JSONObject::markStringifiers(markStack, m_globalData->firstStringifierToMark);
+
+ // Mark the small strings cache last, since it will clear itself if nothing
+ // else has marked it.
+ m_globalData->smallStrings.markChildren(markStack);
+
+ markStack.drain();
+ markStack.compact();
+
+ updateWeakGCHandles();
+
+ m_operationInProgress = NoOperation;
+}
+
+size_t Heap::objectCount() const
+{
+ return m_markedSpace.objectCount();
+}
+
+MarkedSpace::Statistics Heap::statistics() const
+{
+ return m_markedSpace.statistics();
+}
+
+size_t Heap::size() const
+{
+ return m_markedSpace.size();
+}
+
+size_t Heap::globalObjectCount()
+{
+ size_t count = 0;
+ if (JSGlobalObject* head = m_globalData->head) {
+ JSGlobalObject* o = head;
+ do {
+ ++count;
+ o = o->next();
+ } while (o != head);
+ }
+ return count;
+}
+
+size_t Heap::protectedGlobalObjectCount()
+{
+ size_t count = 0;
+ if (JSGlobalObject* head = m_globalData->head) {
+ JSGlobalObject* o = head;
+ do {
+ if (m_protectedValues.contains(o))
+ ++count;
+ o = o->next();
+ } while (o != head);
+ }
+
+ return count;
+}
+
+size_t Heap::protectedObjectCount()
+{
+ return m_protectedValues.size();
+}
+
+static const char* typeName(JSCell* cell)
+{
+ if (cell->isString())
+ return "string";
+ if (cell->isGetterSetter())
+ return "Getter-Setter";
+ if (cell->isAPIValueWrapper())
+ return "API wrapper";
+ if (cell->isPropertyNameIterator())
+ return "For-in iterator";
+ if (!cell->isObject())
+ return "[empty cell]";
+ const ClassInfo* info = cell->classInfo();
+ return info ? info->className : "Object";
+}
+
+HashCountedSet<const char*>* Heap::protectedObjectTypeCounts()
+{
+ HashCountedSet<const char*>* counts = new HashCountedSet<const char*>;
+
+ ProtectCountSet::iterator end = m_protectedValues.end();
+ for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
+ counts->add(typeName(it->first));
+
+ return counts;
+}
+
+HashCountedSet<const char*>* Heap::objectTypeCounts()
+{
+ HashCountedSet<const char*>* counts = new HashCountedSet<const char*>;
+
+ LiveObjectIterator it = primaryHeapBegin();
+ LiveObjectIterator heapEnd = primaryHeapEnd();
+ for ( ; it != heapEnd; ++it)
+ counts->add(typeName(*it));
+
+ return counts;
+}
+
+bool Heap::isBusy()
+{
+ return m_operationInProgress != NoOperation;
+}
+
+void Heap::collectAllGarbage()
+{
+ ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable());
+ 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_markedSpace.didShrink())
+ m_markedSpace.sweep();
+
+ markRoots();
+
+ JAVASCRIPTCORE_GC_MARKED();
+
+ m_markedSpace.reset();
+ m_markedSpace.sweep();
+ m_extraCost = 0;
+
+ JAVASCRIPTCORE_GC_END();
+
+ (*m_activityCallback)();
+}
+
+LiveObjectIterator Heap::primaryHeapBegin()
+{
+ return m_markedSpace.primaryHeapBegin();
+}
+
+LiveObjectIterator Heap::primaryHeapEnd()
+{
+ return m_markedSpace.primaryHeapEnd();
+}
+
+void Heap::setActivityCallback(PassOwnPtr<GCActivityCallback> activityCallback)
+{
+ m_activityCallback = activityCallback;
+}
+
+GCActivityCallback* Heap::activityCallback()
+{
+ return m_activityCallback.get();
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Heap.h b/Source/JavaScriptCore/runtime/Heap.h
new file mode 100644
index 0000000..243bba3
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Heap.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef Heap_h
+#define Heap_h
+
+#include "MarkedSpace.h"
+#include <wtf/Forward.h>
+#include <wtf/HashSet.h>
+
+#define ASSERT_CLASS_FITS_IN_CELL(class) COMPILE_ASSERT(sizeof(class) <= CELL_SIZE, class_fits_in_cell)
+
+namespace JSC {
+
+ class JSValue;
+ class UString;
+ class GCActivityCallback;
+ class JSCell;
+ class JSGlobalData;
+ class JSValue;
+ class LiveObjectIterator;
+ class MarkedArgumentBuffer;
+ class MarkStack;
+ class WeakGCHandlePool;
+
+ typedef std::pair<JSValue, UString> ValueStringPair;
+
+ enum OperationInProgress { NoOperation, Allocation, Collection };
+
+ class Heap : public Noncopyable {
+ public:
+ void destroy();
+
+ void* allocate(size_t);
+
+ bool isBusy(); // true if an allocation or collection is in progress
+ void collectAllGarbage();
+
+ GCActivityCallback* activityCallback();
+ void setActivityCallback(PassOwnPtr<GCActivityCallback>);
+
+ static const size_t minExtraCost = 256;
+ static const size_t maxExtraCost = 1024 * 1024;
+
+ void reportExtraMemoryCost(size_t cost);
+
+ size_t objectCount() const;
+ MarkedSpace::Statistics statistics() const;
+ size_t size() const;
+
+ void protect(JSValue);
+ // Returns true if the value is no longer protected by any protect pointers
+ // (though it may still be alive due to heap/stack references).
+ bool unprotect(JSValue);
+
+ static Heap* heap(JSValue); // 0 for immediate values
+ static Heap* heap(JSCell*);
+
+ size_t globalObjectCount();
+ size_t protectedObjectCount();
+ size_t protectedGlobalObjectCount();
+ HashCountedSet<const char*>* protectedObjectTypeCounts();
+ HashCountedSet<const char*>* objectTypeCounts();
+
+ static bool isCellMarked(const JSCell*);
+ static bool checkMarkCell(const JSCell*);
+ static void markCell(JSCell*);
+
+ WeakGCHandle* addWeakGCHandle(JSCell*);
+
+ void markConservatively(MarkStack&, void* start, void* end);
+
+ void pushTempSortVector(WTF::Vector<ValueStringPair>*);
+ void popTempSortVector(WTF::Vector<ValueStringPair>*);
+
+ HashSet<MarkedArgumentBuffer*>& markListSet() { if (!m_markListSet) m_markListSet = new HashSet<MarkedArgumentBuffer*>; return *m_markListSet; }
+
+ JSGlobalData* globalData() const { return m_globalData; }
+
+ LiveObjectIterator primaryHeapBegin();
+ LiveObjectIterator primaryHeapEnd();
+
+ MachineStackMarker& machineStackMarker() { return m_machineStackMarker; }
+
+ MarkedSpace& markedSpace() { return m_markedSpace; }
+
+ private:
+ friend class JSGlobalData;
+ Heap(JSGlobalData*);
+ ~Heap();
+
+ void recordExtraCost(size_t);
+
+ void markRoots();
+ void markProtectedObjects(MarkStack&);
+ void markTempSortVectors(MarkStack&);
+
+ void updateWeakGCHandles();
+ WeakGCHandlePool* weakGCHandlePool(size_t index);
+
+ MarkedSpace m_markedSpace;
+ OperationInProgress m_operationInProgress;
+
+ ProtectCountSet m_protectedValues;
+ WTF::Vector<PageAllocationAligned> m_weakGCHandlePools;
+ WTF::Vector<WTF::Vector<ValueStringPair>* > m_tempSortingVectors;
+
+ HashSet<MarkedArgumentBuffer*>* m_markListSet;
+
+ OwnPtr<GCActivityCallback> m_activityCallback;
+
+ JSGlobalData* m_globalData;
+
+ MachineStackMarker m_machineStackMarker;
+
+ size_t m_extraCost;
+ };
+
+ inline bool Heap::isCellMarked(const JSCell* cell)
+ {
+ return MarkedSpace::isCellMarked(cell);
+ }
+
+ inline bool Heap::checkMarkCell(const JSCell* cell)
+ {
+ return MarkedSpace::checkMarkCell(cell);
+ }
+
+ inline void Heap::markCell(JSCell* cell)
+ {
+ MarkedSpace::markCell(cell);
+ }
+
+ inline void Heap::reportExtraMemoryCost(size_t cost)
+ {
+ if (cost > minExtraCost)
+ recordExtraCost(cost);
+ }
+
+ inline WeakGCHandlePool* Heap::weakGCHandlePool(size_t index)
+ {
+ return static_cast<WeakGCHandlePool*>(m_weakGCHandlePools[index].base());
+ }
+
+} // namespace JSC
+
+#endif // Heap_h
diff --git a/Source/JavaScriptCore/runtime/InitializeThreading.cpp b/Source/JavaScriptCore/runtime/InitializeThreading.cpp
index 08dddc1..27611b7 100644
--- a/Source/JavaScriptCore/runtime/InitializeThreading.cpp
+++ b/Source/JavaScriptCore/runtime/InitializeThreading.cpp
@@ -29,7 +29,7 @@
#include "config.h"
#include "InitializeThreading.h"
-#include "Collector.h"
+#include "Heap.h"
#include "dtoa.h"
#include "Identifier.h"
#include "JSGlobalObject.h"
diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp
index 556a16e..556603b 100644
--- a/Source/JavaScriptCore/runtime/JSArray.cpp
+++ b/Source/JavaScriptCore/runtime/JSArray.cpp
@@ -952,8 +952,10 @@ void JSArray::sort(ExecState* exec)
for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
values[i].second = values[i].first.toString(exec);
- if (exec->hadException())
+ if (exec->hadException()) {
+ Heap::heap(this)->popTempSortVector(&values);
return;
+ }
// FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather
// than O(N log N).
diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h
index 7d4929d..95f4efa 100644
--- a/Source/JavaScriptCore/runtime/JSCell.h
+++ b/Source/JavaScriptCore/runtime/JSCell.h
@@ -25,7 +25,7 @@
#include "CallData.h"
#include "ConstructData.h"
-#include "Collector.h"
+#include "Heap.h"
#include "JSImmediate.h"
#include "JSValue.h"
#include "MarkStack.h"
@@ -63,6 +63,7 @@ namespace JSC {
friend class JSAPIValueWrapper;
friend class JSZombie;
friend class JSGlobalData;
+ friend class MarkedSpace;
private:
explicit JSCell(Structure*);
@@ -362,7 +363,7 @@ namespace JSC {
inline Heap* Heap::heap(JSCell* c)
{
- return cellBlock(c)->heap;
+ return MarkedSpace::cellBlock(c)->heap;
}
#if ENABLE(JSC_ZOMBIES)
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
index aca995a..f20a9a4 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
@@ -30,7 +30,7 @@
#include "JSGlobalData.h"
#include "ArgList.h"
-#include "Collector.h"
+#include "Heap.h"
#include "CollectorHeapIterator.h"
#include "CommonIdentifiers.h"
#include "FunctionConstructor.h"
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h
index 699f975..a24732a 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalData.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.h
@@ -30,7 +30,7 @@
#define JSGlobalData_h
#include "CachedTranscendentalFunction.h"
-#include "Collector.h"
+#include "Heap.h"
#include "DateInstanceCache.h"
#include "ExecutableAllocator.h"
#include "JITStubs.h"
@@ -128,7 +128,7 @@ namespace JSC {
#if ENABLE(JSC_MULTIPLE_THREADS)
// Will start tracking threads that use the heap, which is resource-heavy.
- void makeUsableFromMultipleThreads() { heap.makeUsableFromMultipleThreads(); }
+ void makeUsableFromMultipleThreads() { heap.machineStackMarker().makeUsableFromMultipleThreads(); }
#endif
GlobalDataType globalDataType;
@@ -229,8 +229,7 @@ namespace JSC {
int maxReentryDepth;
RegExpCache* m_regExpCache;
-
- BumpPointerAllocator m_regexAllocator;
+ BumpPointerAllocator m_regExpAllocator;
#if ENABLE(REGEXP_TRACING)
typedef ListHashSet<RefPtr<RegExp> > RTTraceList;
diff --git a/Source/JavaScriptCore/runtime/JSLock.cpp b/Source/JavaScriptCore/runtime/JSLock.cpp
index 10f4f3f..918141f 100644
--- a/Source/JavaScriptCore/runtime/JSLock.cpp
+++ b/Source/JavaScriptCore/runtime/JSLock.cpp
@@ -21,7 +21,7 @@
#include "config.h"
#include "JSLock.h"
-#include "Collector.h"
+#include "Heap.h"
#include "CallFrame.h"
#if ENABLE(JSC_MULTIPLE_THREADS)
diff --git a/Source/JavaScriptCore/runtime/JSNumberCell.h b/Source/JavaScriptCore/runtime/JSNumberCell.h
index 0040067..1ccdf50 100644
--- a/Source/JavaScriptCore/runtime/JSNumberCell.h
+++ b/Source/JavaScriptCore/runtime/JSNumberCell.h
@@ -26,7 +26,7 @@
#include "CallFrame.h"
#include "JSCell.h"
#include "JSImmediate.h"
-#include "Collector.h"
+#include "Heap.h"
#include "UString.h"
#include <stddef.h> // for size_t
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index 30e40e4..6ecc73f 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -588,10 +588,28 @@ bool JSObject::getPropertyDescriptor(ExecState* exec, const Identifier& property
}
}
-static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& propertyName, PropertyDescriptor& descriptor, unsigned attributes, JSValue oldValue)
+static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& propertyName, PropertyDescriptor& descriptor, unsigned attributes, const PropertyDescriptor& oldDescriptor)
{
if (descriptor.isGenericDescriptor() || descriptor.isDataDescriptor()) {
- target->putWithAttributes(exec, propertyName, descriptor.value() ? descriptor.value() : oldValue, attributes & ~(Getter | Setter));
+ if (descriptor.isGenericDescriptor() && oldDescriptor.isAccessorDescriptor()) {
+ GetterSetter* accessor = new (exec) GetterSetter(exec);
+ if (oldDescriptor.getter()) {
+ attributes |= Getter;
+ accessor->setGetter(asObject(oldDescriptor.getter()));
+ }
+ if (oldDescriptor.setter()) {
+ attributes |= Setter;
+ accessor->setSetter(asObject(oldDescriptor.setter()));
+ }
+ target->putWithAttributes(exec, propertyName, accessor, attributes);
+ return true;
+ }
+ JSValue newValue = jsUndefined();
+ if (descriptor.value())
+ newValue = descriptor.value();
+ else if (oldDescriptor.value())
+ newValue = oldDescriptor.value();
+ target->putWithAttributes(exec, propertyName, newValue, attributes & ~(Getter | Setter));
return true;
}
attributes &= ~ReadOnly;
@@ -608,8 +626,11 @@ bool JSObject::defineOwnProperty(ExecState* exec, const Identifier& propertyName
{
// If we have a new property we can just put it on normally
PropertyDescriptor current;
- if (!getOwnPropertyDescriptor(exec, propertyName, current))
- return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributes(), jsUndefined());
+ if (!getOwnPropertyDescriptor(exec, propertyName, current)) {
+ PropertyDescriptor oldDescriptor;
+ oldDescriptor.setValue(jsUndefined());
+ return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributes(), oldDescriptor);
+ }
if (descriptor.isEmpty())
return true;
@@ -635,7 +656,7 @@ bool JSObject::defineOwnProperty(ExecState* exec, const Identifier& propertyName
if (descriptor.isGenericDescriptor()) {
if (!current.attributesEqual(descriptor)) {
deleteProperty(exec, propertyName);
- putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current.value());
+ putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current);
}
return true;
}
@@ -648,7 +669,7 @@ bool JSObject::defineOwnProperty(ExecState* exec, const Identifier& propertyName
return false;
}
deleteProperty(exec, propertyName);
- return putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current.value() ? current.value() : jsUndefined());
+ return putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current);
}
// Changing the value and attributes of an existing property
@@ -676,7 +697,7 @@ bool JSObject::defineOwnProperty(ExecState* exec, const Identifier& propertyName
return true;
}
deleteProperty(exec, propertyName);
- return putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current.value());
+ return putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current);
}
// Changing the accessor functions of an existing accessor property
diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h
index fefffde..6696404 100644
--- a/Source/JavaScriptCore/runtime/JSString.h
+++ b/Source/JavaScriptCore/runtime/JSString.h
@@ -314,11 +314,15 @@ namespace JSC {
~JSString()
{
ASSERT(vptr() == JSGlobalData::jsStringVPtr);
- for (unsigned i = 0; i < m_fiberCount; ++i)
- RopeImpl::deref(m_other.m_fibers[i]);
-
- if (!m_fiberCount && m_other.m_finalizerCallback)
- m_other.m_finalizerCallback(this, m_other.m_finalizerContext);
+ if (!m_fiberCount) {
+ if (m_other.m_finalizerCallback)
+ m_other.m_finalizerCallback(this, m_other.m_finalizerContext);
+ } else {
+ unsigned i = 0;
+ do
+ RopeImpl::deref(m_other.m_fibers[i]);
+ while (++i < m_fiberCount);
+ }
}
const UString& value(ExecState* exec) const
@@ -624,8 +628,7 @@ namespace JSC {
inline UString JSValue::toPrimitiveString(ExecState* exec) const
{
- if (isString())
- return static_cast<JSString*>(asCell())->value(exec);
+ ASSERT(!isString());
if (isInt32())
return exec->globalData().numericStrings.add(asInt32());
if (isDouble())
diff --git a/Source/JavaScriptCore/runtime/JSValue.h b/Source/JavaScriptCore/runtime/JSValue.h
index dc54f40..cad9662 100644
--- a/Source/JavaScriptCore/runtime/JSValue.h
+++ b/Source/JavaScriptCore/runtime/JSValue.h
@@ -763,8 +763,7 @@ namespace JSC {
return asValue() == jsNull();
}
#endif // USE(JSVALUE32_64)
-
- typedef std::pair<JSValue, UString> ValueStringPair;
+
} // namespace JSC
#endif // JSValue_h
diff --git a/Source/JavaScriptCore/runtime/MachineStackMarker.cpp b/Source/JavaScriptCore/runtime/MachineStackMarker.cpp
new file mode 100644
index 0000000..b4a1936
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/MachineStackMarker.cpp
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "MachineStackMarker.h"
+
+#include "Heap.h"
+#include "JSArray.h"
+#include "JSGlobalData.h"
+#include <setjmp.h>
+#include <stdlib.h>
+
+#if OS(DARWIN)
+
+#include <mach/mach_init.h>
+#include <mach/mach_port.h>
+#include <mach/task.h>
+#include <mach/thread_act.h>
+#include <mach/vm_map.h>
+
+#elif OS(WINDOWS)
+
+#include <windows.h>
+#include <malloc.h>
+
+#elif OS(HAIKU)
+
+#include <OS.h>
+
+#elif OS(UNIX)
+
+#include <stdlib.h>
+#if !OS(HAIKU)
+#include <sys/mman.h>
+#endif
+#include <unistd.h>
+
+#if OS(SOLARIS)
+#include <thread.h>
+#else
+#include <pthread.h>
+#endif
+
+#if HAVE(PTHREAD_NP_H)
+#include <pthread_np.h>
+#endif
+
+#if OS(QNX)
+#include <fcntl.h>
+#include <sys/procfs.h>
+#include <stdio.h>
+#include <errno.h>
+#endif
+
+#endif
+
+namespace JSC {
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+
+#if OS(DARWIN)
+typedef mach_port_t PlatformThread;
+#elif OS(WINDOWS)
+typedef HANDLE PlatformThread;
+#endif
+
+class MachineStackMarker::Thread {
+public:
+ Thread(pthread_t pthread, const PlatformThread& platThread, void* base)
+ : posixThread(pthread)
+ , platformThread(platThread)
+ , stackBase(base)
+ {
+ }
+
+ Thread* next;
+ pthread_t posixThread;
+ PlatformThread platformThread;
+ void* stackBase;
+};
+
+#endif
+
+MachineStackMarker::MachineStackMarker(Heap* heap)
+ : m_heap(heap)
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ , m_registeredThreads(0)
+ , m_currentThreadRegistrar(0)
+#endif
+{
+}
+
+MachineStackMarker::~MachineStackMarker()
+{
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ if (m_currentThreadRegistrar) {
+ int error = pthread_key_delete(m_currentThreadRegistrar);
+ ASSERT_UNUSED(error, !error);
+ }
+
+ MutexLocker registeredThreadsLock(m_registeredThreadsMutex);
+ for (Thread* t = m_registeredThreads; t;) {
+ Thread* next = t->next;
+ delete t;
+ t = next;
+ }
+#endif
+}
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+
+static inline PlatformThread getCurrentPlatformThread()
+{
+#if OS(DARWIN)
+ return pthread_mach_thread_np(pthread_self());
+#elif OS(WINDOWS)
+ return pthread_getw32threadhandle_np(pthread_self());
+#endif
+}
+
+void MachineStackMarker::makeUsableFromMultipleThreads()
+{
+ if (m_currentThreadRegistrar)
+ return;
+
+ int error = pthread_key_create(&m_currentThreadRegistrar, unregisterThread);
+ if (error)
+ CRASH();
+}
+
+void MachineStackMarker::registerThread()
+{
+ ASSERT(!m_heap->globalData()->exclusiveThread || m_heap->globalData()->exclusiveThread == currentThread());
+
+ if (!m_currentThreadRegistrar || pthread_getspecific(m_currentThreadRegistrar))
+ return;
+
+ pthread_setspecific(m_currentThreadRegistrar, this);
+ Thread* thread = new Thread(pthread_self(), getCurrentPlatformThread(), m_heap->globalData()->stack().origin());
+
+ MutexLocker lock(m_registeredThreadsMutex);
+
+ thread->next = m_registeredThreads;
+ m_registeredThreads = thread;
+}
+
+void MachineStackMarker::unregisterThread(void* p)
+{
+ if (p)
+ static_cast<MachineStackMarker*>(p)->unregisterThread();
+}
+
+void MachineStackMarker::unregisterThread()
+{
+ pthread_t currentPosixThread = pthread_self();
+
+ MutexLocker lock(m_registeredThreadsMutex);
+
+ if (pthread_equal(currentPosixThread, m_registeredThreads->posixThread)) {
+ Thread* t = m_registeredThreads;
+ m_registeredThreads = m_registeredThreads->next;
+ delete t;
+ } else {
+ Thread* last = m_registeredThreads;
+ Thread* t;
+ for (t = m_registeredThreads->next; t; t = t->next) {
+ if (pthread_equal(t->posixThread, currentPosixThread)) {
+ last->next = t->next;
+ break;
+ }
+ last = t;
+ }
+ ASSERT(t); // If t is NULL, we never found ourselves in the list.
+ delete t;
+ }
+}
+
+#endif
+
+void NEVER_INLINE MachineStackMarker::markCurrentThreadConservativelyInternal(MarkStack& markStack)
+{
+ m_heap->markConservatively(markStack, m_heap->globalData()->stack().current(), m_heap->globalData()->stack().origin());
+ markStack.drain();
+}
+
+#if COMPILER(GCC)
+#define REGISTER_BUFFER_ALIGNMENT __attribute__ ((aligned (sizeof(void*))))
+#else
+#define REGISTER_BUFFER_ALIGNMENT
+#endif
+
+void MachineStackMarker::markCurrentThreadConservatively(MarkStack& markStack)
+{
+ // setjmp forces volatile registers onto the stack
+ jmp_buf registers REGISTER_BUFFER_ALIGNMENT;
+#if COMPILER(MSVC)
+#pragma warning(push)
+#pragma warning(disable: 4611)
+#endif
+ setjmp(registers);
+#if COMPILER(MSVC)
+#pragma warning(pop)
+#endif
+
+ markCurrentThreadConservativelyInternal(markStack);
+}
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+
+static inline void suspendThread(const PlatformThread& platformThread)
+{
+#if OS(DARWIN)
+ thread_suspend(platformThread);
+#elif OS(WINDOWS)
+ SuspendThread(platformThread);
+#else
+#error Need a way to suspend threads on this platform
+#endif
+}
+
+static inline void resumeThread(const PlatformThread& platformThread)
+{
+#if OS(DARWIN)
+ thread_resume(platformThread);
+#elif OS(WINDOWS)
+ ResumeThread(platformThread);
+#else
+#error Need a way to resume threads on this platform
+#endif
+}
+
+typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit
+
+#if OS(DARWIN)
+
+#if CPU(X86)
+typedef i386_thread_state_t PlatformThreadRegisters;
+#elif CPU(X86_64)
+typedef x86_thread_state64_t PlatformThreadRegisters;
+#elif CPU(PPC)
+typedef ppc_thread_state_t PlatformThreadRegisters;
+#elif CPU(PPC64)
+typedef ppc_thread_state64_t PlatformThreadRegisters;
+#elif CPU(ARM)
+typedef arm_thread_state_t PlatformThreadRegisters;
+#else
+#error Unknown Architecture
+#endif
+
+#elif OS(WINDOWS) && CPU(X86)
+typedef CONTEXT PlatformThreadRegisters;
+#else
+#error Need a thread register struct for this platform
+#endif
+
+static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, PlatformThreadRegisters& regs)
+{
+#if OS(DARWIN)
+
+#if CPU(X86)
+ unsigned user_count = sizeof(regs)/sizeof(int);
+ thread_state_flavor_t flavor = i386_THREAD_STATE;
+#elif CPU(X86_64)
+ unsigned user_count = x86_THREAD_STATE64_COUNT;
+ thread_state_flavor_t flavor = x86_THREAD_STATE64;
+#elif CPU(PPC)
+ unsigned user_count = PPC_THREAD_STATE_COUNT;
+ thread_state_flavor_t flavor = PPC_THREAD_STATE;
+#elif CPU(PPC64)
+ unsigned user_count = PPC_THREAD_STATE64_COUNT;
+ thread_state_flavor_t flavor = PPC_THREAD_STATE64;
+#elif CPU(ARM)
+ unsigned user_count = ARM_THREAD_STATE_COUNT;
+ thread_state_flavor_t flavor = ARM_THREAD_STATE;
+#else
+#error Unknown Architecture
+#endif
+
+ kern_return_t result = thread_get_state(platformThread, flavor, (thread_state_t)&regs, &user_count);
+ if (result != KERN_SUCCESS) {
+ WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION,
+ "JavaScript garbage collection failed because thread_get_state returned an error (%d). This is probably the result of running inside Rosetta, which is not supported.", result);
+ CRASH();
+ }
+ return user_count * sizeof(usword_t);
+// end OS(DARWIN)
+
+#elif OS(WINDOWS) && CPU(X86)
+ regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS;
+ GetThreadContext(platformThread, &regs);
+ return sizeof(CONTEXT);
+#else
+#error Need a way to get thread registers on this platform
+#endif
+}
+
+static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs)
+{
+#if OS(DARWIN)
+
+#if __DARWIN_UNIX03
+
+#if CPU(X86)
+ return reinterpret_cast<void*>(regs.__esp);
+#elif CPU(X86_64)
+ return reinterpret_cast<void*>(regs.__rsp);
+#elif CPU(PPC) || CPU(PPC64)
+ return reinterpret_cast<void*>(regs.__r1);
+#elif CPU(ARM)
+ return reinterpret_cast<void*>(regs.__sp);
+#else
+#error Unknown Architecture
+#endif
+
+#else // !__DARWIN_UNIX03
+
+#if CPU(X86)
+ return reinterpret_cast<void*>(regs.esp);
+#elif CPU(X86_64)
+ return reinterpret_cast<void*>(regs.rsp);
+#elif CPU(PPC) || CPU(PPC64)
+ return reinterpret_cast<void*>(regs.r1);
+#else
+#error Unknown Architecture
+#endif
+
+#endif // __DARWIN_UNIX03
+
+// 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
+#endif
+}
+
+void MachineStackMarker::markOtherThreadConservatively(MarkStack& markStack, Thread* thread)
+{
+ suspendThread(thread->platformThread);
+
+ PlatformThreadRegisters regs;
+ size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs);
+
+ // mark the thread's registers
+ m_heap->markConservatively(markStack, static_cast<void*>(&regs), static_cast<void*>(reinterpret_cast<char*>(&regs) + regSize));
+ markStack.drain();
+
+ void* stackPointer = otherThreadStackPointer(regs);
+ m_heap->markConservatively(markStack, stackPointer, thread->stackBase);
+ markStack.drain();
+
+ resumeThread(thread->platformThread);
+}
+
+#endif
+
+void MachineStackMarker::markMachineStackConservatively(MarkStack& markStack)
+{
+ markCurrentThreadConservatively(markStack);
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+
+ if (m_currentThreadRegistrar) {
+
+ MutexLocker lock(m_registeredThreadsMutex);
+
+#ifndef NDEBUG
+ // Forbid malloc during the mark phase. Marking a thread suspends it, so
+ // a malloc inside markChildren() would risk a deadlock with a thread that had been
+ // suspended while holding the malloc lock.
+ fastMallocForbid();
+#endif
+ // It is safe to access the registeredThreads list, because we earlier asserted that locks are being held,
+ // and since this is a shared heap, they are real locks.
+ for (Thread* thread = m_registeredThreads; thread; thread = thread->next) {
+ if (!pthread_equal(thread->posixThread, pthread_self()))
+ markOtherThreadConservatively(markStack, thread);
+ }
+#ifndef NDEBUG
+ fastMallocAllow();
+#endif
+ }
+#endif
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/MachineStackMarker.h b/Source/JavaScriptCore/runtime/MachineStackMarker.h
new file mode 100644
index 0000000..e80fe05
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/MachineStackMarker.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef MachineStackMarker_h
+#define MachineStackMarker_h
+
+#include <wtf/Noncopyable.h>
+#include <wtf/ThreadingPrimitives.h>
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+#include <pthread.h>
+#endif
+
+namespace JSC {
+
+ class Heap;
+ class MarkStack;
+
+ class MachineStackMarker : public Noncopyable {
+ public:
+ MachineStackMarker(Heap*);
+ ~MachineStackMarker();
+
+ void markMachineStackConservatively(MarkStack&);
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ void makeUsableFromMultipleThreads();
+ void registerThread(); // Only needs to be called by clients that can use the same heap from multiple threads.
+#endif
+
+ private:
+ void markCurrentThreadConservatively(MarkStack&);
+ void markCurrentThreadConservativelyInternal(MarkStack&);
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ class Thread;
+
+ static void unregisterThread(void*);
+
+ void unregisterThread();
+ void markOtherThreadConservatively(MarkStack&, Thread*);
+#endif
+
+ Heap* m_heap;
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ Mutex m_registeredThreadsMutex;
+ Thread* m_registeredThreads;
+ pthread_key_t m_currentThreadRegistrar;
+#endif
+ };
+
+} // namespace JSC
+
+#endif // MachineStackMarker_h
diff --git a/Source/JavaScriptCore/runtime/MarkedSpace.cpp b/Source/JavaScriptCore/runtime/MarkedSpace.cpp
new file mode 100644
index 0000000..4bc3c18
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/MarkedSpace.cpp
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "MarkedSpace.h"
+
+#include "CollectorHeapIterator.h"
+#include "JSCell.h"
+#include "JSGlobalData.h"
+#include "JSLock.h"
+
+using std::max;
+
+namespace JSC {
+
+class Structure;
+
+// tunable parameters
+
+const size_t GROWTH_FACTOR = 2;
+const size_t LOW_WATER_FACTOR = 4;
+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))
+
+MarkedSpace::MarkedSpace(JSGlobalData* globalData)
+ : m_globalData(globalData)
+{
+ memset(&m_heap, 0, sizeof(CollectorHeap));
+ allocateBlock();
+}
+
+void MarkedSpace::destroy(ProtectCountSet& protectedValuesCopy)
+{
+ 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();
+
+ 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)
+ m_heap.blocks[block].deallocate();
+
+ fastFree(m_heap.blocks);
+
+ memset(&m_heap, 0, sizeof(CollectorHeap));
+}
+
+NEVER_INLINE CollectorBlock* MarkedSpace::allocateBlock()
+{
+ PageAllocationAligned allocation = PageAllocationAligned::allocate(BLOCK_SIZE, BLOCK_SIZE, OSAllocator::JSGCHeapPages);
+ CollectorBlock* block = static_cast<CollectorBlock*>(allocation.base());
+ if (!block)
+ CRASH();
+
+ // Initialize block.
+
+ block->heap = &globalData()->heap;
+ clearMarkBits(block);
+
+ Structure* dummyMarkableCellStructure = 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(PageAllocationAligned) / GROWTH_FACTOR;
+ if (numBlocks > maxNumBlocks)
+ CRASH();
+ numBlocks = max(MIN_ARRAY_SIZE, numBlocks * GROWTH_FACTOR);
+ m_heap.numBlocks = numBlocks;
+ m_heap.blocks = static_cast<PageAllocationAligned*>(fastRealloc(m_heap.blocks, numBlocks * sizeof(PageAllocationAligned)));
+ }
+ m_heap.blocks[m_heap.usedBlocks++] = allocation;
+
+ return block;
+}
+
+NEVER_INLINE void MarkedSpace::freeBlock(size_t block)
+{
+ m_heap.didShrink = true;
+
+ ObjectIterator it(m_heap, block);
+ ObjectIterator end(m_heap, block + 1);
+ for ( ; it != end; ++it)
+ (*it)->~JSCell();
+ m_heap.blocks[block].deallocate();
+
+ // swap with the last block so we compact as we go
+ m_heap.blocks[block] = m_heap.blocks[m_heap.usedBlocks - 1];
+ m_heap.usedBlocks--;
+
+ 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<PageAllocationAligned*>(fastRealloc(m_heap.blocks, m_heap.numBlocks * sizeof(PageAllocationAligned)));
+ }
+}
+
+void* MarkedSpace::allocate(size_t s)
+{
+ ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable());
+ typedef HeapConstants::Block Block;
+ typedef HeapConstants::Cell Cell;
+
+ ASSERT(JSLock::lockCount() > 0);
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+ ASSERT_UNUSED(s, s <= HeapConstants::cellSize);
+
+ // Fast case: find the next garbage cell and recycle it.
+
+ do {
+ ASSERT(m_heap.nextBlock < m_heap.usedBlocks);
+ Block* block = m_heap.collectorBlock(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];
+
+ JSCell* imp = reinterpret_cast<JSCell*>(cell);
+ imp->~JSCell();
+
+ ++m_heap.nextCell;
+ return cell;
+ }
+ block->marked.advanceToNextPossibleFreeCell(m_heap.nextCell);
+ } while (m_heap.nextCell != HeapConstants::cellsPerBlock);
+ m_heap.nextCell = 0;
+ } while (++m_heap.nextBlock != m_heap.usedBlocks);
+
+ return 0;
+}
+
+void MarkedSpace::resizeBlocks()
+{
+ m_heap.didShrink = false;
+
+ size_t usedCellCount = markedCells();
+ size_t minCellCount = usedCellCount + max(ALLOCATIONS_PER_COLLECTION, usedCellCount);
+ size_t minBlockCount = (minCellCount + HeapConstants::cellsPerBlock - 1) / HeapConstants::cellsPerBlock;
+
+ size_t maxCellCount = 1.25f * minCellCount;
+ size_t maxBlockCount = (maxCellCount + HeapConstants::cellsPerBlock - 1) / HeapConstants::cellsPerBlock;
+
+ if (m_heap.usedBlocks < minBlockCount)
+ growBlocks(minBlockCount);
+ else if (m_heap.usedBlocks > maxBlockCount)
+ shrinkBlocks(maxBlockCount);
+}
+
+void MarkedSpace::growBlocks(size_t neededBlocks)
+{
+ ASSERT(m_heap.usedBlocks < neededBlocks);
+ while (m_heap.usedBlocks < neededBlocks)
+ allocateBlock();
+}
+
+void MarkedSpace::shrinkBlocks(size_t neededBlocks)
+{
+ 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.collectorBlock(i)->marked.clear(HeapConstants::cellsPerBlock - 1);
+
+ for (size_t i = 0; i != m_heap.usedBlocks && m_heap.usedBlocks != neededBlocks; ) {
+ if (m_heap.collectorBlock(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.collectorBlock(i)->marked.set(HeapConstants::cellsPerBlock - 1);
+}
+
+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);
+
+static inline bool isCellAligned(void *p)
+{
+ return (((intptr_t)(p) & CELL_MASK) == 0);
+}
+
+static inline bool isPossibleCell(void* p)
+{
+ return isCellAligned(p) && p;
+}
+
+void MarkedSpace::markConservatively(MarkStack& markStack, void* start, void* end)
+{
+#if OS(WINCE)
+ if (start > end) {
+ void* tmp = start;
+ start = end;
+ end = tmp;
+ }
+#else
+ ASSERT(start <= end);
+#endif
+
+ ASSERT((static_cast<char*>(end) - static_cast<char*>(start)) < 0x1000000);
+ ASSERT(isPointerAligned(start));
+ ASSERT(isPointerAligned(end));
+
+ char** p = static_cast<char**>(start);
+ char** e = static_cast<char**>(end);
+
+ while (p != e) {
+ char* x = *p++;
+ 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);
+ usedBlocks = m_heap.usedBlocks;
+ for (size_t block = 0; block < usedBlocks; block++) {
+ if (m_heap.collectorBlock(block) != blockAddr)
+ continue;
+ markStack.append(reinterpret_cast<JSCell*>(xAsBits));
+ }
+ }
+ }
+}
+
+void MarkedSpace::clearMarkBits()
+{
+ for (size_t i = 0; i < m_heap.usedBlocks; ++i)
+ clearMarkBits(m_heap.collectorBlock(i));
+}
+
+void MarkedSpace::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 MarkedSpace::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.collectorBlock(startBlock)->marked.count(startCell);
+ for (size_t i = startBlock + 1; i < m_heap.usedBlocks; ++i)
+ result += m_heap.collectorBlock(i)->marked.count();
+
+ return result;
+}
+
+void MarkedSpace::sweep()
+{
+#if !ENABLE(JSC_ZOMBIES)
+ Structure* dummyMarkableCellStructure = globalData()->dummyMarkableCellStructure.get();
+#endif
+
+ DeadObjectIterator it(m_heap, m_heap.nextBlock, m_heap.nextCell);
+ DeadObjectIterator end(m_heap, m_heap.usedBlocks);
+ for ( ; it != end; ++it) {
+ JSCell* cell = *it;
+#if ENABLE(JSC_ZOMBIES)
+ if (!cell->isZombie()) {
+ const ClassInfo* info = cell->classInfo();
+ cell->~JSCell();
+ new (cell) JSZombie(info, JSZombie::leakedZombieStructure());
+ Heap::markCell(cell);
+ }
+#else
+ cell->~JSCell();
+ // Callers of sweep assume it's safe to mark any cell in the heap.
+ new (cell) JSCell(dummyMarkableCellStructure);
+#endif
+ }
+}
+
+size_t MarkedSpace::objectCount() const
+{
+ 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
+}
+
+void MarkedSpace::addToStatistics(Statistics& statistics) const
+{
+ statistics.size += m_heap.usedBlocks * BLOCK_SIZE;
+ statistics.free += m_heap.usedBlocks * BLOCK_SIZE - (objectCount() * HeapConstants::cellSize);
+}
+
+MarkedSpace::Statistics MarkedSpace::statistics() const
+{
+ Statistics statistics = { 0, 0 };
+ addToStatistics(statistics);
+ return statistics;
+}
+
+size_t MarkedSpace::size() const
+{
+ return m_heap.usedBlocks * BLOCK_SIZE;
+}
+
+void MarkedSpace::reset()
+{
+ m_heap.nextCell = 0;
+ m_heap.nextBlock = 0;
+#if ENABLE(JSC_ZOMBIES)
+ sweep();
+#endif
+ resizeBlocks();
+}
+
+LiveObjectIterator MarkedSpace::primaryHeapBegin()
+{
+ return LiveObjectIterator(m_heap, 0);
+}
+
+LiveObjectIterator MarkedSpace::primaryHeapEnd()
+{
+ return LiveObjectIterator(m_heap, m_heap.usedBlocks);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Collector.h b/Source/JavaScriptCore/runtime/MarkedSpace.h
index a4e2fe1..78f918c 100644
--- a/Source/JavaScriptCore/runtime/Collector.h
+++ b/Source/JavaScriptCore/runtime/MarkedSpace.h
@@ -19,44 +19,25 @@
*
*/
-#ifndef Collector_h
-#define Collector_h
-
-#include "GCHandle.h"
-#include "JSValue.h"
-#include <stddef.h>
-#include <string.h>
-#include <wtf/Bitmap.h>
+#ifndef MarkedSpace_h
+#define MarkedSpace_h
+
+#include "MachineStackMarker.h"
+#include "PageAllocationAligned.h"
#include <wtf/FixedArray.h>
#include <wtf/HashCountedSet.h>
-#include <wtf/HashSet.h>
#include <wtf/Noncopyable.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/PageAllocation.h>
-#include <wtf/PageAllocationAligned.h>
-#include <wtf/PassOwnPtr.h>
-#include <wtf/StdLibExtras.h>
-#include <wtf/Threading.h>
-
-#if ENABLE(JSC_MULTIPLE_THREADS)
-#include <pthread.h>
-#endif
-
-#define ASSERT_CLASS_FITS_IN_CELL(class) COMPILE_ASSERT(sizeof(class) <= CELL_SIZE, class_fits_in_cell)
+#include <wtf/Vector.h>
namespace JSC {
class CollectorBlock;
- class GCActivityCallback;
+ class Heap;
class JSCell;
class JSGlobalData;
- class JSValue;
- class MarkedArgumentBuffer;
- class MarkStack;
-
- enum OperationInProgress { NoOperation, Allocation, Collection };
-
class LiveObjectIterator;
+ class MarkStack;
+ class WeakGCHandle;
#if OS(WINCE) || OS(SYMBIAN) || PLATFORM(BREWMP)
const size_t BLOCK_SIZE = 64 * 1024; // 64k
@@ -64,47 +45,31 @@ namespace JSC {
const size_t BLOCK_SIZE = 256 * 1024; // 256k
#endif
+ typedef HashCountedSet<JSCell*> ProtectCountSet;
+
struct CollectorHeap {
size_t nextBlock;
size_t nextCell;
PageAllocationAligned* blocks;
- void* nextNumber;
-
size_t numBlocks;
size_t usedBlocks;
- size_t extraCost;
bool didShrink;
- OperationInProgress operationInProgress;
-
CollectorBlock* collectorBlock(size_t index) const
{
return static_cast<CollectorBlock*>(blocks[index].base());
}
};
- class Heap : public Noncopyable {
+ class MarkedSpace : public Noncopyable {
public:
- class Thread;
+ MarkedSpace(JSGlobalData*);
+ void destroy(ProtectCountSet&);
- void destroy();
-
- void* allocateNumber(size_t);
void* allocate(size_t);
- bool isBusy(); // true if an allocation or collection is in progress
- void collectAllGarbage();
-
- GCActivityCallback* activityCallback();
- void setActivityCallback(PassOwnPtr<GCActivityCallback>);
-
- static const size_t minExtraCost = 256;
- static const size_t maxExtraCost = 1024 * 1024;
-
- void reportExtraMemoryCost(size_t cost);
-
size_t objectCount() const;
struct Statistics {
size_t size;
@@ -113,22 +78,8 @@ namespace JSC {
Statistics statistics() const;
size_t size() const;
- void protect(JSValue);
- // Returns true if the value is no longer protected by any protect pointers
- // (though it may still be alive due to heap/stack references).
- bool unprotect(JSValue);
-
- static Heap* heap(JSValue); // 0 for immediate values
static Heap* heap(JSCell*);
- size_t globalObjectCount();
- size_t protectedObjectCount();
- size_t protectedGlobalObjectCount();
- HashCountedSet<const char*>* protectedObjectTypeCounts();
- HashCountedSet<const char*>* objectTypeCounts();
-
- void registerThread(); // Only needs to be called by clients that can use the same heap from multiple threads.
-
static bool isCellMarked(const JSCell*);
static bool checkMarkCell(const JSCell*);
static void markCell(JSCell*);
@@ -137,30 +88,21 @@ namespace JSC {
void markConservatively(MarkStack&, void* start, void* end);
- void pushTempSortVector(WTF::Vector<ValueStringPair>*);
- void popTempSortVector(WTF::Vector<ValueStringPair>*);
-
- HashSet<MarkedArgumentBuffer*>& markListSet() { if (!m_markListSet) m_markListSet = new HashSet<MarkedArgumentBuffer*>; return *m_markListSet; }
-
- JSGlobalData* globalData() const { return m_globalData; }
static bool isNumber(JSCell*);
LiveObjectIterator primaryHeapBegin();
LiveObjectIterator primaryHeapEnd();
- private:
- void reset();
- void sweep();
+ JSGlobalData* globalData() { return m_globalData; }
+
static CollectorBlock* cellBlock(const JSCell*);
static size_t cellOffset(const JSCell*);
- friend class JSGlobalData;
- Heap(JSGlobalData*);
- ~Heap();
+ void reset();
+ void sweep();
NEVER_INLINE CollectorBlock* allocateBlock();
NEVER_INLINE void freeBlock(size_t);
- void freeBlocks();
void resizeBlocks();
void growBlocks(size_t neededBlocks);
void shrinkBlocks(size_t neededBlocks);
@@ -168,44 +110,14 @@ namespace JSC {
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 markTempSortVectors(MarkStack&);
- void markCurrentThreadConservatively(MarkStack&);
- void markCurrentThreadConservativelyInternal(MarkStack&);
- void markOtherThreadConservatively(MarkStack&, Thread*);
- void markStackObjectsConservatively(MarkStack&);
-
- void updateWeakGCHandles();
- WeakGCHandlePool* weakGCHandlePool(size_t index);
-
- typedef HashCountedSet<JSCell*> ProtectCountSet;
+ bool didShrink() { return m_heap.didShrink; }
+
+ private:
CollectorHeap m_heap;
-
- ProtectCountSet m_protectedValues;
- WTF::Vector<PageAllocationAligned> m_weakGCHandlePools;
- WTF::Vector<WTF::Vector<ValueStringPair>* > m_tempSortingVectors;
-
- HashSet<MarkedArgumentBuffer*>* m_markListSet;
-
- OwnPtr<GCActivityCallback> m_activityCallback;
-
-#if ENABLE(JSC_MULTIPLE_THREADS)
- void makeUsableFromMultipleThreads();
-
- static void unregisterThread(void*);
- void unregisterThread();
-
- Mutex m_registeredThreadsMutex;
- Thread* m_registeredThreads;
- pthread_key_t m_currentThreadRegistrar;
-#endif
-
JSGlobalData* m_globalData;
};
@@ -219,7 +131,7 @@ 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 - sizeof(Heap*)) * 8 * CELL_SIZE / (8 * CELL_SIZE + 1) / CELL_SIZE; // one bitmap byte can represent 8 cells.
+ const size_t CELLS_PER_BLOCK = (BLOCK_SIZE - sizeof(MarkedSpace*)) * 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);
@@ -283,54 +195,31 @@ namespace JSC {
typedef CollectorBlock Block;
};
- inline CollectorBlock* Heap::cellBlock(const JSCell* cell)
+ inline CollectorBlock* MarkedSpace::cellBlock(const JSCell* cell)
{
return reinterpret_cast<CollectorBlock*>(reinterpret_cast<uintptr_t>(cell) & BLOCK_MASK);
}
- inline size_t Heap::cellOffset(const JSCell* cell)
+ inline size_t MarkedSpace::cellOffset(const JSCell* cell)
{
return (reinterpret_cast<uintptr_t>(cell) & BLOCK_OFFSET_MASK) / CELL_SIZE;
}
- inline bool Heap::isCellMarked(const JSCell* cell)
+ inline bool MarkedSpace::isCellMarked(const JSCell* cell)
{
return cellBlock(cell)->marked.get(cellOffset(cell));
}
- inline bool Heap::checkMarkCell(const JSCell* cell)
+ inline bool MarkedSpace::checkMarkCell(const JSCell* cell)
{
return cellBlock(cell)->marked.getset(cellOffset(cell));
}
- inline void Heap::markCell(JSCell* cell)
+ inline void MarkedSpace::markCell(JSCell* cell)
{
cellBlock(cell)->marked.set(cellOffset(cell));
}
- inline void Heap::reportExtraMemoryCost(size_t cost)
- {
- 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;
- }
-
-
- inline WeakGCHandlePool* Heap::weakGCHandlePool(size_t index)
- {
- return static_cast<WeakGCHandlePool*>(m_weakGCHandlePools[index].base());
- }
} // namespace JSC
-#endif /* Collector_h */
+#endif // MarkedSpace_h
diff --git a/Source/JavaScriptCore/runtime/MemoryStatistics.cpp b/Source/JavaScriptCore/runtime/MemoryStatistics.cpp
index 7fafa9c..06a319b 100644
--- a/Source/JavaScriptCore/runtime/MemoryStatistics.cpp
+++ b/Source/JavaScriptCore/runtime/MemoryStatistics.cpp
@@ -32,7 +32,7 @@
namespace JSC {
-Heap::Statistics heapStatistics(JSGlobalData* commonGlobalData)
+MarkedSpace::Statistics heapStatistics(JSGlobalData* commonGlobalData)
{
return commonGlobalData->heap.statistics();
}
diff --git a/Source/JavaScriptCore/runtime/MemoryStatistics.h b/Source/JavaScriptCore/runtime/MemoryStatistics.h
index 1b92eb9..2659702 100644
--- a/Source/JavaScriptCore/runtime/MemoryStatistics.h
+++ b/Source/JavaScriptCore/runtime/MemoryStatistics.h
@@ -26,7 +26,7 @@
#ifndef MemoryStatistics_h
#define MemoryStatistics_h
-#include "Collector.h"
+#include "Heap.h"
class JSGlobalData;
@@ -37,7 +37,7 @@ struct GlobalMemoryStatistics {
size_t JITBytes;
};
-Heap::Statistics heapStatistics(JSGlobalData* commonGlobalData);
+MarkedSpace::Statistics heapStatistics(JSGlobalData* commonGlobalData);
GlobalMemoryStatistics globalMemoryStatistics();
}
diff --git a/Source/JavaScriptCore/runtime/Protect.h b/Source/JavaScriptCore/runtime/Protect.h
index 06cf97f..0c1b5e8 100644
--- a/Source/JavaScriptCore/runtime/Protect.h
+++ b/Source/JavaScriptCore/runtime/Protect.h
@@ -22,7 +22,7 @@
#ifndef Protect_h
#define Protect_h
-#include "Collector.h"
+#include "Heap.h"
#include "JSValue.h"
namespace JSC {
diff --git a/Source/JavaScriptCore/runtime/RegExp.cpp b/Source/JavaScriptCore/runtime/RegExp.cpp
index 664a7fb..31a1abe 100644
--- a/Source/JavaScriptCore/runtime/RegExp.cpp
+++ b/Source/JavaScriptCore/runtime/RegExp.cpp
@@ -22,22 +22,20 @@
#include "config.h"
#include "RegExp.h"
+
#include "Lexer.h"
+#include "yarr/Yarr.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wtf/Assertions.h>
#include <wtf/OwnArrayPtr.h>
-#include "yarr/RegexJIT.h"
-#include "yarr/RegexInterpreter.h"
-#include "yarr/RegexPattern.h"
-
namespace JSC {
struct RegExpRepresentation {
#if ENABLE(YARR_JIT)
- Yarr::RegexCodeBlock m_regExpJITCode;
+ Yarr::YarrCodeBlock m_regExpJITCode;
#endif
OwnPtr<Yarr::BytecodePattern> m_regExpBytecode;
};
@@ -82,7 +80,7 @@ PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& patte
RegExp::RegExpState RegExp::compile(JSGlobalData* globalData)
{
- Yarr::RegexPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError);
+ Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError);
if (m_constructionError)
return ParseError;
@@ -92,7 +90,7 @@ RegExp::RegExpState RegExp::compile(JSGlobalData* globalData)
#if ENABLE(YARR_JIT)
if (!pattern.m_containsBackreferences && globalData->canUseJIT()) {
- Yarr::jitCompileRegex(pattern, globalData, m_representation->m_regExpJITCode);
+ Yarr::jitCompile(pattern, globalData, m_representation->m_regExpJITCode);
#if ENABLE(YARR_JIT_DEBUG)
if (!m_representation->m_regExpJITCode.isFallBack())
res = JITCode;
@@ -105,7 +103,7 @@ RegExp::RegExpState RegExp::compile(JSGlobalData* globalData)
}
#endif
- m_representation->m_regExpBytecode = Yarr::byteCompileRegex(pattern, &globalData->m_regexAllocator);
+ m_representation->m_regExpBytecode = Yarr::byteCompile(pattern, &globalData->m_regExpAllocator);
return res;
}
@@ -144,13 +142,13 @@ int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector)
int result;
#if ENABLE(YARR_JIT)
if (m_state == JITCode) {
- result = Yarr::executeRegex(m_representation->m_regExpJITCode, s.characters(), startOffset, s.length(), offsetVector);
+ result = Yarr::execute(m_representation->m_regExpJITCode, s.characters(), startOffset, s.length(), offsetVector);
#if ENABLE(YARR_JIT_DEBUG)
matchCompareWithInterpreter(s, startOffset, offsetVector, result);
#endif
} else
#endif
- result = Yarr::interpretRegex(m_representation->m_regExpBytecode.get(), s.characters(), startOffset, s.length(), offsetVector);
+ result = Yarr::interpret(m_representation->m_regExpBytecode.get(), s.characters(), startOffset, s.length(), offsetVector);
ASSERT(result >= -1);
#if ENABLE(REGEXP_TRACING)
@@ -181,7 +179,7 @@ void RegExp::matchCompareWithInterpreter(const UString& s, int startOffset, int*
for (unsigned j = 0, i = 0; i < m_numSubpatterns + 1; j += 2, i++)
interpreterOffsetVector[j] = -1;
- interpreterResult = Yarr::interpretRegex(m_representation->m_regExpBytecode.get(), s.characters(), startOffset, s.length(), interpreterOffsetVector);
+ interpreterResult = Yarr::interpret(m_representation->m_regExpBytecode.get(), s.characters(), startOffset, s.length(), interpreterOffsetVector);
if (jitResult != interpreterResult)
differences++;
@@ -230,7 +228,7 @@ void RegExp::matchCompareWithInterpreter(const UString& s, int startOffset, int*
snprintf(formattedPattern, 41, (pattLen <= 38) ? "/%.38s/" : "/%.36s...", rawPattern);
#if ENABLE(YARR_JIT)
- Yarr::RegexCodeBlock& codeBlock = m_representation->m_regExpJITCode;
+ Yarr::YarrCodeBlock& codeBlock = m_representation->m_regExpJITCode;
char jitAddr[20];
if (m_state == JITCode)
diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
index 21ca170..30d3eab 100644
--- a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
@@ -307,7 +307,7 @@ JSObject* constructRegExp(ExecState* exec, const ArgList& args)
RefPtr<RegExp> regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags);
if (!regExp->isValid())
- return throwError(exec, createSyntaxError(exec, makeUString("Invalid regular expression: ", regExp->errorMessage())));
+ return throwError(exec, createSyntaxError(exec, regExp->errorMessage()));
return new (exec) RegExpObject(exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regExp.release());
}
diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
index 0a4c8bf..04bcc3b 100644
--- a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
@@ -95,7 +95,7 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec)
}
if (!regExp->isValid())
- return throwVMError(exec, createSyntaxError(exec, makeUString("Invalid regular expression: ", regExp->errorMessage())));
+ return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage()));
asRegExpObject(thisValue)->setRegExp(regExp.release());
asRegExpObject(thisValue)->setLastIndex(0);
diff --git a/Source/JavaScriptCore/runtime/UString.cpp b/Source/JavaScriptCore/runtime/UString.cpp
index b3cd40c..b70d505 100644
--- a/Source/JavaScriptCore/runtime/UString.cpp
+++ b/Source/JavaScriptCore/runtime/UString.cpp
@@ -25,7 +25,7 @@
#include "UString.h"
#include "JSGlobalObjectFunctions.h"
-#include "Collector.h"
+#include "Heap.h"
#include "Identifier.h"
#include "Operations.h"
#include <ctype.h>
diff --git a/Source/JavaScriptCore/runtime/WeakGCMap.h b/Source/JavaScriptCore/runtime/WeakGCMap.h
index 6b96a74..2d4e59d 100644
--- a/Source/JavaScriptCore/runtime/WeakGCMap.h
+++ b/Source/JavaScriptCore/runtime/WeakGCMap.h
@@ -26,7 +26,7 @@
#ifndef WeakGCMap_h
#define WeakGCMap_h
-#include "Collector.h"
+#include "Heap.h"
#include <wtf/HashMap.h>
namespace JSC {
diff --git a/Source/JavaScriptCore/runtime/WeakGCPtr.h b/Source/JavaScriptCore/runtime/WeakGCPtr.h
index ac77cf3..6cc75a5 100644
--- a/Source/JavaScriptCore/runtime/WeakGCPtr.h
+++ b/Source/JavaScriptCore/runtime/WeakGCPtr.h
@@ -26,7 +26,7 @@
#ifndef WeakGCPtr_h
#define WeakGCPtr_h
-#include "Collector.h"
+#include "Heap.h"
#include "GCHandle.h"
#include <wtf/Noncopyable.h>