summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-06-20 13:01:08 +0200
committerSimon Hausmann <simon.hausmann@nokia.com>2012-06-20 13:01:08 +0200
commit49233e234e5c787396cadb2cea33b31ae0cd65c1 (patch)
tree5410cb9a8fd53168bb60d62c54b654d86f03c38d /Source/JavaScriptCore/runtime
parentb211c645d8ab690f713515dfdc84d80b11c27d2c (diff)
downloadqtwebkit-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')
-rw-r--r--Source/JavaScriptCore/runtime/Completion.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/Executable.cpp65
-rw-r--r--Source/JavaScriptCore/runtime/Executable.h73
-rw-r--r--Source/JavaScriptCore/runtime/GCActivityCallback.cpp94
-rw-r--r--Source/JavaScriptCore/runtime/GCActivityCallback.h34
-rw-r--r--Source/JavaScriptCore/runtime/GCActivityCallbackBlackBerry.cpp58
-rw-r--r--Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp155
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/JSCell.cpp5
-rw-r--r--Source/JavaScriptCore/runtime/JSCell.h4
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalData.cpp15
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalData.h7
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.cpp60
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.h34
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.cpp24
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.h2
-rw-r--r--Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp71
-rw-r--r--Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h101
-rw-r--r--Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp8
-rw-r--r--Source/JavaScriptCore/runtime/JSString.cpp13
-rw-r--r--Source/JavaScriptCore/runtime/JSString.h1
-rw-r--r--Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp88
-rw-r--r--Source/JavaScriptCore/runtime/JSSymbolTableObject.h163
-rw-r--r--Source/JavaScriptCore/runtime/JSVariableObject.cpp61
-rw-r--r--Source/JavaScriptCore/runtime/JSVariableObject.h90
-rw-r--r--Source/JavaScriptCore/runtime/Lookup.h7
-rw-r--r--Source/JavaScriptCore/runtime/MathObject.cpp388
-rw-r--r--Source/JavaScriptCore/runtime/Options.cpp42
-rw-r--r--Source/JavaScriptCore/runtime/Options.h5
-rw-r--r--Source/JavaScriptCore/runtime/Structure.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/Structure.h38
-rw-r--r--Source/JavaScriptCore/runtime/SymbolTable.cpp94
-rw-r--r--Source/JavaScriptCore/runtime/SymbolTable.h247
-rw-r--r--Source/JavaScriptCore/runtime/WriteBarrier.h3
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(); }