diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-20 13:01:08 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-20 13:01:08 +0200 |
commit | 49233e234e5c787396cadb2cea33b31ae0cd65c1 (patch) | |
tree | 5410cb9a8fd53168bb60d62c54b654d86f03c38d /Source/JavaScriptCore/runtime | |
parent | b211c645d8ab690f713515dfdc84d80b11c27d2c (diff) | |
download | qtwebkit-49233e234e5c787396cadb2cea33b31ae0cd65c1.tar.gz |
Imported WebKit commit 3a8c29f35d00659d2ce7a0ccdfa8304f14e82327 (http://svn.webkit.org/repository/webkit/trunk@120813)
New snapshot with Windows build fixes
Diffstat (limited to 'Source/JavaScriptCore/runtime')
34 files changed, 1525 insertions, 533 deletions
diff --git a/Source/JavaScriptCore/runtime/Completion.cpp b/Source/JavaScriptCore/runtime/Completion.cpp index ce620245b..311d660a0 100644 --- a/Source/JavaScriptCore/runtime/Completion.cpp +++ b/Source/JavaScriptCore/runtime/Completion.cpp @@ -55,6 +55,8 @@ JSValue evaluate(ExecState* exec, ScopeChainNode* scopeChain, const SourceCode& { JSLock lock(exec); ASSERT(exec->globalData().identifierTable == wtfThreadData().currentIdentifierTable()); + if (exec->globalData().isCollectorBusy()) + CRASH(); CodeProfiling profile(source); diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index 0ada2cb0f..73b4b6c4f 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -47,7 +47,7 @@ void ExecutableBase::destroy(JSCell* cell) } #endif -inline void ExecutableBase::clearCode() +void ExecutableBase::clearCode() { #if ENABLE(JIT) m_jitCodeForCall.clear(); @@ -98,11 +98,6 @@ static void jettisonCodeBlock(JSGlobalData& globalData, OwnPtr<T>& codeBlock) } #endif -void NativeExecutable::finalize(JSCell* cell) -{ - jsCast<NativeExecutable*>(cell)->clearCode(); -} - const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; #if ENABLE(JIT) @@ -146,8 +141,6 @@ FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, const Identifie , m_name(name) , m_inferredName(inferredName.isNull() ? globalData.propertyNames->emptyIdentifier : inferredName) , m_symbolTable(0) - , m_next(0) - , m_prev(0) { } @@ -159,8 +152,6 @@ FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, , m_name(name) , m_inferredName(inferredName.isNull() ? exec->globalData().propertyNames->emptyIdentifier : inferredName) , m_symbolTable(0) - , m_next(0) - , m_prev(0) { } @@ -292,17 +283,9 @@ void EvalExecutable::unlinkCalls() #endif } -void EvalExecutable::finalize(JSCell* cell) -{ - jsCast<EvalExecutable*>(cell)->clearCode(); -} - -inline void EvalExecutable::clearCode() +void EvalExecutable::clearCode() { - if (m_evalCodeBlock) { - m_evalCodeBlock->clearEvalCache(); - m_evalCodeBlock.clear(); - } + m_evalCodeBlock.clear(); Base::clearCode(); } @@ -424,17 +407,9 @@ void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) thisObject->m_programCodeBlock->visitAggregate(visitor); } -void ProgramExecutable::finalize(JSCell* cell) -{ - jsCast<ProgramExecutable*>(cell)->clearCode(); -} - -inline void ProgramExecutable::clearCode() +void ProgramExecutable::clearCode() { - if (m_programCodeBlock) { - m_programCodeBlock->clearEvalCache(); - m_programCodeBlock.clear(); - } + m_programCodeBlock.clear(); Base::clearCode(); } @@ -642,37 +617,17 @@ void FunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) thisObject->m_codeBlockForConstruct->visitAggregate(visitor); } -void FunctionExecutable::discardCode() +void FunctionExecutable::clearCodeIfNotCompiling() { -#if ENABLE(JIT) - // These first two checks are to handle the rare case where - // we are trying to evict code for a function during its - // codegen. - if (!m_jitCodeForCall && m_codeBlockForCall) - return; - if (!m_jitCodeForConstruct && m_codeBlockForConstruct) + if (isCompiling()) return; -#endif clearCode(); } -void FunctionExecutable::finalize(JSCell* cell) +void FunctionExecutable::clearCode() { - FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell); - Heap::heap(executable)->removeFunctionExecutable(executable); - executable->clearCode(); -} - -inline void FunctionExecutable::clearCode() -{ - if (m_codeBlockForCall) { - m_codeBlockForCall->clearEvalCache(); - m_codeBlockForCall.clear(); - } - if (m_codeBlockForConstruct) { - m_codeBlockForConstruct->clearEvalCache(); - m_codeBlockForConstruct.clear(); - } + m_codeBlockForCall.clear(); + m_codeBlockForConstruct.clear(); Base::clearCode(); } diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h index e999d3a08..e5f6de438 100644 --- a/Source/JavaScriptCore/runtime/Executable.h +++ b/Source/JavaScriptCore/runtime/Executable.h @@ -54,7 +54,8 @@ namespace JSC { return false; } - class ExecutableBase : public JSCell { + class ExecutableBase : public JSCell, public DoublyLinkedListNode<ExecutableBase> { + friend class WTF::DoublyLinkedListNode<ExecutableBase>; friend class JIT; protected: @@ -80,6 +81,11 @@ namespace JSC { static void destroy(JSCell*); #endif + bool isFunctionExecutable() + { + return structure()->typeInfo().type() == FunctionExecutableType; + } + bool isHostFunction() const { ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST)); @@ -88,6 +94,8 @@ namespace JSC { static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(CompoundType, StructureFlags), &s_info); } + void clearCode(); + static JS_EXPORTDATA const ClassInfo s_info; protected: @@ -95,8 +103,10 @@ namespace JSC { int m_numParametersForCall; int m_numParametersForConstruct; -#if ENABLE(JIT) public: + static void clearCodeVirtual(ExecutableBase*); + +#if ENABLE(JIT) JITCode& generatedJITCodeForCall() { ASSERT(m_jitCodeForCall); @@ -166,14 +176,18 @@ namespace JSC { return intrinsic(); return NoIntrinsic; } +#endif protected: + ExecutableBase* m_prev; + ExecutableBase* m_next; + +#if ENABLE(JIT) JITCode m_jitCodeForCall; JITCode m_jitCodeForConstruct; MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck; MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck; #endif - void clearCode(); }; class NativeExecutable : public ExecutableBase { @@ -194,7 +208,6 @@ namespace JSC { executable = new (NotNull, allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor); executable->finishCreation(globalData, JITCode::HostFunction(callThunk), JITCode::HostFunction(constructThunk), intrinsic); } - globalData.heap.addFinalizer(executable, &finalize); return executable; } #endif @@ -205,7 +218,6 @@ namespace JSC { ASSERT(!globalData.canUseJIT()); NativeExecutable* executable = new (NotNull, allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor); executable->finishCreation(globalData); - globalData.heap.addFinalizer(executable, &finalize); return executable; } #endif @@ -246,8 +258,6 @@ namespace JSC { } #endif - static void finalize(JSCell*); - private: NativeExecutable(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor) : ExecutableBase(globalData, globalData.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST) @@ -303,6 +313,8 @@ namespace JSC { void finishCreation(JSGlobalData& globalData) { Base::finishCreation(globalData); + globalData.heap.addCompiledCode(this); // Balanced by Heap::deleteUnmarkedCompiledCode(). + #if ENABLE(CODEBLOCK_SAMPLING) if (SamplingTool* sampler = globalData.interpreter->sampler()) sampler->notifyOfScope(globalData, this); @@ -358,7 +370,6 @@ namespace JSC { { EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext); executable->finishCreation(exec->globalData()); - exec->globalData().heap.addFinalizer(executable, &finalize); return executable; } @@ -377,9 +388,7 @@ namespace JSC { void unlinkCalls(); - protected: void clearCode(); - static void finalize(JSCell*); private: static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; @@ -400,7 +409,6 @@ namespace JSC { { ProgramExecutable* executable = new (NotNull, allocateCell<ProgramExecutable>(*exec->heap())) ProgramExecutable(exec, source); executable->finishCreation(exec->globalData()); - exec->globalData().heap.addFinalizer(executable, &finalize); return executable; } @@ -447,9 +455,7 @@ namespace JSC { void unlinkCalls(); - protected: void clearCode(); - static void finalize(JSCell*); private: static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; @@ -461,10 +467,9 @@ namespace JSC { OwnPtr<ProgramCodeBlock> m_programCodeBlock; }; - class FunctionExecutable : public ScriptExecutable, public DoublyLinkedListNode<FunctionExecutable> { + class FunctionExecutable : public ScriptExecutable { friend class JIT; friend class LLIntOffsetsExtractor; - friend class WTF::DoublyLinkedListNode<FunctionExecutable>; public: typedef ScriptExecutable Base; @@ -472,8 +477,6 @@ namespace JSC { { FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(*exec->heap())) FunctionExecutable(exec, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext); executable->finishCreation(exec->globalData(), name, firstLine, lastLine); - exec->globalData().heap.addFunctionExecutable(executable); - exec->globalData().heap.addFinalizer(executable, &finalize); return executable; } @@ -481,8 +484,6 @@ namespace JSC { { FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext); executable->finishCreation(globalData, name, firstLine, lastLine); - globalData.heap.addFunctionExecutable(executable); - globalData.heap.addFinalizer(executable, &finalize); return executable; } @@ -639,7 +640,7 @@ namespace JSC { UString paramString() const; SharedSymbolTable* symbolTable() const { return m_symbolTable; } - void discardCode(); + void clearCodeIfNotCompiling(); static void visitChildren(JSCell*, SlotVisitor&); static FunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception); static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) @@ -651,10 +652,9 @@ namespace JSC { void unlinkCalls(); - protected: void clearCode(); - static void finalize(JSCell*); + protected: void finishCreation(JSGlobalData& globalData, const Identifier& name, int firstLine, int lastLine) { Base::finishCreation(globalData); @@ -677,7 +677,18 @@ namespace JSC { ASSERT(kind == CodeForConstruct); return m_codeBlockForConstruct; } - + + bool isCompiling() + { +#if ENABLE(JIT) + if (!m_jitCodeForCall && m_codeBlockForCall) + return true; + if (!m_jitCodeForConstruct && m_codeBlockForConstruct) + return true; +#endif + return false; + } + static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; unsigned m_numCapturedVariables : 31; bool m_forceUsesArguments : 1; @@ -689,8 +700,6 @@ namespace JSC { Identifier m_inferredName; WriteBarrier<JSString> m_nameValue; SharedSymbolTable* m_symbolTable; - FunctionExecutable* m_next; - FunctionExecutable* m_prev; }; inline FunctionExecutable* JSFunction::jsExecutable() const @@ -725,6 +734,20 @@ namespace JSC { return function->nativeFunction() == nativeFunction; } + inline void ExecutableBase::clearCodeVirtual(ExecutableBase* executable) + { + switch (executable->structure()->typeInfo().type()) { + case EvalExecutableType: + return jsCast<EvalExecutable*>(executable)->clearCode(); + case ProgramExecutableType: + return jsCast<ProgramExecutable*>(executable)->clearCode(); + case FunctionExecutableType: + return jsCast<FunctionExecutable*>(executable)->clearCode(); + default: + return jsCast<NativeExecutable*>(executable)->clearCode(); + } + } + inline void ScriptExecutable::unlinkCalls() { switch (structure()->typeInfo().type()) { diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.cpp b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp index 6ec538f72..794d1545e 100644 --- a/Source/JavaScriptCore/runtime/GCActivityCallback.cpp +++ b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp @@ -29,28 +29,108 @@ #include "config.h" #include "GCActivityCallback.h" +#include "APIShims.h" +#include "Heap.h" +#include "JSGlobalData.h" +#include "JSLock.h" +#include "JSObject.h" +#include "ScopeChain.h" +#include <wtf/RetainPtr.h> +#include <wtf/WTFThreadData.h> + namespace JSC { -struct DefaultGCActivityCallbackPlatformData { -}; +#if USE(CF) + +const double gcTimeSlicePerMB = 0.01; // Percentage of CPU time we will spend to reclaim 1 MB +const double maxGCTimeSlice = 0.05; // The maximum amount of CPU time we want to use for opportunistic timer-triggered collections. +const double timerSlop = 2.0; // Fudge factor to avoid performance cost of resetting timer. +const double pagingTimeOut = 0.1; // Time in seconds to allow opportunistic timer to iterate over all blocks to see if the Heap is paged out. +const CFTimeInterval hour = 60 * 60; -DefaultGCActivityCallback::DefaultGCActivityCallback(Heap*) +DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) + : GCActivityCallback(heap->globalData(), CFRunLoopGetCurrent()) + , m_delay(s_decade) { } -DefaultGCActivityCallback::~DefaultGCActivityCallback() +DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap, CFRunLoopRef runLoop) + : GCActivityCallback(heap->globalData(), runLoop) + , m_delay(s_decade) { } -void DefaultGCActivityCallback::didAllocate(size_t) +void DefaultGCActivityCallback::doWork() +{ + Heap* heap = &m_globalData->heap; + if (!isEnabled()) + return; + + APIEntryShim shim(m_globalData); +#if !PLATFORM(IOS) + double startTime = WTF::monotonicallyIncreasingTime(); + if (heap->isPagedOut(startTime + pagingTimeOut)) { + heap->activityCallback()->cancel(); + heap->increaseLastGCLength(pagingTimeOut); + return; + } +#endif + heap->collectAllGarbage(); +} + +void DefaultGCActivityCallback::scheduleTimer(double newDelay) +{ + if (newDelay * timerSlop > m_delay) + return; + double delta = m_delay - newDelay; + m_delay = newDelay; + CFRunLoopTimerSetNextFireDate(m_timer.get(), CFRunLoopTimerGetNextFireDate(m_timer.get()) - delta); +} + +void DefaultGCActivityCallback::cancelTimer() +{ + m_delay = s_decade; + CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + s_decade); +} + +void DefaultGCActivityCallback::didAllocate(size_t bytes) { + // The first byte allocated in an allocation cycle will report 0 bytes to didAllocate. + // We pretend it's one byte so that we don't ignore this allocation entirely. + if (!bytes) + bytes = 1; + Heap* heap = static_cast<Heap*>(&m_globalData->heap); + double gcTimeSlice = std::min((static_cast<double>(bytes) / MB) * gcTimeSlicePerMB, maxGCTimeSlice); + double newDelay = heap->lastGCLength() / gcTimeSlice; + scheduleTimer(newDelay); } void DefaultGCActivityCallback::willCollect() { + cancelTimer(); +} + +void DefaultGCActivityCallback::cancel() +{ + cancelTimer(); +} + +#else + +DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) + : GCActivityCallback(heap->globalData()) +{ +} + +void DefaultGCActivityCallback::doWork() +{ } -void DefaultGCActivityCallback::synchronize() +void DefaultGCActivityCallback::didAllocate(size_t) +{ +} + +void DefaultGCActivityCallback::willCollect() { } @@ -58,5 +138,7 @@ void DefaultGCActivityCallback::cancel() { } +#endif + } diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.h b/Source/JavaScriptCore/runtime/GCActivityCallback.h index 32077f2b0..18bbd31e0 100644 --- a/Source/JavaScriptCore/runtime/GCActivityCallback.h +++ b/Source/JavaScriptCore/runtime/GCActivityCallback.h @@ -29,6 +29,7 @@ #ifndef GCActivityCallback_h #define GCActivityCallback_h +#include "HeapTimer.h" #include <wtf/OwnPtr.h> #include <wtf/PassOwnPtr.h> @@ -40,47 +41,54 @@ namespace JSC { class Heap; -class GCActivityCallback { +class GCActivityCallback : public HeapTimer { public: - virtual ~GCActivityCallback() { } virtual void didAllocate(size_t) { } virtual void willCollect() { } - virtual void synchronize() { } virtual void cancel() { } bool isEnabled() const { return m_enabled; } void setEnabled(bool enabled) { m_enabled = enabled; } protected: - GCActivityCallback() - : m_enabled(true) +#if USE(CF) + GCActivityCallback(JSGlobalData* globalData, CFRunLoopRef runLoop) + : HeapTimer(globalData, runLoop) + , m_enabled(true) + { + } +# else + GCActivityCallback(JSGlobalData* globalData) + : HeapTimer(globalData) + , m_enabled(true) { } +#endif bool m_enabled; }; -struct DefaultGCActivityCallbackPlatformData; - class DefaultGCActivityCallback : public GCActivityCallback { public: static PassOwnPtr<DefaultGCActivityCallback> create(Heap*); DefaultGCActivityCallback(Heap*); - virtual ~DefaultGCActivityCallback(); virtual void didAllocate(size_t); virtual void willCollect(); - virtual void synchronize(); virtual void cancel(); + + virtual void doWork(); #if USE(CF) protected: DefaultGCActivityCallback(Heap*, CFRunLoopRef); - void commonConstructor(Heap*, CFRunLoopRef); -#endif - + + void cancelTimer(); + void scheduleTimer(double); + private: - OwnPtr<DefaultGCActivityCallbackPlatformData> d; + double m_delay; +#endif }; inline PassOwnPtr<DefaultGCActivityCallback> DefaultGCActivityCallback::create(Heap* heap) diff --git a/Source/JavaScriptCore/runtime/GCActivityCallbackBlackBerry.cpp b/Source/JavaScriptCore/runtime/GCActivityCallbackBlackBerry.cpp new file mode 100644 index 000000000..3b0b5a751 --- /dev/null +++ b/Source/JavaScriptCore/runtime/GCActivityCallbackBlackBerry.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 Research In Motion Limited. 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 + */ + +#include "config.h" +#include "GCActivityCallback.h" + +#include "Heap.h" +#include <BlackBerryPlatformMemory.h> + +namespace JSC { + +DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) + : GCActivityCallback(heap->globalData()) +{ +} + +DefaultGCActivityCallback::doWork() +{ +} + +void DefaultGCActivityCallback::didAllocate(size_t bytesAllocated) +{ + if (!BlackBerry::Platform::isMemoryLow()) + return; + + if (bytesAllocated < 1 * 1024 * 1024) + return; + + if (m_globalData->heap.isBusy() || !m_globalData->heap.isSafeToCollect()) + return; + + m_globalData->heap.collect(Heap::DoNotSweep); +} + +void DefaultGCActivityCallback::willCollect() +{ +} + +void DefaultGCActivityCallback::cancel() +{ +} + +} diff --git a/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp b/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp deleted file mode 100644 index d82403a6b..000000000 --- a/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "GCActivityCallback.h" - -#include "APIShims.h" -#include "Heap.h" -#include "JSGlobalData.h" -#include "JSLock.h" -#include "JSObject.h" -#include "ScopeChain.h" -#include <wtf/RetainPtr.h> -#include <wtf/WTFThreadData.h> - -#if !USE(CF) -#error "This file should only be used on CF platforms." -#endif - -namespace JSC { - -struct DefaultGCActivityCallbackPlatformData { - static void timerDidFire(CFRunLoopTimerRef, void *info); - - RetainPtr<CFRunLoopTimerRef> timer; - RetainPtr<CFRunLoopRef> runLoop; - CFRunLoopTimerContext context; - double delay; -}; - -const double gcTimeSlicePerMB = 0.01; // Percentage of CPU time we will spend to reclaim 1 MB -const double maxGCTimeSlice = 0.05; // The maximum amount of CPU time we want to use for opportunistic timer-triggered collections. -const double timerSlop = 2.0; // Fudge factor to avoid performance cost of resetting timer. -const double pagingTimeOut = 0.1; // Time in seconds to allow opportunistic timer to iterate over all blocks to see if the Heap is paged out. -const CFTimeInterval decade = 60 * 60 * 24 * 365 * 10; -const CFTimeInterval hour = 60 * 60; - -void DefaultGCActivityCallbackPlatformData::timerDidFire(CFRunLoopTimerRef, void *info) -{ - Heap* heap = static_cast<Heap*>(info); - if (!heap->activityCallback()->isEnabled()) - return; - - APIEntryShim shim(heap->globalData()); -#if !PLATFORM(IOS) - double startTime = WTF::monotonicallyIncreasingTime(); - if (heap->isPagedOut(startTime + pagingTimeOut)) { - heap->activityCallback()->cancel(); - heap->increaseLastGCLength(pagingTimeOut); - return; - } -#endif - heap->collectAllGarbage(); -} - -DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) -{ - commonConstructor(heap, CFRunLoopGetCurrent()); -} - -DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap, CFRunLoopRef runLoop) -{ - commonConstructor(heap, runLoop); -} - -DefaultGCActivityCallback::~DefaultGCActivityCallback() -{ - CFRunLoopRemoveTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes); - CFRunLoopTimerInvalidate(d->timer.get()); -} - -void DefaultGCActivityCallback::commonConstructor(Heap* heap, CFRunLoopRef runLoop) -{ - d = adoptPtr(new DefaultGCActivityCallbackPlatformData); - - memset(&d->context, 0, sizeof(CFRunLoopTimerContext)); - d->context.info = heap; - d->runLoop = runLoop; - d->timer.adoptCF(CFRunLoopTimerCreate(0, decade, decade, 0, 0, DefaultGCActivityCallbackPlatformData::timerDidFire, &d->context)); - d->delay = decade; - CFRunLoopAddTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes); -} - -static void scheduleTimer(DefaultGCActivityCallbackPlatformData* d, double newDelay) -{ - if (newDelay * timerSlop > d->delay) - return; - double delta = d->delay - newDelay; - d->delay = newDelay; - CFRunLoopTimerSetNextFireDate(d->timer.get(), CFRunLoopTimerGetNextFireDate(d->timer.get()) - delta); -} - -static void cancelTimer(DefaultGCActivityCallbackPlatformData* d) -{ - d->delay = decade; - CFRunLoopTimerSetNextFireDate(d->timer.get(), CFAbsoluteTimeGetCurrent() + decade); -} - -void DefaultGCActivityCallback::didAllocate(size_t bytes) -{ - // The first byte allocated in an allocation cycle will report 0 bytes to didAllocate. - // We pretend it's one byte so that we don't ignore this allocation entirely. - if (!bytes) - bytes = 1; - Heap* heap = static_cast<Heap*>(d->context.info); - double gcTimeSlice = std::min((static_cast<double>(bytes) / MB) * gcTimeSlicePerMB, maxGCTimeSlice); - double newDelay = heap->lastGCLength() / gcTimeSlice; - scheduleTimer(d.get(), newDelay); -} - -void DefaultGCActivityCallback::willCollect() -{ - cancelTimer(d.get()); -} - -void DefaultGCActivityCallback::synchronize() -{ - if (CFRunLoopGetCurrent() == d->runLoop.get()) - return; - CFRunLoopRemoveTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes); - d->runLoop = CFRunLoopGetCurrent(); - CFRunLoopAddTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes); -} - -void DefaultGCActivityCallback::cancel() -{ - cancelTimer(d.get()); -} - -} diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp index 9e7aaba51..96cc44780 100644 --- a/Source/JavaScriptCore/runtime/JSArray.cpp +++ b/Source/JavaScriptCore/runtime/JSArray.cpp @@ -1371,6 +1371,8 @@ void JSArray::visitChildren(JSCell* cell, SlotVisitor& visitor) JSNonFinalObject::visitChildren(thisObject, visitor); if (thisObject->m_storage) { + MARK_LOG_MESSAGE1("[%u]: ", thisObject->length()); + ArrayStorage* storage = thisObject->m_storage; void* baseStorage = storage->m_allocBase; diff --git a/Source/JavaScriptCore/runtime/JSCell.cpp b/Source/JavaScriptCore/runtime/JSCell.cpp index 06c1f7c4d..61e8549ee 100644 --- a/Source/JavaScriptCore/runtime/JSCell.cpp +++ b/Source/JavaScriptCore/runtime/JSCell.cpp @@ -184,6 +184,11 @@ UString JSCell::className(const JSObject*) return UString(); } +const char* JSCell::className() +{ + return classInfo()->className; +} + void JSCell::getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode) { ASSERT_NOT_REACHED(); diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h index 0233f0fec..cdd409706 100644 --- a/Source/JavaScriptCore/runtime/JSCell.h +++ b/Source/JavaScriptCore/runtime/JSCell.h @@ -84,6 +84,8 @@ namespace JSC { void setStructure(JSGlobalData&, Structure*); void clearStructure() { m_structure.clear(); } + const char* className(); + // Extracting the value. JS_EXPORT_PRIVATE bool getString(ExecState* exec, UString&) const; JS_EXPORT_PRIVATE UString getString(ExecState* exec) const; // null string if not a string @@ -197,6 +199,8 @@ namespace JSC { inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor) { + MARK_LOG_PARENT(visitor, cell); + visitor.append(&cell->m_structure); } diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp index a13eb79c5..1fb90df40 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp @@ -54,6 +54,7 @@ #include "RegExpObject.h" #include "StrictEvalActivation.h" #include "StrongInlines.h" +#include <wtf/RetainPtr.h> #include <wtf/Threading.h> #include <wtf/WTFThreadData.h> @@ -100,13 +101,10 @@ static bool enableAssembler(ExecutableAllocator& executableAllocator) return false; #if USE(CF) - CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman); - CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication); - if (canUseJIT) { - return kCFBooleanTrue == canUseJIT; - CFRelease(canUseJIT); - } - CFRelease(canUseJITKey); + RetainPtr<CFStringRef> canUseJITKey(AdoptCF, CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman)); + RetainPtr<CFBooleanRef> canUseJIT(AdoptCF, (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey.get(), kCFPreferencesCurrentApplication)); + if (canUseJIT) + return kCFBooleanTrue == canUseJIT.get(); #endif #if USE(CF) || OS(UNIX) @@ -159,6 +157,7 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread , dynamicGlobalObject(0) , cachedUTCOffset(std::numeric_limits<double>::quiet_NaN()) , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth) + , m_enabledProfiler(0) , m_regExpCache(new RegExpCache(this)) #if ENABLE(REGEXP_TRACING) , m_rtTraceList(new RTTraceList()) @@ -418,7 +417,7 @@ struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor { FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell); if (currentlyExecutingFunctions.contains(executable)) return; - executable->discardCode(); + executable->clearCodeIfNotCompiling(); } }; diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h index c39a01920..f8833104a 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.h +++ b/Source/JavaScriptCore/runtime/JSGlobalData.h @@ -70,6 +70,7 @@ namespace JSC { class LLIntOffsetsExtractor; class NativeExecutable; class ParserArena; + class Profiler; class RegExpCache; class Stringifier; class Structure; @@ -255,6 +256,11 @@ namespace JSC { return m_inDefineOwnProperty; } + Profiler* enabledProfiler() + { + return m_enabledProfiler; + } + #if ENABLE(ASSEMBLER) ExecutableAllocator executableAllocator; #endif @@ -346,6 +352,7 @@ namespace JSC { int maxReentryDepth; + Profiler* m_enabledProfiler; RegExpCache* m_regExpCache; BumpPointerAllocator m_regExpAllocator; diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index 86186b7e1..7b6109599 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -79,7 +79,7 @@ namespace JSC { -const ClassInfo JSGlobalObject::s_info = { "GlobalObject", &JSVariableObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(JSGlobalObject) }; +const ClassInfo JSGlobalObject::s_info = { "GlobalObject", &JSSegmentedVariableObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(JSGlobalObject) }; const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled }; @@ -119,10 +119,8 @@ JSGlobalObject::~JSGlobalObject() if (m_debugger) m_debugger->detach(this); - Profiler** profiler = Profiler::enabledProfilerReference(); - if (UNLIKELY(*profiler != 0)) { - (*profiler)->stopProfiling(this); - } + if (Profiler* profiler = globalData().enabledProfiler()) + profiler->stopProfiling(this); } void JSGlobalObject::destroy(JSCell* cell) @@ -150,9 +148,9 @@ void JSGlobalObject::put(JSCell* cell, ExecState* exec, PropertyName propertyNam JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); - if (thisObject->symbolTablePut(exec, propertyName, value, slot.isStrictMode())) + if (symbolTablePut(thisObject, exec, propertyName, value, slot.isStrictMode())) return; - JSVariableObject::put(thisObject, exec, propertyName, value, slot); + JSSegmentedVariableObject::put(thisObject, exec, propertyName, value, slot); } void JSGlobalObject::putDirectVirtual(JSObject* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes) @@ -160,12 +158,12 @@ void JSGlobalObject::putDirectVirtual(JSObject* object, ExecState* exec, Propert JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); - if (thisObject->symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes)) + if (symbolTablePutWithAttributes(thisObject, exec->globalData(), propertyName, value, attributes)) return; JSValue valueBefore = thisObject->getDirect(exec->globalData(), propertyName); PutPropertySlot slot; - JSVariableObject::put(thisObject, exec, propertyName, value, slot); + JSSegmentedVariableObject::put(thisObject, exec, propertyName, value, slot); if (!valueBefore) { JSValue valueAfter = thisObject->getDirect(exec->globalData(), propertyName); if (valueAfter) @@ -178,7 +176,7 @@ bool JSGlobalObject::defineOwnProperty(JSObject* object, ExecState* exec, Proper JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object); PropertySlot slot; // silently ignore attempts to add accessors aliasing vars. - if (descriptor.isAccessorDescriptor() && thisObject->symbolTableGet(propertyName, slot)) + if (descriptor.isAccessorDescriptor() && symbolTableGet(thisObject, propertyName, slot)) return false; return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow); } @@ -347,7 +345,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - JSVariableObject::visitChildren(thisObject, visitor); + JSSegmentedVariableObject::visitChildren(thisObject, visitor); visitIfNeeded(visitor, &thisObject->m_globalScopeChain); visitIfNeeded(visitor, &thisObject->m_methodCallDummy); @@ -395,17 +393,6 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) visitIfNeeded(visitor, &thisObject->m_regExpStructure); visitIfNeeded(visitor, &thisObject->m_stringObjectStructure); visitIfNeeded(visitor, &thisObject->m_internalFunctionStructure); - - if (thisObject->m_registerArray) { - // Outside the execution of global code, when our variables are torn off, - // we can mark the torn-off array. - visitor.appendValues(thisObject->m_registerArray.get(), thisObject->m_registerArraySize); - } else if (thisObject->m_registers) { - // During execution of global code, when our variables are in the register file, - // the symbol table tells us how many variables there are, and registers - // points to where they end, and the registers used for execution begin. - visitor.appendValues(thisObject->m_registers - thisObject->symbolTable().size(), thisObject->symbolTable().size()); - } } ExecState* JSGlobalObject::globalExec() @@ -413,26 +400,9 @@ ExecState* JSGlobalObject::globalExec() return CallFrame::create(m_globalCallFrame + RegisterFile::CallFrameHeaderSize); } -void JSGlobalObject::resizeRegisters(size_t newSize) -{ - // Previous duplicate symbols may have created spare capacity in m_registerArray. - if (newSize <= m_registerArraySize) - return; - - size_t oldSize = m_registerArraySize; - OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[newSize]); - for (size_t i = 0; i < oldSize; ++i) - registerArray[i].set(globalData(), this, m_registerArray[i].get()); - for (size_t i = oldSize; i < newSize; ++i) - registerArray[i].setUndefined(); - - WriteBarrier<Unknown>* registers = registerArray.get(); - setRegisters(registers, registerArray.release(), newSize); -} - void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count) { - resizeRegisters(symbolTable().size() + count); + addRegisters(count); for (int i = 0; i < count; ++i) { GlobalPropertyInfo& global = globals[i]; @@ -448,17 +418,17 @@ void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count) bool JSGlobalObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell); - if (getStaticFunctionSlot<JSVariableObject>(exec, ExecState::globalObjectTable(exec), thisObject, propertyName, slot)) + if (getStaticFunctionSlot<JSSegmentedVariableObject>(exec, ExecState::globalObjectTable(exec), thisObject, propertyName, slot)) return true; - return thisObject->symbolTableGet(propertyName, slot); + return symbolTableGet(thisObject, propertyName, slot); } bool JSGlobalObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor) { JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object); - if (getStaticFunctionDescriptor<JSVariableObject>(exec, ExecState::globalObjectTable(exec), thisObject, propertyName, descriptor)) + if (getStaticFunctionDescriptor<JSSegmentedVariableObject>(exec, ExecState::globalObjectTable(exec), thisObject, propertyName, descriptor)) return true; - return thisObject->symbolTableGet(propertyName, descriptor); + return symbolTableGet(thisObject, propertyName, descriptor); } void JSGlobalObject::clearRareData(JSCell* cell) @@ -473,7 +443,7 @@ DynamicGlobalObjectScope::DynamicGlobalObjectScope(JSGlobalData& globalData, JSG if (!m_dynamicGlobalObjectSlot) { #if ENABLE(ASSEMBLER) if (ExecutableAllocator::underMemoryPressure()) - globalData.heap.discardAllCompiledCode(); + globalData.heap.deleteAllCompiledCode(); #endif m_dynamicGlobalObjectSlot = dynamicGlobalObject; diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h index 1e75b7267..2396142b1 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h @@ -25,7 +25,7 @@ #include "JSArray.h" #include "JSGlobalData.h" #include "JSGlobalThis.h" -#include "JSVariableObject.h" +#include "JSSegmentedVariableObject.h" #include "JSWeakObjectMapRefInternal.h" #include "NumberPrototype.h" #include "StringPrototype.h" @@ -74,7 +74,7 @@ namespace JSC { JavaScriptExperimentsEnabledFunctionPtr javaScriptExperimentsEnabled; }; - class JSGlobalObject : public JSVariableObject { + class JSGlobalObject : public JSSegmentedVariableObject { private: typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet; @@ -90,7 +90,6 @@ namespace JSC { protected: - size_t m_registerArraySize; Register m_globalCallFrame[RegisterFile::CallFrameHeaderSize]; WriteBarrier<ScopeChainNode> m_globalScopeChain; @@ -164,7 +163,7 @@ namespace JSC { } public: - typedef JSVariableObject Base; + typedef JSSegmentedVariableObject Base; static JSGlobalObject* create(JSGlobalData& globalData, Structure* structure) { @@ -177,8 +176,7 @@ namespace JSC { protected: explicit JSGlobalObject(JSGlobalData& globalData, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable = 0) - : JSVariableObject(globalData, structure, &m_symbolTable, 0) - , m_registerArraySize(0) + : JSSegmentedVariableObject(globalData, structure, &m_symbolTable) , m_globalScopeChain() , m_weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0))) , m_evalEnabled(true) @@ -308,8 +306,6 @@ namespace JSC { void setEvalEnabled(bool enabled) { m_evalEnabled = enabled; } bool evalEnabled() { return m_evalEnabled; } - void resizeRegisters(size_t newSize); - void resetPrototype(JSGlobalData&, JSValue prototype); JSGlobalData& globalData() const { return *Heap::heap(this)->globalData(); } @@ -334,7 +330,7 @@ namespace JSC { double weakRandomNumber() { return m_weakRandom.get(); } protected: - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags; + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSSegmentedVariableObject::StructureFlags; struct GlobalPropertyInfo { GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a) @@ -359,7 +355,6 @@ namespace JSC { void createThrowTypeError(ExecState*); - void setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray, size_t count); JS_EXPORT_PRIVATE static void clearRareData(JSCell*); }; @@ -371,19 +366,13 @@ namespace JSC { return jsCast<JSGlobalObject*>(asObject(value)); } - inline void JSGlobalObject::setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray, size_t count) - { - JSVariableObject::setRegisters(registers, registerArray); - m_registerArraySize = count; - } - inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, PropertyName propertyName) { PropertySlot slot; - if (JSVariableObject::getOwnPropertySlot(this, exec, propertyName, slot)) + if (JSSegmentedVariableObject::getOwnPropertySlot(this, exec, propertyName, slot)) return true; bool slotIsWriteable; - return symbolTableGet(propertyName, slot, slotIsWriteable); + return symbolTableGet(this, propertyName, slot, slotIsWriteable); } inline bool JSGlobalObject::symbolTableHasProperty(PropertyName propertyName) @@ -392,13 +381,18 @@ namespace JSC { return !entry.isNull(); } - inline JSValue Structure::prototypeForLookup(ExecState* exec) const + inline JSValue Structure::prototypeForLookup(JSGlobalObject* globalObject) const { if (isObject()) return m_prototype.get(); ASSERT(typeInfo().type() == StringType); - return exec->lexicalGlobalObject()->stringPrototype(); + return globalObject->stringPrototype(); + } + + inline JSValue Structure::prototypeForLookup(ExecState* exec) const + { + return prototypeForLookup(exec->lexicalGlobalObject()); } inline StructureChain* Structure::prototypeChain(ExecState* exec) const diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index 8d9e4a96b..aa71b8a7b 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -56,7 +56,7 @@ const ClassInfo JSObject::s_info = { "Object", 0, 0, 0, CREATE_METHOD_TABLE(JSOb const ClassInfo JSFinalObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFinalObject) }; -static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode) +static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode, bool didReify) { // Add properties from the static hashtables of properties for (; classInfo; classInfo = classInfo->parentClass) { @@ -69,7 +69,7 @@ static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* class int hashSizeMask = table->compactSize - 1; const HashEntry* entry = table->table; for (int i = 0; i <= hashSizeMask; ++i, ++entry) { - if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties))) + if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties)) && !((entry->attributes() & Function) && didReify)) propertyNames.add(entry->key()); } } @@ -417,9 +417,8 @@ void JSObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameA void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { + getClassPropertyNames(exec, object->classInfo(), propertyNames, mode, object->staticFunctionsReified()); object->structure()->getPropertyNamesFromStructure(exec->globalData(), propertyNames, mode); - if (!object->staticFunctionsReified()) - getClassPropertyNames(exec, object->classInfo(), propertyNames, mode); } double JSObject::toNumber(ExecState* exec) const @@ -505,22 +504,25 @@ void JSObject::reifyStaticFunctionsForDelete(ExecState* exec) structure()->setStaticFunctionsReified(); } -void JSObject::removeDirect(JSGlobalData& globalData, PropertyName propertyName) +bool JSObject::removeDirect(JSGlobalData& globalData, PropertyName propertyName) { if (structure()->get(globalData, propertyName) == WTF::notFound) - return; + return false; size_t offset; if (structure()->isUncacheableDictionary()) { offset = structure()->removePropertyWithoutTransition(globalData, propertyName); - if (offset != WTF::notFound) - putUndefinedAtDirectOffset(offset); - return; + if (offset == WTF::notFound) + return false; + putUndefinedAtDirectOffset(offset); + return true; } setStructure(globalData, Structure::removePropertyTransition(globalData, structure(), propertyName, offset)); - if (offset != WTF::notFound) - putUndefinedAtDirectOffset(offset); + if (offset == WTF::notFound) + return false; + putUndefinedAtDirectOffset(offset); + return true; } NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, WriteBarrierBase<Unknown>* location) diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index 67aa1516c..ac8601deb 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -176,7 +176,7 @@ namespace JSC { void transitionTo(JSGlobalData&, Structure*); - void removeDirect(JSGlobalData&, PropertyName); + bool removeDirect(JSGlobalData&, PropertyName); // Return true if anything is removed. bool hasCustomProperties() { return structure()->didTransition(); } bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); } diff --git a/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp new file mode 100644 index 000000000..c65d2b1b9 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSSegmentedVariableObject.h" + +namespace JSC { + +int JSSegmentedVariableObject::findRegisterIndex(void* registerAddress) +{ + for (int i = m_registers.size(); i--;) { + if (&m_registers[i] != registerAddress) + continue; + return i; + } + CRASH(); + return -1; +} + +int JSSegmentedVariableObject::addRegisters(int numberOfRegistersToAdd) +{ + ASSERT(numberOfRegistersToAdd >= 0); + + size_t oldSize = m_registers.size(); + m_registers.grow(oldSize + numberOfRegistersToAdd); + + for (size_t i = numberOfRegistersToAdd; i--;) + m_registers[oldSize + i].setWithoutWriteBarrier(jsUndefined()); + + return static_cast<int>(oldSize); +} + +void JSSegmentedVariableObject::visitChildren(JSCell* cell, SlotVisitor& slotVisitor) +{ + JSSegmentedVariableObject* thisObject = jsCast<JSSegmentedVariableObject*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + JSSymbolTableObject::visitChildren(thisObject, slotVisitor); + + for (unsigned i = thisObject->m_registers.size(); i--;) + slotVisitor.append(&thisObject->m_registers[i]); +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h new file mode 100644 index 000000000..f1fe0483d --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSSegmentedVariableObject_h +#define JSSegmentedVariableObject_h + +#include "JSObject.h" +#include "JSSymbolTableObject.h" +#include "Register.h" +#include "SymbolTable.h" +#include <wtf/OwnArrayPtr.h> +#include <wtf/SegmentedVector.h> +#include <wtf/UnusedParam.h> + +namespace JSC { + +class LLIntOffsetsExtractor; +class Register; + +// This is a mostly drop-in replacement for JSVariableObject, except that it preserves +// the invariant that after a variable is created, its address in memory will not change +// so long as the JSSegmentedVariableObject is alive. This allows optimizations based +// on getting the address of the variable and remembering it. As well, unlike a +// JSVariableObject, this will manage the memory for the registers itself and neither +// requires nor allows for the subclasses to manage that memory. Finally, +// JSSegmentedVariableObject has its own GC tracing functionality, since it knows the +// exact dimensions of the variables array at all times. + +class JSSegmentedVariableObject : public JSSymbolTableObject { + friend class JIT; + friend class LLIntOffsetsExtractor; + +public: + typedef JSSymbolTableObject Base; + + WriteBarrier<Unknown>& registerAt(int index) { return m_registers[index]; } + + // This is a slow method call, which searches the register bank to find the index + // given a pointer. It will CRASH() if it does not find the register. Only use this + // in debug code (like bytecode dumping). + JS_EXPORT_PRIVATE int findRegisterIndex(void*); + + WriteBarrier<Unknown>* assertRegisterIsInThisObject(WriteBarrier<Unknown>* registerPointer) + { +#if !ASSERT_DISABLED + findRegisterIndex(registerPointer); +#endif + return registerPointer; + } + + // Adds numberOfRegistersToAdd registers, initializes them to Undefined, and returns + // the index of the first one added. + JS_EXPORT_PRIVATE int addRegisters(int numberOfRegistersToAdd); + + JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); + +protected: + static const unsigned StructureFlags = OverridesVisitChildren | JSSymbolTableObject::StructureFlags; + + JSSegmentedVariableObject(JSGlobalData& globalData, Structure* structure, SymbolTable* symbolTable) + : JSSymbolTableObject(globalData, structure, symbolTable) + { + } + + void finishCreation(JSGlobalData& globalData) + { + Base::finishCreation(globalData); + } + + SegmentedVector<WriteBarrier<Unknown>, 16> m_registers; +}; + +} // namespace JSC + +#endif // JSSegmentedVariableObject_h + diff --git a/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp b/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp index e5e65673c..14187f422 100644 --- a/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp +++ b/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp @@ -66,13 +66,13 @@ void JSStaticScopeObject::put(JSCell* cell, ExecState* exec, PropertyName proper // a pointer compare. PropertySlot slot; bool isWritable = true; - thisObject->symbolTableGet(propertyName, slot, isWritable); + symbolTableGet(thisObject, propertyName, slot, isWritable); if (!isWritable) { throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError)); return; } } - if (thisObject->symbolTablePut(exec, propertyName, value, slot.isStrictMode())) + if (symbolTablePut(thisObject, exec, propertyName, value, slot.isStrictMode())) return; ASSERT_NOT_REACHED(); @@ -81,7 +81,7 @@ void JSStaticScopeObject::put(JSCell* cell, ExecState* exec, PropertyName proper void JSStaticScopeObject::putDirectVirtual(JSObject* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes) { JSStaticScopeObject* thisObject = jsCast<JSStaticScopeObject*>(object); - if (thisObject->symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes)) + if (symbolTablePutWithAttributes(thisObject, exec->globalData(), propertyName, value, attributes)) return; ASSERT_NOT_REACHED(); @@ -89,7 +89,7 @@ void JSStaticScopeObject::putDirectVirtual(JSObject* object, ExecState* exec, Pr bool JSStaticScopeObject::getOwnPropertySlot(JSCell* cell, ExecState*, PropertyName propertyName, PropertySlot& slot) { - return jsCast<JSStaticScopeObject*>(cell)->symbolTableGet(propertyName, slot); + return symbolTableGet(jsCast<JSStaticScopeObject*>(cell), propertyName, slot); } } diff --git a/Source/JavaScriptCore/runtime/JSString.cpp b/Source/JavaScriptCore/runtime/JSString.cpp index 180c64b8b..4eb2a5297 100644 --- a/Source/JavaScriptCore/runtime/JSString.cpp +++ b/Source/JavaScriptCore/runtime/JSString.cpp @@ -56,6 +56,19 @@ void JSString::visitChildren(JSCell* cell, SlotVisitor& visitor) JSString* thisObject = jsCast<JSString*>(cell); Base::visitChildren(thisObject, visitor); + MARK_LOG_MESSAGE1("[%u]: ", thisObject->length()); + +#if ENABLE(OBJECT_MARK_LOGGING) + if (!thisObject->isRope()) { + WTF::StringImpl* ourImpl = thisObject->m_value.impl(); + if (ourImpl->is8Bit()) + MARK_LOG_MESSAGE1("[8 %p]", ourImpl->characters8()); + else + MARK_LOG_MESSAGE1("[16 %p]", ourImpl->characters16()); + } else + MARK_LOG_MESSAGE0("[rope]: "); +#endif + if (thisObject->isRope()) static_cast<JSRopeString*>(thisObject)->visitFibers(visitor); } diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h index 111853c39..4fb157c8b 100644 --- a/Source/JavaScriptCore/runtime/JSString.h +++ b/Source/JavaScriptCore/runtime/JSString.h @@ -67,6 +67,7 @@ namespace JSC { friend class JSGlobalData; friend class SpecializedThunkJIT; friend class JSRopeString; + friend class SlotVisitor; friend struct ThunkHelpers; typedef JSCell Base; diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp new file mode 100644 index 000000000..927ad25cf --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSSymbolTableObject.h" + +#include "JSActivation.h" +#include "JSGlobalObject.h" +#include "JSStaticScopeObject.h" +#include "PropertyNameArray.h" + +namespace JSC { + +void JSSymbolTableObject::destroy(JSCell* cell) +{ + static_cast<JSSymbolTableObject*>(cell)->JSSymbolTableObject::~JSSymbolTableObject(); +} + +bool JSSymbolTableObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) +{ + JSSymbolTableObject* thisObject = jsCast<JSSymbolTableObject*>(cell); + if (thisObject->symbolTable().contains(propertyName.publicName())) + return false; + + return JSObject::deleteProperty(thisObject, exec, propertyName); +} + +void JSSymbolTableObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +{ + JSSymbolTableObject* thisObject = jsCast<JSSymbolTableObject*>(object); + SymbolTable::const_iterator end = thisObject->symbolTable().end(); + for (SymbolTable::const_iterator it = thisObject->symbolTable().begin(); it != end; ++it) { + if (!(it->second.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties)) + propertyNames.add(Identifier(exec, it->first.get())); + } + + JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode); +} + +void JSSymbolTableObject::putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned) +{ + ASSERT_NOT_REACHED(); +} + +bool JSSymbolTableObject::isDynamicScope(bool& requiresDynamicChecks) const +{ + switch (structure()->typeInfo().type()) { + case GlobalObjectType: + return static_cast<const JSGlobalObject*>(this)->isDynamicScope(requiresDynamicChecks); + case ActivationObjectType: + return static_cast<const JSActivation*>(this)->isDynamicScope(requiresDynamicChecks); + case StaticScopeObjectType: + return static_cast<const JSStaticScopeObject*>(this)->isDynamicScope(requiresDynamicChecks); + default: + ASSERT_NOT_REACHED(); + break; + } + + return false; +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h new file mode 100644 index 000000000..2bbe21d06 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSSymbolTableObject_h +#define JSSymbolTableObject_h + +#include "JSObject.h" +#include "PropertyDescriptor.h" +#include "SymbolTable.h" + +namespace JSC { + +class JSSymbolTableObject : public JSNonFinalObject { +public: + typedef JSNonFinalObject Base; + + SymbolTable& symbolTable() const { return *m_symbolTable; } + + JS_EXPORT_PRIVATE static void destroy(JSCell*); + + static NO_RETURN_DUE_TO_ASSERT void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); + + JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName); + JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + + bool isDynamicScope(bool& requiresDynamicChecks) const; + +protected: + static const unsigned StructureFlags = OverridesGetPropertyNames | JSNonFinalObject::StructureFlags; + + JSSymbolTableObject(JSGlobalData& globalData, Structure* structure, SymbolTable* symbolTable) + : JSNonFinalObject(globalData, structure) + , m_symbolTable(symbolTable) + { + } + + void finishCreation(JSGlobalData& globalData) + { + Base::finishCreation(globalData); + ASSERT(m_symbolTable); + } + + SymbolTable* m_symbolTable; +}; + +template<typename SymbolTableObjectType> +inline bool symbolTableGet( + SymbolTableObjectType* object, PropertyName propertyName, PropertySlot& slot) +{ + SymbolTable& symbolTable = object->symbolTable(); + SymbolTable::iterator iter = symbolTable.find(propertyName.publicName()); + if (iter == symbolTable.end()) + return false; + SymbolTableEntry::Fast entry = iter->second; + ASSERT(!entry.isNull()); + slot.setValue(object->registerAt(entry.getIndex()).get()); + return true; +} + +template<typename SymbolTableObjectType> +inline bool symbolTableGet( + SymbolTableObjectType* object, PropertyName propertyName, PropertyDescriptor& descriptor) +{ + SymbolTable& symbolTable = object->symbolTable(); + SymbolTable::iterator iter = symbolTable.find(propertyName.publicName()); + if (iter == symbolTable.end()) + return false; + SymbolTableEntry::Fast entry = iter->second; + ASSERT(!entry.isNull()); + descriptor.setDescriptor( + object->registerAt(entry.getIndex()).get(), entry.getAttributes() | DontDelete); + return true; +} + +template<typename SymbolTableObjectType> +inline bool symbolTableGet( + SymbolTableObjectType* object, PropertyName propertyName, PropertySlot& slot, + bool& slotIsWriteable) +{ + SymbolTable& symbolTable = object->symbolTable(); + SymbolTable::iterator iter = symbolTable.find(propertyName.publicName()); + if (iter == symbolTable.end()) + return false; + SymbolTableEntry::Fast entry = iter->second; + ASSERT(!entry.isNull()); + slot.setValue(object->registerAt(entry.getIndex()).get()); + slotIsWriteable = !entry.isReadOnly(); + return true; +} + +template<typename SymbolTableObjectType> +inline bool symbolTablePut( + SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value, + bool shouldThrow) +{ + JSGlobalData& globalData = exec->globalData(); + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); + + SymbolTable& symbolTable = object->symbolTable(); + SymbolTable::iterator iter = symbolTable.find(propertyName.publicName()); + if (iter == symbolTable.end()) + return false; + bool wasFat; + SymbolTableEntry::Fast fastEntry = iter->second.getFast(wasFat); + ASSERT(!fastEntry.isNull()); + if (fastEntry.isReadOnly()) { + if (shouldThrow) + throwTypeError(exec, StrictModeReadonlyPropertyWriteError); + return true; + } + if (UNLIKELY(wasFat)) + iter->second.notifyWrite(); + object->registerAt(fastEntry.getIndex()).set(globalData, object, value); + return true; +} + +template<typename SymbolTableObjectType> +inline bool symbolTablePutWithAttributes( + SymbolTableObjectType* object, JSGlobalData& globalData, PropertyName propertyName, + JSValue value, unsigned attributes) +{ + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); + + SymbolTable::iterator iter = object->symbolTable().find(propertyName.publicName()); + if (iter == object->symbolTable().end()) + return false; + SymbolTableEntry& entry = iter->second; + ASSERT(!entry.isNull()); + entry.notifyWrite(); + entry.setAttributes(attributes); + object->registerAt(entry.getIndex()).set(globalData, object, value); + return true; +} + +} // namespace JSC + +#endif // JSSymbolTableObject_h + diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.cpp b/Source/JavaScriptCore/runtime/JSVariableObject.cpp index 9dcbead34..7210c9b90 100644 --- a/Source/JavaScriptCore/runtime/JSVariableObject.cpp +++ b/Source/JavaScriptCore/runtime/JSVariableObject.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,12 +29,6 @@ #include "config.h" #include "JSVariableObject.h" -#include "JSActivation.h" -#include "JSGlobalObject.h" -#include "JSStaticScopeObject.h" -#include "PropertyNameArray.h" -#include "PropertyDescriptor.h" - namespace JSC { void JSVariableObject::destroy(JSCell* cell) @@ -42,57 +36,4 @@ void JSVariableObject::destroy(JSCell* cell) static_cast<JSVariableObject*>(cell)->JSVariableObject::~JSVariableObject(); } -bool JSVariableObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) -{ - JSVariableObject* thisObject = jsCast<JSVariableObject*>(cell); - if (thisObject->symbolTable().contains(propertyName.publicName())) - return false; - - return JSObject::deleteProperty(thisObject, exec, propertyName); -} - -void JSVariableObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) -{ - JSVariableObject* thisObject = jsCast<JSVariableObject*>(object); - SymbolTable::const_iterator end = thisObject->symbolTable().end(); - for (SymbolTable::const_iterator it = thisObject->symbolTable().begin(); it != end; ++it) { - if (!(it->second.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties)) - propertyNames.add(Identifier(exec, it->first.get())); - } - - JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode); -} - -bool JSVariableObject::symbolTableGet(PropertyName propertyName, PropertyDescriptor& descriptor) -{ - SymbolTableEntry entry = symbolTable().inlineGet(propertyName.publicName()); - if (!entry.isNull()) { - descriptor.setDescriptor(registerAt(entry.getIndex()).get(), entry.getAttributes() | DontDelete); - return true; - } - return false; -} - -void JSVariableObject::putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned) -{ - ASSERT_NOT_REACHED(); -} - -bool JSVariableObject::isDynamicScope(bool& requiresDynamicChecks) const -{ - switch (structure()->typeInfo().type()) { - case GlobalObjectType: - return static_cast<const JSGlobalObject*>(this)->isDynamicScope(requiresDynamicChecks); - case ActivationObjectType: - return static_cast<const JSActivation*>(this)->isDynamicScope(requiresDynamicChecks); - case StaticScopeObjectType: - return static_cast<const JSStaticScopeObject*>(this)->isDynamicScope(requiresDynamicChecks); - default: - ASSERT_NOT_REACHED(); - break; - } - - return false; -} - } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.h b/Source/JavaScriptCore/runtime/JSVariableObject.h index ea2798457..46fe72684 100644 --- a/Source/JavaScriptCore/runtime/JSVariableObject.h +++ b/Source/JavaScriptCore/runtime/JSVariableObject.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,6 +30,7 @@ #define JSVariableObject_h #include "JSObject.h" +#include "JSSymbolTableObject.h" #include "Register.h" #include "SymbolTable.h" #include <wtf/UnusedParam.h> @@ -41,40 +42,25 @@ namespace JSC { class LLIntOffsetsExtractor; class Register; - class JSVariableObject : public JSNonFinalObject { + class JSVariableObject : public JSSymbolTableObject { friend class JIT; friend class LLIntOffsetsExtractor; public: - typedef JSNonFinalObject Base; - - SymbolTable& symbolTable() const { return *m_symbolTable; } - - JS_EXPORT_PRIVATE static void destroy(JSCell*); - - static NO_RETURN_DUE_TO_ASSERT void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); - - JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName); - JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - - bool isDynamicScope(bool& requiresDynamicChecks) const; + typedef JSSymbolTableObject Base; WriteBarrier<Unknown>& registerAt(int index) const { return m_registers[index]; } WriteBarrier<Unknown>* const * addressOfRegisters() const { return &m_registers; } static size_t offsetOfRegisters() { return OBJECT_OFFSETOF(JSVariableObject, m_registers); } - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(globalData, globalObject, prototype, TypeInfo(VariableObjectType, StructureFlags), &s_info); - } - + JS_EXPORT_PRIVATE static void destroy(JSCell*); + protected: - static const unsigned StructureFlags = OverridesGetPropertyNames | JSNonFinalObject::StructureFlags; + static const unsigned StructureFlags = JSSymbolTableObject::StructureFlags; JSVariableObject(JSGlobalData& globalData, Structure* structure, SymbolTable* symbolTable, Register* registers) - : JSNonFinalObject(globalData, structure) - , m_symbolTable(symbolTable) + : JSSymbolTableObject(globalData, structure, symbolTable) , m_registers(reinterpret_cast<WriteBarrier<Unknown>*>(registers)) { } @@ -82,76 +68,16 @@ namespace JSC { void finishCreation(JSGlobalData& globalData) { Base::finishCreation(globalData); - ASSERT(m_symbolTable); COMPILE_ASSERT(sizeof(WriteBarrier<Unknown>) == sizeof(Register), Register_should_be_same_size_as_WriteBarrier); } PassOwnArrayPtr<WriteBarrier<Unknown> > copyRegisterArray(JSGlobalData&, WriteBarrier<Unknown>* src, size_t count, size_t callframeStarts); void setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray); - bool symbolTableGet(PropertyName, PropertySlot&); - JS_EXPORT_PRIVATE bool symbolTableGet(PropertyName, PropertyDescriptor&); - bool symbolTableGet(PropertyName, PropertySlot&, bool& slotIsWriteable); - bool symbolTablePut(ExecState*, PropertyName, JSValue, bool shouldThrow); - bool symbolTablePutWithAttributes(JSGlobalData&, PropertyName, JSValue, unsigned attributes); - - SymbolTable* m_symbolTable; // Maps name -> offset from "r" in register file. WriteBarrier<Unknown>* m_registers; // "r" in the register file. OwnArrayPtr<WriteBarrier<Unknown> > m_registerArray; // Independent copy of registers, used when a variable object copies its registers out of the register file. }; - inline bool JSVariableObject::symbolTableGet(PropertyName propertyName, PropertySlot& slot) - { - SymbolTableEntry entry = symbolTable().inlineGet(propertyName.publicName()); - if (!entry.isNull()) { - slot.setValue(registerAt(entry.getIndex()).get()); - return true; - } - return false; - } - - inline bool JSVariableObject::symbolTableGet(PropertyName propertyName, PropertySlot& slot, bool& slotIsWriteable) - { - SymbolTableEntry entry = symbolTable().inlineGet(propertyName.publicName()); - if (!entry.isNull()) { - slot.setValue(registerAt(entry.getIndex()).get()); - slotIsWriteable = !entry.isReadOnly(); - return true; - } - return false; - } - - inline bool JSVariableObject::symbolTablePut(ExecState* exec, PropertyName propertyName, JSValue value, bool shouldThrow) - { - JSGlobalData& globalData = exec->globalData(); - ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); - - SymbolTableEntry entry = symbolTable().inlineGet(propertyName.publicName()); - if (entry.isNull()) - return false; - if (entry.isReadOnly()) { - if (shouldThrow) - throwTypeError(exec, StrictModeReadonlyPropertyWriteError); - return true; - } - registerAt(entry.getIndex()).set(globalData, this, value); - return true; - } - - inline bool JSVariableObject::symbolTablePutWithAttributes(JSGlobalData& globalData, PropertyName propertyName, JSValue value, unsigned attributes) - { - ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); - - SymbolTable::iterator iter = symbolTable().find(propertyName.publicName()); - if (iter == symbolTable().end()) - return false; - SymbolTableEntry& entry = iter->second; - ASSERT(!entry.isNull()); - entry.setAttributes(attributes); - registerAt(entry.getIndex()).set(globalData, this, value); - return true; - } - inline PassOwnArrayPtr<WriteBarrier<Unknown> > JSVariableObject::copyRegisterArray(JSGlobalData& globalData, WriteBarrier<Unknown>* src, size_t count, size_t callframeStarts) { OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[count]); diff --git a/Source/JavaScriptCore/runtime/Lookup.h b/Source/JavaScriptCore/runtime/Lookup.h index a75b521cd..ccb08128d 100644 --- a/Source/JavaScriptCore/runtime/Lookup.h +++ b/Source/JavaScriptCore/runtime/Lookup.h @@ -114,6 +114,13 @@ namespace JSC { const HashTableValue* values; // Fixed values generated by script. mutable const HashEntry* table; // Table allocated at runtime. + ALWAYS_INLINE HashTable copy() const + { + // Don't copy dynamic table since it's thread specific. + HashTable result = { compactSize, compactHashSizeMask, values, 0 }; + return result; + } + ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const { if (!table) diff --git a/Source/JavaScriptCore/runtime/MathObject.cpp b/Source/JavaScriptCore/runtime/MathObject.cpp index 9d83290a5..2a550a38b 100644 --- a/Source/JavaScriptCore/runtime/MathObject.cpp +++ b/Source/JavaScriptCore/runtime/MathObject.cpp @@ -202,6 +202,43 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncMin(ExecState* exec) return JSValue::encode(jsNumber(result)); } +#if PLATFORM(IOS) && CPU(ARM_THUMB2) + +static double fdlibmPow(double x, double y); + +static ALWAYS_INLINE bool isDenormal(double x) +{ + static const uint64_t signbit = 0x8000000000000000ULL; + static const uint64_t minNormal = 0x0001000000000000ULL; + return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 < minNormal - 1; +} + +static ALWAYS_INLINE bool isEdgeCase(double x) +{ + static const uint64_t signbit = 0x8000000000000000ULL; + static const uint64_t infinity = 0x7fffffffffffffffULL; + return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 >= infinity - 1; +} + +static ALWAYS_INLINE double mathPow(double x, double y) +{ + if (!isDenormal(x) && !isDenormal(y)) { + double libmResult = pow(x,y); + if (libmResult || isEdgeCase(x) || isEdgeCase(y)) + return libmResult; + } + return fdlibmPow(x,y); +} + +#else + +ALWAYS_INLINE double mathPow(double x, double y) +{ + return pow(x, y); +} + +#endif + EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec) { // ECMA 15.8.2.1.13 @@ -213,7 +250,7 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec) return JSValue::encode(jsNaN()); if (isinf(arg2) && fabs(arg) == 1) return JSValue::encode(jsNaN()); - return JSValue::encode(jsNumber(pow(arg, arg2))); + return JSValue::encode(jsNumber(mathPow(arg, arg2))); } EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState* exec) @@ -243,4 +280,353 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState* exec) return JSValue::encode(jsDoubleNumber(tan(exec->argument(0).toNumber(exec)))); } +#if PLATFORM(IOS) && CPU(ARM_THUMB2) + +// The following code is taken from netlib.org: +// http://www.netlib.org/fdlibm/fdlibm.h +// http://www.netlib.org/fdlibm/e_pow.c +// http://www.netlib.org/fdlibm/s_scalbn.c +// +// And was originally distributed under the following license: + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* __ieee754_pow(x,y) return x**y + * + * n + * Method: Let x = 2 * (1+f) + * 1. Compute and return log2(x) in two pieces: + * log2(x) = w1 + w2, + * where w1 has 53-24 = 29 bit trailing zeros. + * 2. Perform y*log2(x) = n+y' by simulating muti-precision + * arithmetic, where |y'|<=0.5. + * 3. Return x**y = 2**n*exp(y'*log2) + * + * Special cases: + * 1. (anything) ** 0 is 1 + * 2. (anything) ** 1 is itself + * 3. (anything) ** NAN is NAN + * 4. NAN ** (anything except 0) is NAN + * 5. +-(|x| > 1) ** +INF is +INF + * 6. +-(|x| > 1) ** -INF is +0 + * 7. +-(|x| < 1) ** +INF is +0 + * 8. +-(|x| < 1) ** -INF is +INF + * 9. +-1 ** +-INF is NAN + * 10. +0 ** (+anything except 0, NAN) is +0 + * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + * 12. +0 ** (-anything except 0, NAN) is +INF + * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF + * 14. -0 ** (odd integer) = -( +0 ** (odd integer) ) + * 15. +INF ** (+anything except 0,NAN) is +INF + * 16. +INF ** (-anything except 0,NAN) is +0 + * 17. -INF ** (anything) = -0 ** (-anything) + * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + * 19. (-anything except 0 and inf) ** (non-integer) is NAN + * + * Accuracy: + * pow(x,y) returns x**y nearly rounded. In particular + * pow(integer,integer) + * always returns the correct integer provided it is + * representable. + * + * Constants : + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#define __HI(x) *(1+(int*)&x) +#define __LO(x) *(int*)&x + +static const double +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ +dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */ +zero = 0.0, +one = 1.0, +two = 2.0, +two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ +huge = 1.0e300, +tiny = 1.0e-300, + /* for scalbn */ +two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ +twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */ + /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ +L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ +L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ +L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ +L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ +L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ +lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ +lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ +lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ +ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */ +cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ +cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ +cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ +ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ +ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ +ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ + +inline double fdlibmScalbn (double x, int n) +{ + int k,hx,lx; + hx = __HI(x); + lx = __LO(x); + k = (hx&0x7ff00000)>>20; /* extract exponent */ + if (k==0) { /* 0 or subnormal x */ + if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */ + x *= two54; + hx = __HI(x); + k = ((hx&0x7ff00000)>>20) - 54; + if (n< -50000) return tiny*x; /*underflow*/ + } + if (k==0x7ff) return x+x; /* NaN or Inf */ + k = k+n; + if (k > 0x7fe) return huge*copysign(huge,x); /* overflow */ + if (k > 0) /* normal result */ + {__HI(x) = (hx&0x800fffff)|(k<<20); return x;} + if (k <= -54) { + if (n > 50000) /* in case integer overflow in n+k */ + return huge*copysign(huge,x); /*overflow*/ + else return tiny*copysign(tiny,x); /*underflow*/ + } + k += 54; /* subnormal result */ + __HI(x) = (hx&0x800fffff)|(k<<20); + return x*twom54; +} + +double fdlibmPow(double x, double y) +{ + double z,ax,z_h,z_l,p_h,p_l; + double y1,t1,t2,r,s,t,u,v,w; + int i0,i1,i,j,k,yisint,n; + int hx,hy,ix,iy; + unsigned lx,ly; + + i0 = ((*(int*)&one)>>29)^1; i1=1-i0; + hx = __HI(x); lx = __LO(x); + hy = __HI(y); ly = __LO(y); + ix = hx&0x7fffffff; iy = hy&0x7fffffff; + + /* y==zero: x**0 = 1 */ + if((iy|ly)==0) return one; + + /* +-NaN return x+y */ + if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) || + iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) + return x+y; + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if(hx<0) { + if(iy>=0x43400000) yisint = 2; /* even integer y */ + else if(iy>=0x3ff00000) { + k = (iy>>20)-0x3ff; /* exponent */ + if(k>20) { + j = ly>>(52-k); + if(static_cast<unsigned>(j<<(52-k))==ly) yisint = 2-(j&1); + } else if(ly==0) { + j = iy>>(20-k); + if((j<<(20-k))==iy) yisint = 2-(j&1); + } + } + } + + /* special value of y */ + if(ly==0) { + if (iy==0x7ff00000) { /* y is +-inf */ + if(((ix-0x3ff00000)|lx)==0) + return y - y; /* inf**+-1 is NaN */ + else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */ + return (hy>=0)? y: zero; + else /* (|x|<1)**-,+inf = inf,0 */ + return (hy<0)?-y: zero; + } + if(iy==0x3ff00000) { /* y is +-1 */ + if(hy<0) return one/x; else return x; + } + if(hy==0x40000000) return x*x; /* y is 2 */ + if(hy==0x3fe00000) { /* y is 0.5 */ + if(hx>=0) /* x >= +0 */ + return sqrt(x); + } + } + + ax = fabs(x); + /* special value of x */ + if(lx==0) { + if(ix==0x7ff00000||ix==0||ix==0x3ff00000){ + z = ax; /*x is +-0,+-inf,+-1*/ + if(hy<0) z = one/z; /* z = (1/|x|) */ + if(hx<0) { + if(((ix-0x3ff00000)|yisint)==0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if(yisint==1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + } + + n = (hx>>31)+1; + + /* (x<0)**(non-int) is NaN */ + if((n|yisint)==0) return (x-x)/(x-x); + + s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ + if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */ + + /* |y| is huge */ + if(iy>0x41e00000) { /* if |y| > 2**31 */ + if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */ + if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny; + if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny; + } + /* over/underflow if x is not close to one */ + if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny; + if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax-one; /* t has 20 trailing zeros */ + w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25)); + u = ivln2_h*t; /* ivln2_h has 21 sig. bits */ + v = t*ivln2_l-w*ivln2; + t1 = u+v; + __LO(t1) = 0; + t2 = v-(t1-u); + } else { + double ss,s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if(ix<0x00100000) + {ax *= two53; n -= 53; ix = __HI(ax); } + n += ((ix)>>20)-0x3ff; + j = ix&0x000fffff; + /* determine interval */ + ix = j|0x3ff00000; /* normalize ix */ + if(j<=0x3988E) k=0; /* |x|<sqrt(3/2) */ + else if(j<0xBB67A) k=1; /* |x|<sqrt(3) */ + else {k=0;n+=1;ix -= 0x00100000;} + __HI(ax) = ix; + + /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ + u = ax-bp[k]; /* bp[0]=1.0, bp[1]=1.5 */ + v = one/(ax+bp[k]); + ss = u*v; + s_h = ss; + __LO(s_h) = 0; + /* t_h=ax+bp[k] High */ + t_h = zero; + __HI(t_h)=((ix>>1)|0x20000000)+0x00080000+(k<<18); + t_l = ax - (t_h-bp[k]); + s_l = v*((u-s_h*t_h)-s_h*t_l); + /* compute log(ax) */ + s2 = ss*ss; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+ss); + s2 = s_h*s_h; + t_h = 3.0+s2+r; + __LO(t_h) = 0; + t_l = r-((t_h-3.0)-s2); + /* u+v = ss*(1+...) */ + u = s_h*t_h; + v = s_l*t_h+t_l*ss; + /* 2/(3log2)*(ss+...) */ + p_h = u+v; + __LO(p_h) = 0; + p_l = v-(p_h-u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h+p_l*cp+dp_l[k]; + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (double)n; + t1 = (((z_h+z_l)+dp_h[k])+t); + __LO(t1) = 0; + t2 = z_l-(((t1-t)-dp_h[k])-z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + y1 = y; + __LO(y1) = 0; + p_l = (y-y1)*t1+y*t2; + p_h = y1*t1; + z = p_l+p_h; + j = __HI(z); + i = __LO(z); + if (j>=0x40900000) { /* z >= 1024 */ + if(((j-0x40900000)|i)!=0) /* if z > 1024 */ + return s*huge*huge; /* overflow */ + else { + if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */ + } + } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */ + if(((j-0xc090cc00)|i)!=0) /* z < -1075 */ + return s*tiny*tiny; /* underflow */ + else { + if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */ + } + } + /* + * compute 2**(p_h+p_l) + */ + i = j&0x7fffffff; + k = (i>>20)-0x3ff; + n = 0; + if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j+(0x00100000>>(k+1)); + k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */ + t = zero; + __HI(t) = (n&~(0x000fffff>>k)); + n = ((n&0x000fffff)|0x00100000)>>(20-k); + if(j<0) n = -n; + p_h -= t; + } + t = p_l+p_h; + __LO(t) = 0; + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2+t*lg2_l; + z = u+v; + w = v-(z-u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-two)-(w+z*w); + z = one-(r-z); + j = __HI(z); + j += (n<<20); + if((j>>20)<=0) z = fdlibmScalbn(z,n); /* subnormal output */ + else __HI(z) += (n<<20); + return s*z; +} + +#endif + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp index 8f5a05067..ec228f82a 100644 --- a/Source/JavaScriptCore/runtime/Options.cpp +++ b/Source/JavaScriptCore/runtime/Options.cpp @@ -47,6 +47,8 @@ namespace JSC { namespace Options { bool useJIT; +bool showDisassembly; + unsigned maximumOptimizationCandidateInstructionCount; unsigned maximumFunctionForCallInlineCandidateInstructionCount; @@ -89,9 +91,6 @@ double doubleVoteRatioForDoubleFormat; unsigned minimumNumberOfScansBetweenRebalance; unsigned gcMarkStackSegmentSize; -unsigned minimumNumberOfCellsToKeep; -unsigned maximumNumberOfSharedSegments; -unsigned sharedStackWakeupThreshold; unsigned numberOfGCMarkers; unsigned opaqueRootMergeThreshold; @@ -145,10 +144,28 @@ void setHeuristic(T& variable, const char* name, U value) #define SET(variable, value) variable = value #endif +static unsigned computeNumberOfGCMarkers(int maxNumberOfGCMarkers) +{ + int cpusToUse = 1; + +#if ENABLE(PARALLEL_GC) + cpusToUse = std::min(WTF::numberOfProcessorCores(), maxNumberOfGCMarkers); + + // Be paranoid, it is the OS we're dealing with, after all. + ASSERT(cpusToUse >= 1); + if (cpusToUse < 1) + cpusToUse = 1; +#endif + + return cpusToUse; +} + void initializeOptions() { SET(useJIT, true); + SET(showDisassembly, false); + SET(maximumOptimizationCandidateInstructionCount, 10000); SET(maximumFunctionForCallInlineCandidateInstructionCount, 180); @@ -188,25 +205,10 @@ void initializeOptions() SET(doubleVoteRatioForDoubleFormat, 2); - SET(minimumNumberOfScansBetweenRebalance, 10000); + SET(minimumNumberOfScansBetweenRebalance, 100); SET(gcMarkStackSegmentSize, pageSize()); - SET(minimumNumberOfCellsToKeep, 10); - SET(maximumNumberOfSharedSegments, 3); - SET(sharedStackWakeupThreshold, 1); SET(opaqueRootMergeThreshold, 1000); - - int cpusToUse = 1; -#if ENABLE(PARALLEL_GC) - cpusToUse = WTF::numberOfProcessorCores(); -#endif - // We don't scale so well beyond 4. - if (cpusToUse > 4) - cpusToUse = 4; - // Be paranoid, it is the OS we're dealing with, after all. - if (cpusToUse < 1) - cpusToUse = 1; - - SET(numberOfGCMarkers, cpusToUse); + SET(numberOfGCMarkers, computeNumberOfGCMarkers(7)); // We don't scale so well beyond 7. ASSERT(thresholdForOptimizeAfterLongWarmUp >= thresholdForOptimizeAfterWarmUp); ASSERT(thresholdForOptimizeAfterWarmUp >= thresholdForOptimizeSoon); diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h index d1ad2ca87..e5cc99590 100644 --- a/Source/JavaScriptCore/runtime/Options.h +++ b/Source/JavaScriptCore/runtime/Options.h @@ -32,6 +32,8 @@ namespace JSC { namespace Options { extern bool useJIT; +extern bool showDisassembly; + extern unsigned maximumOptimizationCandidateInstructionCount; extern unsigned maximumFunctionForCallInlineCandidateInstructionCount; @@ -75,9 +77,6 @@ extern double doubleVoteRatioForDoubleFormat; extern unsigned minimumNumberOfScansBetweenRebalance; extern unsigned gcMarkStackSegmentSize; -extern unsigned minimumNumberOfCellsToKeep; -extern unsigned maximumNumberOfSharedSegments; -extern unsigned sharedStackWakeupThreshold; JS_EXPORTDATA extern unsigned numberOfGCMarkers; JS_EXPORTDATA extern unsigned opaqueRootMergeThreshold; diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp index dc4239799..569126147 100644 --- a/Source/JavaScriptCore/runtime/Structure.cpp +++ b/Source/JavaScriptCore/runtime/Structure.cpp @@ -155,6 +155,7 @@ Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSV , m_globalObject(globalData, this, globalObject, WriteBarrier<JSGlobalObject>::MayBeNull) , m_prototype(globalData, this, prototype) , m_classInfo(classInfo) + , m_transitionWatchpointSet(InitializedWatching) , m_propertyStorageCapacity(typeInfo.isFinalObject() ? JSFinalObject_inlineStorageCapacity : JSNonFinalObject_inlineStorageCapacity) , m_offset(noOffset) , m_dictionaryKind(NoneDictionaryKind) @@ -177,6 +178,7 @@ Structure::Structure(JSGlobalData& globalData) , m_typeInfo(CompoundType, OverridesVisitChildren) , m_prototype(globalData, this, jsNull()) , m_classInfo(&s_info) + , m_transitionWatchpointSet(InitializedWatching) , m_propertyStorageCapacity(0) , m_offset(noOffset) , m_dictionaryKind(NoneDictionaryKind) @@ -197,6 +199,7 @@ Structure::Structure(JSGlobalData& globalData, const Structure* previous) , m_typeInfo(previous->typeInfo()) , m_prototype(globalData, this, previous->storedPrototype()) , m_classInfo(previous->m_classInfo) + , m_transitionWatchpointSet(InitializedWatching) , m_propertyStorageCapacity(previous->m_propertyStorageCapacity) , m_offset(noOffset) , m_dictionaryKind(previous->m_dictionaryKind) @@ -210,6 +213,7 @@ Structure::Structure(JSGlobalData& globalData, const Structure* previous) , m_didTransition(true) , m_staticFunctionReified(previous->m_staticFunctionReified) { + previous->notifyTransitionFromThisStructure(); if (previous->m_globalObject) m_globalObject.set(globalData, this, previous->m_globalObject.get()); } diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h index f67c4e7f7..448a81c27 100644 --- a/Source/JavaScriptCore/runtime/Structure.h +++ b/Source/JavaScriptCore/runtime/Structure.h @@ -37,6 +37,7 @@ #include "StructureTransitionTable.h" #include "JSTypeInfo.h" #include "UString.h" +#include "Watchpoint.h" #include "Weak.h" #include <wtf/PassOwnPtr.h> #include <wtf/PassRefPtr.h> @@ -127,6 +128,8 @@ namespace JSC { JSValue storedPrototype() const { return m_prototype.get(); } JSValue prototypeForLookup(ExecState*) const; + JSValue prototypeForLookup(JSGlobalObject*) const; + JSValue prototypeForLookup(CodeBlock*) const; StructureChain* prototypeChain(ExecState*) const; static void visitChildren(JSCell*, SlotVisitor&); @@ -208,6 +211,27 @@ namespace JSC { return structure; } + bool transitionWatchpointSetHasBeenInvalidated() const + { + return m_transitionWatchpointSet.hasBeenInvalidated(); + } + + bool transitionWatchpointSetIsStillValid() const + { + return m_transitionWatchpointSet.isStillValid(); + } + + void addTransitionWatchpoint(Watchpoint* watchpoint) const + { + ASSERT(transitionWatchpointSetIsStillValid()); + m_transitionWatchpointSet.add(watchpoint); + } + + void notifyTransitionFromThisStructure() const + { + m_transitionWatchpointSet.notifyWrite(); + } + static JS_EXPORTDATA const ClassInfo s_info; private: @@ -291,9 +315,11 @@ namespace JSC { OwnPtr<PropertyTable> m_propertyTable; - uint32_t m_propertyStorageCapacity; - WriteBarrier<JSString> m_objectToStringValue; + + mutable InlineWatchpointSet m_transitionWatchpointSet; + + uint32_t m_propertyStorageCapacity; // m_offset does not account for anonymous slots int m_offset; @@ -363,6 +389,9 @@ namespace JSC { { ASSERT(structure->typeInfo().overridesVisitChildren() == this->structure()->typeInfo().overridesVisitChildren()); ASSERT(structure->classInfo() == m_structure->classInfo()); + ASSERT(!m_structure + || m_structure->transitionWatchpointSetHasBeenInvalidated() + || m_structure.get() == structure); m_structure.set(globalData, this, structure); } @@ -382,10 +411,13 @@ namespace JSC { #if ENABLE(GC_VALIDATION) validate(cell); #endif - m_visitCount++; if (Heap::testAndSetMarked(cell) || !cell->structure()) return; + + m_visitCount++; + MARK_LOG_CHILD(*this, cell); + // Should never attempt to mark something that is zapped. ASSERT(!cell->isZapped()); diff --git a/Source/JavaScriptCore/runtime/SymbolTable.cpp b/Source/JavaScriptCore/runtime/SymbolTable.cpp new file mode 100644 index 000000000..2a9d71629 --- /dev/null +++ b/Source/JavaScriptCore/runtime/SymbolTable.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SymbolTable.h" + +namespace JSC { + +SymbolTableEntry& SymbolTableEntry::copySlow(const SymbolTableEntry& other) +{ + ASSERT(other.isFat()); + FatEntry* newFatEntry = new FatEntry(*other.fatEntry()); + freeFatEntry(); + m_bits = bitwise_cast<intptr_t>(newFatEntry) | FatFlag; + return *this; +} + +void SymbolTableEntry::freeFatEntrySlow() +{ + ASSERT(isFat()); + delete fatEntry(); +} + +bool SymbolTableEntry::couldBeWatched() +{ + if (!isFat()) + return false; + WatchpointSet* watchpoints = fatEntry()->m_watchpoints.get(); + if (!watchpoints) + return false; + return watchpoints->isStillValid(); +} + +void SymbolTableEntry::attemptToWatch() +{ + FatEntry* entry = inflate(); + if (!entry->m_watchpoints) + entry->m_watchpoints = adoptRef(new WatchpointSet(InitializedWatching)); +} + +bool* SymbolTableEntry::addressOfIsWatched() +{ + ASSERT(couldBeWatched()); + return fatEntry()->m_watchpoints->addressOfIsWatched(); +} + +void SymbolTableEntry::addWatchpoint(Watchpoint* watchpoint) +{ + ASSERT(couldBeWatched()); + fatEntry()->m_watchpoints->add(watchpoint); +} + +void SymbolTableEntry::notifyWriteSlow() +{ + WatchpointSet* watchpoints = fatEntry()->m_watchpoints.get(); + if (!watchpoints) + return; + watchpoints->notifyWrite(); +} + +SymbolTableEntry::FatEntry* SymbolTableEntry::inflateSlow() +{ + FatEntry* entry = new FatEntry(m_bits); + m_bits = bitwise_cast<intptr_t>(entry) | FatFlag; + return entry; +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h index f540a12c7..9ddc32c8c 100644 --- a/Source/JavaScriptCore/runtime/SymbolTable.h +++ b/Source/JavaScriptCore/runtime/SymbolTable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,53 +31,163 @@ #include "JSObject.h" #include "UString.h" +#include "Watchpoint.h" #include <wtf/AlwaysInline.h> #include <wtf/HashTraits.h> namespace JSC { + class Watchpoint; + class WatchpointSet; + static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>::max(); } // The bit twiddling in this class assumes that every register index is a // reasonably small positive or negative number, and therefore has its high // four bits all set or all unset. + // In addition to implementing semantics-mandated variable attributes and + // implementation-mandated variable indexing, this class also implements + // watchpoints to be used for JIT optimizations. Because watchpoints are + // meant to be relatively rare, this class optimizes heavily for the case + // that they are not being used. To that end, this class uses the thin-fat + // idiom: either it is thin, in which case it contains an in-place encoded + // word that consists of attributes, the index, and a bit saying that it is + // thin; or it is fat, in which case it contains a pointer to a malloc'd + // data structure and a bit saying that it is fat. The malloc'd data + // structure will be malloced a second time upon copy, to preserve the + // property that in-place edits to SymbolTableEntry do not manifest in any + // copies. However, the malloc'd FatEntry data structure contains a ref- + // counted pointer to a shared WatchpointSet. Thus, in-place edits of the + // WatchpointSet will manifest in all copies. Here's a picture: + // + // SymbolTableEntry --> FatEntry --> WatchpointSet + // + // If you make a copy of a SymbolTableEntry, you will have: + // + // original: SymbolTableEntry --> FatEntry --> WatchpointSet + // copy: SymbolTableEntry --> FatEntry -----^ + struct SymbolTableEntry { + // Use the SymbolTableEntry::Fast class, either via implicit cast or by calling + // getFast(), when you (1) only care about isNull(), getIndex(), and isReadOnly(), + // and (2) you are in a hot path where you need to minimize the number of times + // that you branch on isFat() when getting the bits(). + class Fast { + public: + Fast() + : m_bits(0) + { + } + + ALWAYS_INLINE Fast(const SymbolTableEntry& entry) + : m_bits(entry.bits()) + { + } + + bool isNull() const + { + return !m_bits; + } + + int getIndex() const + { + return static_cast<int>(m_bits >> FlagBits); + } + + bool isReadOnly() const + { + return m_bits & ReadOnlyFlag; + } + + unsigned getAttributes() const + { + unsigned attributes = 0; + if (m_bits & ReadOnlyFlag) + attributes |= ReadOnly; + if (m_bits & DontEnumFlag) + attributes |= DontEnum; + return attributes; + } + + bool isFat() const + { + return m_bits & FatFlag; + } + + private: + friend struct SymbolTableEntry; + intptr_t m_bits; + }; + SymbolTableEntry() : m_bits(0) { } SymbolTableEntry(int index) + : m_bits(0) { ASSERT(isValidIndex(index)); pack(index, false, false); } SymbolTableEntry(int index, unsigned attributes) + : m_bits(0) { ASSERT(isValidIndex(index)); pack(index, attributes & ReadOnly, attributes & DontEnum); } + ~SymbolTableEntry() + { + freeFatEntry(); + } + + SymbolTableEntry(const SymbolTableEntry& other) + : m_bits(0) + { + *this = other; + } + + SymbolTableEntry& operator=(const SymbolTableEntry& other) + { + if (UNLIKELY(other.isFat())) + return copySlow(other); + freeFatEntry(); + m_bits = other.m_bits; + return *this; + } + bool isNull() const { - return !m_bits; + return !bits(); } int getIndex() const { - return m_bits >> FlagBits; + return static_cast<int>(bits() >> FlagBits); } - + + ALWAYS_INLINE Fast getFast() const + { + return Fast(*this); + } + + ALWAYS_INLINE Fast getFast(bool& wasFat) const + { + Fast result; + wasFat = isFat(); + if (wasFat) + result.m_bits = fatEntry()->m_bits; + else + result.m_bits = m_bits; + return result; + } + unsigned getAttributes() const { - unsigned attributes = 0; - if (m_bits & ReadOnlyFlag) - attributes |= ReadOnly; - if (m_bits & DontEnumFlag) - attributes |= DontEnum; - return attributes; + return getFast().getAttributes(); } void setAttributes(unsigned attributes) @@ -87,30 +197,125 @@ namespace JSC { bool isReadOnly() const { - return m_bits & ReadOnlyFlag; + return bits() & ReadOnlyFlag; } - + + bool couldBeWatched(); + + // Notify an opportunity to create a watchpoint for a variable. This is + // idempotent and fail-silent. It is idempotent in the sense that if + // a watchpoint set had already been created, then another one will not + // be created. Hence two calls to this method have the same effect as + // one call. It is also fail-silent, in the sense that if a watchpoint + // set had been created and had already been invalidated, then this will + // just return. This means that couldBeWatched() may return false even + // immediately after a call to attemptToWatch(). + void attemptToWatch(); + + bool* addressOfIsWatched(); + + void addWatchpoint(Watchpoint*); + + WatchpointSet* watchpointSet() + { + return fatEntry()->m_watchpoints.get(); + } + + ALWAYS_INLINE void notifyWrite() + { + if (LIKELY(!isFat())) + return; + notifyWriteSlow(); + } + private: - static const unsigned ReadOnlyFlag = 0x1; - static const unsigned DontEnumFlag = 0x2; - static const unsigned NotNullFlag = 0x4; - static const unsigned FlagBits = 3; + static const intptr_t FatFlag = 0x1; + static const intptr_t ReadOnlyFlag = 0x2; + static const intptr_t DontEnumFlag = 0x4; + static const intptr_t NotNullFlag = 0x8; + static const intptr_t FlagBits = 4; + + class FatEntry { + WTF_MAKE_FAST_ALLOCATED; + public: + FatEntry(intptr_t bits) + : m_bits(bits | FatFlag) + { + } + + intptr_t m_bits; // always has FatFlag set and exactly matches what the bits would have been if this wasn't fat. + + RefPtr<WatchpointSet> m_watchpoints; + }; + + SymbolTableEntry& copySlow(const SymbolTableEntry&); + JS_EXPORT_PRIVATE void notifyWriteSlow(); + + bool isFat() const + { + return m_bits & FatFlag; + } + + const FatEntry* fatEntry() const + { + ASSERT(isFat()); + return bitwise_cast<const FatEntry*>(m_bits & ~FatFlag); + } + + FatEntry* fatEntry() + { + ASSERT(isFat()); + return bitwise_cast<FatEntry*>(m_bits & ~FatFlag); + } + + FatEntry* inflate() + { + if (LIKELY(isFat())) + return fatEntry(); + return inflateSlow(); + } + + FatEntry* inflateSlow(); + + ALWAYS_INLINE intptr_t bits() const + { + if (isFat()) + return fatEntry()->m_bits; + return m_bits; + } + + ALWAYS_INLINE intptr_t& bits() + { + if (isFat()) + return fatEntry()->m_bits; + return m_bits; + } + + void freeFatEntry() + { + if (LIKELY(!isFat())) + return; + freeFatEntrySlow(); + } + + void freeFatEntrySlow(); void pack(int index, bool readOnly, bool dontEnum) { - m_bits = (index << FlagBits) | NotNullFlag; + intptr_t& bitsRef = bits(); + bitsRef = (static_cast<intptr_t>(index) << FlagBits) | NotNullFlag; if (readOnly) - m_bits |= ReadOnlyFlag; + bitsRef |= ReadOnlyFlag; if (dontEnum) - m_bits |= DontEnumFlag; + bitsRef |= DontEnumFlag; } bool isValidIndex(int index) { - return ((index << FlagBits) >> FlagBits) == index; + return ((static_cast<intptr_t>(index) << FlagBits) >> FlagBits) == static_cast<intptr_t>(index); } - int m_bits; + intptr_t m_bits; }; struct SymbolTableIndexHashTraits : HashTraits<SymbolTableEntry> { diff --git a/Source/JavaScriptCore/runtime/WriteBarrier.h b/Source/JavaScriptCore/runtime/WriteBarrier.h index 05f3bc5bb..9784a921e 100644 --- a/Source/JavaScriptCore/runtime/WriteBarrier.h +++ b/Source/JavaScriptCore/runtime/WriteBarrier.h @@ -177,6 +177,9 @@ public: return u.slot; } + int32_t* tagPointer() { return &bitwise_cast<EncodedValueDescriptor*>(&m_value)->asBits.tag; } + int32_t* payloadPointer() { return &bitwise_cast<EncodedValueDescriptor*>(&m_value)->asBits.payload; } + typedef JSValue (WriteBarrierBase::*UnspecifiedBoolType); operator UnspecifiedBoolType*() const { return get() ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; } bool operator!() const { return !get(); } |