summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/tools
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2015-10-15 09:45:50 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2015-10-15 09:45:50 +0000
commite15dd966d523731101f70ccf768bba12435a0208 (patch)
treeae9cb828a24ded2585a41af3f21411523b47897d /Source/JavaScriptCore/tools
downloadWebKitGtk-tarball-e15dd966d523731101f70ccf768bba12435a0208.tar.gz
webkitgtk-2.10.2webkitgtk-2.10.2
Diffstat (limited to 'Source/JavaScriptCore/tools')
-rw-r--r--Source/JavaScriptCore/tools/CodeProfile.cpp192
-rw-r--r--Source/JavaScriptCore/tools/CodeProfile.h94
-rw-r--r--Source/JavaScriptCore/tools/CodeProfiling.cpp177
-rw-r--r--Source/JavaScriptCore/tools/CodeProfiling.h85
-rw-r--r--Source/JavaScriptCore/tools/FunctionOverrides.cpp250
-rw-r--r--Source/JavaScriptCore/tools/FunctionOverrides.h64
-rw-r--r--Source/JavaScriptCore/tools/JSDollarVM.cpp36
-rw-r--r--Source/JavaScriptCore/tools/JSDollarVM.h60
-rw-r--r--Source/JavaScriptCore/tools/JSDollarVMPrototype.cpp424
-rw-r--r--Source/JavaScriptCore/tools/JSDollarVMPrototype.h81
-rw-r--r--Source/JavaScriptCore/tools/ProfileTreeNode.h123
-rw-r--r--Source/JavaScriptCore/tools/TieredMMapArray.h116
12 files changed, 1702 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/tools/CodeProfile.cpp b/Source/JavaScriptCore/tools/CodeProfile.cpp
new file mode 100644
index 000000000..c64f1d5a6
--- /dev/null
+++ b/Source/JavaScriptCore/tools/CodeProfile.cpp
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CodeProfile.h"
+
+#include "CodeBlock.h"
+#include "CodeProfiling.h"
+#include "LinkBuffer.h"
+#include "ProfileTreeNode.h"
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+#if OS(DARWIN)
+#include <cxxabi.h>
+#include <dlfcn.h>
+#include <execinfo.h>
+#endif
+
+namespace JSC {
+
+// Map from CodeType enum to a corresponding name.
+const char* CodeProfile::s_codeTypeNames[CodeProfile::NumberOfCodeTypes] = {
+ "[[EngineCode]]",
+ "[[GlobalThunk]]",
+ "[[RegExpCode]]",
+ "[[DFGJIT]]",
+ "[[BaselineOnly]]",
+ "[[BaselineProfile]]",
+ "[[BaselineOSR]]",
+ "[[EngineFrame]]"
+};
+
+// Helper function, find the symbol name for a pc in JSC.
+static const char* symbolName(void* address)
+{
+#if OS(DARWIN)
+ Dl_info info;
+ if (!dladdr(address, &info) || !info.dli_sname)
+ return "<unknown>";
+
+ const char* mangledName = info.dli_sname;
+ const char* cxaDemangled = abi::__cxa_demangle(mangledName, 0, 0, 0);
+ return cxaDemangled ? cxaDemangled : mangledName;
+#else
+ UNUSED_PARAM(address);
+ return "<unknown>";
+#endif
+}
+
+// Helper function, truncate traces to prune the output & make very verbose mode a little more readable.
+static bool truncateTrace(const char* symbolName)
+{
+ return !strcmp(symbolName, "JSC::BytecodeGenerator::generate()")
+ || !strcmp(symbolName, "JSC::Parser<JSC::Lexer<unsigned char>>::parseInner()")
+ || !strcmp(symbolName, "WTF::fastMalloc(unsigned long)")
+ || !strcmp(symbolName, "WTF::calculateUTCOffset()")
+ || !strcmp(symbolName, "JSC::DFG::ByteCodeParser::parseCodeBlock()");
+
+}
+
+// Each trace consists of a sequence of zero or more 'EngineFrame' entries,
+// followed by a sample in JIT code, or one or more 'EngineFrame' entries,
+// followed by a 'EngineCode' terminator.
+void CodeProfile::sample(void* pc, void** framePointer)
+{
+ // Disallow traces containing only a 'EngineCode' terminator, without any 'EngineFrame' frames.
+ if (!framePointer)
+ return;
+
+ while (framePointer) {
+ CodeType type;
+
+#if ENABLE(JIT)
+ // Determine if this sample fell in JIT code, and if so, from which JIT & why.
+ void* ownerUID = CodeProfiling::getOwnerUIDForPC(pc);
+
+ if (!ownerUID)
+ type = EngineFrame;
+ else if (ownerUID == GLOBAL_THUNK_ID)
+ type = GlobalThunk;
+ else if (ownerUID == REGEXP_CODE_ID)
+ type = RegExpCode;
+ else {
+ CodeBlock* codeBlock = static_cast<CodeBlock*>(ownerUID);
+ if (codeBlock->jitType() == JITCode::DFGJIT)
+ type = DFGJIT;
+ else if (!canCompile(codeBlock->capabilityLevelState()))
+ type = BaselineOnly;
+ else if (codeBlock->replacement())
+ type = BaselineOSR;
+ else
+ type = BaselineProfile;
+ }
+#else
+ type = EngineFrame;
+#endif
+
+ // A sample in JIT code terminates the trace.
+ m_samples.append(CodeRecord(pc, type));
+ if (type != EngineFrame)
+ return;
+
+#if OS(DARWIN) && CPU(X86_64)
+ // Walk up the stack.
+ pc = framePointer[1];
+ framePointer = reinterpret_cast<void**>(*framePointer);
+#elif OS(LINUX) && CPU(X86)
+ // Don't unwind the stack as some dependent third party libraries
+ // may be compiled with -fomit-frame-pointer.
+ framePointer = 0;
+#else
+ // This platform is not yet supported!
+ RELEASE_ASSERT_NOT_REACHED();
+#endif
+ }
+
+ // If we get here, we walked the entire stack without finding any frames of JIT code.
+ m_samples.append(CodeRecord(0, EngineCode));
+}
+
+void CodeProfile::report()
+{
+ dataLogF("<CodeProfiling %s:%d>\n", m_file.data(), m_lineNumber);
+
+ // How many frames of C-code to print - 0, if not verbose, 1 if verbose, up to 1024 if very verbose.
+ unsigned recursionLimit = CodeProfiling::beVeryVerbose() ? 1024 : CodeProfiling::beVerbose();
+
+ ProfileTreeNode profile;
+
+ // Walk through the sample buffer.
+ size_t trace = 0;
+ while (trace < m_samples.size()) {
+
+ // All traces are zero or more 'EngineFrame's, followed by a non-'EngineFrame'.
+ // Scan to find the last sample in the trace.
+ size_t lastInTrace = trace;
+ while (m_samples[lastInTrace].type == EngineFrame)
+ ++lastInTrace;
+
+ // We use the last sample type to look up a name (used as a bucket in the profiler).
+ ProfileTreeNode* callbacks = profile.sampleChild(s_codeTypeNames[m_samples[lastInTrace].type]);
+
+ // If there are any samples in C-code, add up to recursionLimit of them into the profile tree.
+ size_t lastEngineFrame = lastInTrace;
+ for (unsigned count = 0; lastEngineFrame > trace && count < recursionLimit; ++count) {
+ --lastEngineFrame;
+ ASSERT(m_samples[lastEngineFrame].type == EngineFrame);
+ const char* name = symbolName(m_samples[lastEngineFrame].pc);
+ callbacks = callbacks->sampleChild(name);
+ if (truncateTrace(name))
+ break;
+ }
+
+ // Move on to the next trace.
+ trace = lastInTrace + 1;
+ ASSERT(trace <= m_samples.size());
+ }
+
+ // Output the profile tree.
+ dataLogF("Total samples: %lld\n", static_cast<long long>(profile.childCount()));
+ profile.dump();
+
+ for (size_t i = 0 ; i < m_children.size(); ++i)
+ m_children[i]->report();
+
+ dataLogF("</CodeProfiling %s:%d>\n", m_file.data(), m_lineNumber);
+}
+
+}
diff --git a/Source/JavaScriptCore/tools/CodeProfile.h b/Source/JavaScriptCore/tools/CodeProfile.h
new file mode 100644
index 000000000..42f6de50c
--- /dev/null
+++ b/Source/JavaScriptCore/tools/CodeProfile.h
@@ -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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CodeProfile_h
+#define CodeProfile_h
+
+#include "SourceCode.h"
+#include "TieredMMapArray.h"
+#include <wtf/text/CString.h>
+
+namespace JSC {
+
+class CodeProfile {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ CodeProfile(const SourceCode& source, CodeProfile* parent)
+ : m_file(source.provider()->url().utf8())
+ , m_lineNumber(source.firstLine())
+ , m_parent(parent)
+ {
+ if (parent)
+ parent->addChild(std::unique_ptr<CodeProfile>(this));
+ }
+
+ void sample(void* pc, void** framePointer);
+ void report();
+
+ CodeProfile* parent()
+ {
+ return m_parent;
+ }
+
+ void addChild(std::unique_ptr<CodeProfile> child)
+ {
+ m_children.append(WTF::move(child));
+ }
+
+private:
+ enum CodeType {
+ EngineCode,
+ GlobalThunk,
+ RegExpCode,
+ DFGJIT,
+ BaselineOnly,
+ BaselineProfile,
+ BaselineOSR,
+ EngineFrame,
+ NumberOfCodeTypes
+ };
+ struct CodeRecord {
+ CodeRecord(void* pc, CodeType type)
+ : pc(pc)
+ , type(type)
+ {
+ }
+ void* pc;
+ CodeType type;
+ };
+
+ CString m_file;
+ unsigned m_lineNumber;
+ CodeProfile* m_parent;
+ Vector<std::unique_ptr<CodeProfile>> m_children;
+ TieredMMapArray<CodeRecord> m_samples;
+
+ static const char* s_codeTypeNames[NumberOfCodeTypes];
+};
+
+}
+
+#endif // CodeProfile_h
+
diff --git a/Source/JavaScriptCore/tools/CodeProfiling.cpp b/Source/JavaScriptCore/tools/CodeProfiling.cpp
new file mode 100644
index 000000000..302b5f929
--- /dev/null
+++ b/Source/JavaScriptCore/tools/CodeProfiling.cpp
@@ -0,0 +1,177 @@
+/*
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CodeProfiling.h"
+
+#include "CodeProfile.h"
+#include <wtf/MetaAllocator.h>
+
+#if HAVE(SIGNAL_H)
+#include <signal.h>
+#endif
+
+#if OS(LINUX) || OS(DARWIN)
+#include <sys/time.h>
+#endif
+
+namespace JSC {
+
+volatile CodeProfile* CodeProfiling::s_profileStack = 0;
+CodeProfiling::Mode CodeProfiling::s_mode = CodeProfiling::Disabled;
+WTF::MetaAllocatorTracker* CodeProfiling::s_tracker = 0;
+
+#if COMPILER(CLANG)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-noreturn"
+#endif
+
+#if (OS(DARWIN) && !PLATFORM(EFL) && !PLATFORM(GTK) && CPU(X86_64)) || (OS(LINUX) && CPU(X86))
+// Helper function to start & stop the timer.
+// Presently we're using the wall-clock timer, since this seems to give the best results.
+static void setProfileTimer(unsigned usec)
+{
+ itimerval timer;
+ timer.it_value.tv_sec = 0;
+ timer.it_value.tv_usec = usec;
+ timer.it_interval.tv_sec = 0;
+ timer.it_interval.tv_usec = usec;
+ setitimer(ITIMER_REAL, &timer, 0);
+}
+#endif
+
+#if COMPILER(CLANG)
+#pragma clang diagnostic pop
+#endif
+
+#if OS(DARWIN) && !PLATFORM(EFL) && !PLATFORM(GTK) && CPU(X86_64)
+static void profilingTimer(int, siginfo_t*, void* uap)
+{
+ mcontext_t context = static_cast<ucontext_t*>(uap)->uc_mcontext;
+ CodeProfiling::sample(reinterpret_cast<void*>(context->__ss.__rip),
+ reinterpret_cast<void**>(context->__ss.__rbp));
+}
+#elif OS(LINUX) && CPU(X86)
+static void profilingTimer(int, siginfo_t*, void* uap)
+{
+ mcontext_t context = static_cast<ucontext_t*>(uap)->uc_mcontext;
+ CodeProfiling::sample(reinterpret_cast<void*>(context.gregs[REG_EIP]),
+ reinterpret_cast<void**>(context.gregs[REG_EBP]));
+}
+#endif
+
+// Callback triggered when the timer is fired.
+void CodeProfiling::sample(void* pc, void** framePointer)
+{
+ CodeProfile* profileStack = const_cast<CodeProfile*>(s_profileStack);
+ if (profileStack)
+ profileStack->sample(pc, framePointer);
+}
+
+void CodeProfiling::notifyAllocator(WTF::MetaAllocator* allocator)
+{
+ // Check for JSC_CODE_PROFILING.
+ const char* codeProfilingMode = getenv("JSC_CODE_PROFILING");
+ if (!codeProfilingMode)
+ return;
+
+ // Check for a valid mode, currently "1", "2", or "3".
+ if (!codeProfilingMode[0] || codeProfilingMode[1])
+ return;
+ switch (*codeProfilingMode) {
+ case '1':
+ s_mode = Enabled;
+ break;
+ case '2':
+ s_mode = Verbose;
+ break;
+ case '3':
+ s_mode = VeryVerbose;
+ break;
+ default:
+ return;
+ }
+
+ ASSERT(enabled());
+ ASSERT(!s_tracker);
+ s_tracker = new WTF::MetaAllocatorTracker();
+ allocator->trackAllocations(s_tracker);
+}
+
+void* CodeProfiling::getOwnerUIDForPC(void* address)
+{
+ if (!s_tracker)
+ return 0;
+ WTF::MetaAllocatorHandle* handle = s_tracker->find(address);
+ if (!handle)
+ return 0;
+ return handle->ownerUID();
+}
+
+void CodeProfiling::begin(const SourceCode& source)
+{
+ // Push a new CodeProfile onto the stack for each script encountered.
+ CodeProfile* profileStack = const_cast<CodeProfile*>(s_profileStack);
+ bool alreadyProfiling = profileStack;
+ s_profileStack = profileStack = new CodeProfile(source, profileStack);
+
+ // Is the profiler already running - if so, the timer will already be set up.
+ if (alreadyProfiling)
+ return;
+
+#if (OS(DARWIN) && !PLATFORM(EFL) && !PLATFORM(GTK) && CPU(X86_64)) || (OS(LINUX) && CPU(X86))
+ // Regsiter a signal handler & itimer.
+ struct sigaction action;
+ action.sa_sigaction = reinterpret_cast<void (*)(int, siginfo_t *, void *)>(profilingTimer);
+ sigfillset(&action.sa_mask);
+ action.sa_flags = SA_SIGINFO;
+ sigaction(SIGALRM, &action, 0);
+ setProfileTimer(100);
+#endif
+}
+
+void CodeProfiling::end()
+{
+ // Pop the current profiler off the stack.
+ CodeProfile* current = const_cast<CodeProfile*>(s_profileStack);
+ ASSERT(current);
+ s_profileStack = current->parent();
+
+ // Is this the outermost script being profiled? - if not, just return.
+ // We perform all output of profiles recursively from the outermost script,
+ // to minimize profiling overhead from skewing results.
+ if (s_profileStack)
+ return;
+
+#if (OS(DARWIN) && !PLATFORM(EFL) && !PLATFORM(GTK) && CPU(X86_64)) || (OS(LINUX) && CPU(X86))
+ // Stop profiling
+ setProfileTimer(0);
+#endif
+
+ current->report();
+ delete current;
+}
+
+}
diff --git a/Source/JavaScriptCore/tools/CodeProfiling.h b/Source/JavaScriptCore/tools/CodeProfiling.h
new file mode 100644
index 000000000..9b0f5daa3
--- /dev/null
+++ b/Source/JavaScriptCore/tools/CodeProfiling.h
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CodeProfiling_h
+#define CodeProfiling_h
+
+namespace WTF {
+
+class MetaAllocator;
+class MetaAllocatorTracker;
+
+}
+
+namespace JSC {
+
+class CodeProfile;
+class SourceCode;
+
+class CodeProfiling {
+ enum Mode {
+ Disabled,
+ Enabled,
+ Verbose,
+ VeryVerbose
+ };
+
+public:
+ CodeProfiling(const SourceCode& source)
+ : m_active(enabled())
+ {
+ if (m_active)
+ begin(source);
+ }
+
+ ~CodeProfiling()
+ {
+ if (m_active)
+ end();
+ }
+
+ static bool enabled() { return s_mode != Disabled; }
+ static bool beVerbose() { return s_mode >= Verbose; }
+ static bool beVeryVerbose() { return s_mode >= VeryVerbose; }
+
+ static void notifyAllocator(WTF::MetaAllocator*);
+ static void* getOwnerUIDForPC(void*);
+ static void sample(void* pc, void** framePointer);
+
+private:
+ void begin(const SourceCode&);
+ void end();
+
+ bool m_active;
+
+ static Mode s_mode;
+ static WTF::MetaAllocatorTracker* s_tracker;
+ static volatile CodeProfile* s_profileStack;
+};
+
+}
+
+#endif // CodeProfiling_h
+
diff --git a/Source/JavaScriptCore/tools/FunctionOverrides.cpp b/Source/JavaScriptCore/tools/FunctionOverrides.cpp
new file mode 100644
index 000000000..2034d60f5
--- /dev/null
+++ b/Source/JavaScriptCore/tools/FunctionOverrides.cpp
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FunctionOverrides.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <wtf/DataLog.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringHash.h>
+
+namespace JSC {
+
+/*
+ The overrides file defines function bodies that we will want to override with
+ a replacement for debugging purposes. The overrides file may contain
+ 'override' and 'with' clauses like these:
+
+ // Example 1: function foo1(a)
+ override !@#$%{ print("In foo1"); }!@#$%
+ with abc{
+ print("I am overridden");
+ }abc
+
+ // Example 2: function foo2(a)
+ override %%%{
+ print("foo2's body has a string with }%% in it.");
+ // Because }%% appears in the function body here, we cannot use
+ // %% or % as the delimiter. %%% is ok though.
+ }%%%
+ with %%%{
+ print("Overridden foo2");
+ }%%%
+
+ 1. Comments are lines starting with //. All comments will be ignored.
+
+ 2. An 'override' clause is used to specify the original function body we
+ want to override. The with clause is used to specify the overriding
+ function body.
+
+ An 'override' clause must be followed immediately by a 'with' clause.
+
+ 3. An 'override' clause must be of the form:
+ override <delimiter>{...function body...}<delimiter>
+
+ The override keyword must be at the start of the line.
+
+ <delimiter> may be any string of any ASCII characters (except for '{',
+ '}', and whitespace characters) as long as the pattern of "}<delimiter>"
+ does not appear in the function body e.g. the override clause of Example 2
+ above illustrates this.
+
+ The start and end <delimiter> must be identical.
+
+ The space between the override keyword and the start <delimiter> is
+ required.
+
+ All characters between the pair of delimiters will be considered to
+ be part of the function body string. This allows us to also work
+ with script source that are multi-lined i.e. newlines are allowed.
+
+ 4. A 'with' clause is identical in form to an 'override' clause except that
+ it uses the 'with' keyword instead of the 'override' keyword.
+ */
+
+FunctionOverrides& FunctionOverrides::overrides()
+{
+ static LazyNeverDestroyed<FunctionOverrides> overrides;
+ static std::once_flag initializeListFlag;
+ std::call_once(initializeListFlag, [] {
+ const char* overridesFileName = Options::functionOverrides();
+ overrides.construct(overridesFileName);
+ });
+ return overrides;
+}
+
+FunctionOverrides::FunctionOverrides(const char* overridesFileName)
+{
+ parseOverridesInFile(overridesFileName);
+}
+
+static void initializeOverrideInfo(const SourceCode& origCode, const String& newBody, FunctionOverrides::OverrideInfo& info)
+{
+ String origProviderStr = origCode.provider()->source();
+ unsigned origBraceStart = origCode.startOffset();
+ unsigned origFunctionStart = origProviderStr.reverseFind("function", origBraceStart);
+ unsigned headerLength = origBraceStart - origFunctionStart;
+ String origHeader = origProviderStr.substring(origFunctionStart, headerLength);
+
+ String newProviderStr;
+ newProviderStr.append(origHeader);
+ newProviderStr.append(newBody);
+
+ RefPtr<SourceProvider> newProvider = StringSourceProvider::create(newProviderStr, "<overridden>");
+
+ info.firstLine = 1;
+ info.lineCount = 1; // Faking it. This doesn't really matter for now.
+ info.startColumn = 1;
+ info.endColumn = 1; // Faking it. This doesn't really matter for now.
+ info.parametersStartOffset = newProviderStr.find("(");
+ info.typeProfilingStartOffset = newProviderStr.find("{");
+ info.typeProfilingEndOffset = newProviderStr.length() - 1;
+
+ info.sourceCode =
+ SourceCode(newProvider.release(), info.typeProfilingStartOffset, info.typeProfilingEndOffset + 1, 1, 1);
+}
+
+bool FunctionOverrides::initializeOverrideFor(const SourceCode& origCode, FunctionOverrides::OverrideInfo& result)
+{
+ ASSERT(Options::functionOverrides());
+ FunctionOverrides& overrides = FunctionOverrides::overrides();
+
+ auto it = overrides.m_entries.find(origCode.toString());
+ if (it == overrides.m_entries.end())
+ return false;
+
+ initializeOverrideInfo(origCode, it->value, result);
+ return true;
+}
+
+#define SYNTAX_ERROR "SYNTAX ERROR"
+#define IO_ERROR "IO ERROR"
+#define FAIL_WITH_ERROR(error, errorMessageInBrackets) \
+ do { \
+ dataLog("functionOverrides ", error, ": "); \
+ dataLog errorMessageInBrackets; \
+ exit(EXIT_FAILURE); \
+ } while (false)
+
+static bool hasDisallowedCharacters(const char* str, size_t length)
+{
+ while (length--) {
+ char c = *str++;
+ // '{' is also disallowed, but we don't need to check for it because
+ // parseClause() searches for '{' as the end of the start delimiter.
+ // As a result, the parsed delimiter string will never include '{'.
+ if (c == '}' || isASCIISpace(c))
+ return true;
+ }
+ return false;
+}
+
+static String parseClause(const char* keyword, size_t keywordLength, FILE* file, const char* line, char* buffer, size_t bufferSize)
+{
+ const char* keywordPos = strstr(line, keyword);
+ if (!keywordPos)
+ FAIL_WITH_ERROR(SYNTAX_ERROR, ("Expecting '", keyword, "' clause:\n", line, "\n"));
+ if (keywordPos != line)
+ FAIL_WITH_ERROR(SYNTAX_ERROR, ("Cannot have any characters before '", keyword, "':\n", line, "\n"));
+ if (line[keywordLength] != ' ')
+ FAIL_WITH_ERROR(SYNTAX_ERROR, ("'", keyword, "' must be followed by a ' ':\n", line, "\n"));
+
+ const char* delimiterStart = &line[keywordLength + 1];
+ const char* delimiterEnd = strstr(delimiterStart, "{");
+ if (!delimiterEnd)
+ FAIL_WITH_ERROR(SYNTAX_ERROR, ("Missing { after '", keyword, "' clause start delimiter:\n", line, "\n"));
+
+ size_t delimiterLength = delimiterEnd - delimiterStart;
+ String delimiter(delimiterStart, delimiterLength);
+
+ if (hasDisallowedCharacters(delimiterStart, delimiterLength))
+ FAIL_WITH_ERROR(SYNTAX_ERROR, ("Delimiter '", delimiter, "' cannot have '{', '}', or whitespace:\n", line, "\n"));
+
+ String terminatorString;
+ terminatorString.append("}");
+ terminatorString.append(delimiter);
+
+ const char* terminator = terminatorString.ascii().data();
+ line = delimiterEnd; // Start from the {.
+
+ StringBuilder builder;
+ do {
+ const char* p = strstr(line, terminator);
+ if (p) {
+ if (p[strlen(terminator)] != '\n')
+ FAIL_WITH_ERROR(SYNTAX_ERROR, ("Unexpected characters after '", keyword, "' clause end delimiter '", delimiter, "':\n", line, "\n"));
+
+ builder.append(line, p - line + 1);
+ return builder.toString();
+ }
+ builder.append(line);
+
+ } while ((line = fgets(buffer, bufferSize, file)));
+
+ FAIL_WITH_ERROR(SYNTAX_ERROR, ("'", keyword, "' clause end delimiter '", delimiter, "' not found:\n", builder.toString(), "\n", "Are you missing a '}' before the delimiter?\n"));
+}
+
+void FunctionOverrides::parseOverridesInFile(const char* fileName)
+{
+ if (!fileName)
+ return;
+
+ FILE* file = fopen(fileName, "r");
+ if (!file)
+ FAIL_WITH_ERROR(IO_ERROR, ("Failed to open file ", fileName, ". Did you add the file-read-data entitlement to WebProcess.sb?\n"));
+
+ char* line;
+ char buffer[BUFSIZ];
+ while ((line = fgets(buffer, sizeof(buffer), file))) {
+ if (strstr(line, "//") == line)
+ continue;
+
+ if (line[0] == '\n' || line[0] == '\0')
+ continue;
+
+ size_t keywordLength;
+
+ keywordLength = sizeof("override") - 1;
+ String keyStr = parseClause("override", keywordLength, file, line, buffer, sizeof(buffer));
+
+ line = fgets(buffer, sizeof(buffer), file);
+
+ keywordLength = sizeof("with") - 1;
+ String valueStr = parseClause("with", keywordLength, file, line, buffer, sizeof(buffer));
+
+ m_entries.add(keyStr, valueStr);
+ }
+
+ int result = fclose(file);
+ if (result)
+ dataLogF("Failed to close file %s: %s\n", fileName, strerror(errno));
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/tools/FunctionOverrides.h b/Source/JavaScriptCore/tools/FunctionOverrides.h
new file mode 100644
index 000000000..a0d8ad47a
--- /dev/null
+++ b/Source/JavaScriptCore/tools/FunctionOverrides.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FunctionOverrides_h
+#define FunctionOverrides_h
+
+#include "Options.h"
+#include "SourceCode.h"
+#include <wtf/HashMap.h>
+#include <wtf/text/WTFString.h>
+
+namespace JSC {
+
+class ScriptExecutable;
+
+class FunctionOverrides {
+public:
+ struct OverrideInfo {
+ SourceCode sourceCode;
+ unsigned firstLine;
+ unsigned lineCount;
+ unsigned startColumn;
+ unsigned endColumn;
+ unsigned parametersStartOffset;
+ unsigned typeProfilingStartOffset;
+ unsigned typeProfilingEndOffset;
+ };
+
+ static FunctionOverrides& overrides();
+ FunctionOverrides(const char* functionOverridesFileName);
+
+ static bool initializeOverrideFor(const SourceCode& origCode, OverrideInfo& result);
+
+private:
+ void parseOverridesInFile(const char* fileName);
+
+ HashMap<String, String> m_entries;
+};
+
+} // namespace JSC
+
+#endif // FunctionOverrides_h
diff --git a/Source/JavaScriptCore/tools/JSDollarVM.cpp b/Source/JavaScriptCore/tools/JSDollarVM.cpp
new file mode 100644
index 000000000..ee5c3d18e
--- /dev/null
+++ b/Source/JavaScriptCore/tools/JSDollarVM.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSDollarVM.h"
+
+#include "JSCJSValueInlines.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+const ClassInfo JSDollarVM::s_info = { "DollarVM", &Base::s_info, 0, CREATE_METHOD_TABLE(JSDollarVM) };
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/tools/JSDollarVM.h b/Source/JavaScriptCore/tools/JSDollarVM.h
new file mode 100644
index 000000000..6b5be038f
--- /dev/null
+++ b/Source/JavaScriptCore/tools/JSDollarVM.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSDollarVM_h
+#define JSDollarVM_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class JSDollarVM : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+
+ DECLARE_EXPORT_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ static JSDollarVM* create(VM& vm, Structure* structure)
+ {
+ JSDollarVM* instance = new (NotNull, allocateCell<JSDollarVM>(vm.heap)) JSDollarVM(vm, structure);
+ instance->finishCreation(vm);
+ return instance;
+ }
+
+private:
+ JSDollarVM(VM& vm, Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+};
+
+} // namespace JSC
+
+#endif // JSDollarVM_h
diff --git a/Source/JavaScriptCore/tools/JSDollarVMPrototype.cpp b/Source/JavaScriptCore/tools/JSDollarVMPrototype.cpp
new file mode 100644
index 000000000..26a8e77b1
--- /dev/null
+++ b/Source/JavaScriptCore/tools/JSDollarVMPrototype.cpp
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSDollarVMPrototype.h"
+
+#include "Heap.h"
+#include "HeapIterationScope.h"
+#include "JSCInlines.h"
+#include "JSFunction.h"
+#include "StackVisitor.h"
+#include <wtf/DataLog.h>
+
+namespace JSC {
+
+const ClassInfo JSDollarVMPrototype::s_info = { "DollarVMPrototype", &Base::s_info, 0, CREATE_METHOD_TABLE(JSDollarVMPrototype) };
+
+
+bool JSDollarVMPrototype::currentThreadOwnsJSLock(ExecState* exec)
+{
+ return exec->vm().apiLock().currentThreadIsHoldingLock();
+}
+
+static bool ensureCurrentThreadOwnsJSLock(ExecState* exec)
+{
+ if (JSDollarVMPrototype::currentThreadOwnsJSLock(exec))
+ return true;
+ dataLog("ERROR: current thread does not own the JSLock\n");
+ return false;
+}
+
+void JSDollarVMPrototype::addFunction(VM& vm, JSGlobalObject* globalObject, const char* name, NativeFunction function, unsigned arguments)
+{
+ Identifier identifier = Identifier::fromString(&vm, name);
+ putDirect(vm, identifier, JSFunction::create(vm, globalObject, arguments, identifier.string(), function));
+}
+
+static EncodedJSValue JSC_HOST_CALL functionCrash(ExecState*)
+{
+ CRASH();
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL functionDFGTrue(ExecState*)
+{
+ return JSValue::encode(jsBoolean(false));
+}
+
+class CallerFrameJITTypeFunctor {
+public:
+ CallerFrameJITTypeFunctor()
+ : m_currentFrame(0)
+ , m_jitType(JITCode::None)
+ {
+ }
+
+ StackVisitor::Status operator()(StackVisitor& visitor)
+ {
+ if (m_currentFrame++ > 1) {
+ m_jitType = visitor->codeBlock()->jitType();
+ return StackVisitor::Done;
+ }
+ return StackVisitor::Continue;
+ }
+
+ JITCode::JITType jitType() { return m_jitType; }
+
+private:
+ unsigned m_currentFrame;
+ JITCode::JITType m_jitType;
+};
+
+static EncodedJSValue JSC_HOST_CALL functionLLintTrue(ExecState* exec)
+{
+ if (!exec)
+ return JSValue::encode(jsUndefined());
+ CallerFrameJITTypeFunctor functor;
+ exec->iterate(functor);
+ return JSValue::encode(jsBoolean(functor.jitType() == JITCode::InterpreterThunk));
+}
+
+static EncodedJSValue JSC_HOST_CALL functionJITTrue(ExecState* exec)
+{
+ if (!exec)
+ return JSValue::encode(jsUndefined());
+ CallerFrameJITTypeFunctor functor;
+ exec->iterate(functor);
+ return JSValue::encode(jsBoolean(functor.jitType() == JITCode::BaselineJIT));
+}
+
+void JSDollarVMPrototype::gc(ExecState* exec)
+{
+ if (!ensureCurrentThreadOwnsJSLock(exec))
+ return;
+ exec->heap()->collectAllGarbage();
+}
+
+static EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec)
+{
+ JSDollarVMPrototype::gc(exec);
+ return JSValue::encode(jsUndefined());
+}
+
+void JSDollarVMPrototype::edenGC(ExecState* exec)
+{
+ if (!ensureCurrentThreadOwnsJSLock(exec))
+ return;
+ exec->heap()->collectAndSweep(EdenCollection);
+}
+
+static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
+{
+ JSDollarVMPrototype::edenGC(exec);
+ return JSValue::encode(jsUndefined());
+}
+
+bool JSDollarVMPrototype::isInHeap(Heap* heap, void* ptr)
+{
+ return isInObjectSpace(heap, ptr) || isInStorageSpace(heap, ptr);
+}
+
+bool JSDollarVMPrototype::isInObjectSpace(Heap* heap, void* ptr)
+{
+ MarkedBlock* candidate = MarkedBlock::blockFor(ptr);
+ return heap->objectSpace().blocks().set().contains(candidate);
+}
+
+bool JSDollarVMPrototype::isInStorageSpace(Heap* heap, void* ptr)
+{
+ CopiedBlock* candidate = CopiedSpace::blockFor(ptr);
+ return heap->storageSpace().contains(candidate);
+}
+
+struct CellAddressCheckFunctor : MarkedBlock::CountFunctor {
+ CellAddressCheckFunctor(JSCell* candidate)
+ : candidate(candidate)
+ {
+ }
+
+ IterationStatus operator()(JSCell* cell)
+ {
+ if (cell == candidate) {
+ found = true;
+ return IterationStatus::Done;
+ }
+ return IterationStatus::Continue;
+ }
+
+ JSCell* candidate;
+ bool found { false };
+};
+
+bool JSDollarVMPrototype::isValidCell(Heap* heap, JSCell* candidate)
+{
+ HeapIterationScope iterationScope(*heap);
+ CellAddressCheckFunctor functor(candidate);
+ heap->objectSpace().forEachLiveCell(iterationScope, functor);
+ return functor.found;
+}
+
+bool JSDollarVMPrototype::isValidCodeBlock(ExecState* exec, CodeBlock* candidate)
+{
+ if (!ensureCurrentThreadOwnsJSLock(exec))
+ return false;
+
+ struct CodeBlockValidationFunctor {
+ CodeBlockValidationFunctor(CodeBlock* candidate)
+ : candidate(candidate)
+ {
+ }
+
+ bool operator()(CodeBlock* codeBlock)
+ {
+ if (codeBlock == candidate)
+ found = true;
+ return found;
+ }
+
+ CodeBlock* candidate;
+ bool found { false };
+ };
+
+ VM& vm = exec->vm();
+ CodeBlockValidationFunctor functor(candidate);
+ vm.heap.forEachCodeBlock(functor);
+ return functor.found;
+}
+
+CodeBlock* JSDollarVMPrototype::codeBlockForFrame(CallFrame* topCallFrame, unsigned frameNumber)
+{
+ if (!ensureCurrentThreadOwnsJSLock(topCallFrame))
+ return nullptr;
+
+ if (!topCallFrame)
+ return nullptr;
+
+ struct FetchCodeBlockFunctor {
+ public:
+ FetchCodeBlockFunctor(unsigned targetFrameNumber)
+ : targetFrame(targetFrameNumber)
+ {
+ }
+
+ StackVisitor::Status operator()(StackVisitor& visitor)
+ {
+ currentFrame++;
+ if (currentFrame == targetFrame) {
+ codeBlock = visitor->codeBlock();
+ return StackVisitor::Done;
+ }
+ return StackVisitor::Continue;
+ }
+
+ unsigned targetFrame;
+ unsigned currentFrame { 0 };
+ CodeBlock* codeBlock { nullptr };
+ };
+
+ FetchCodeBlockFunctor functor(frameNumber);
+ topCallFrame->iterate(functor);
+ return functor.codeBlock;
+}
+
+static EncodedJSValue JSC_HOST_CALL functionCodeBlockForFrame(ExecState* exec)
+{
+ if (exec->argumentCount() < 1)
+ return JSValue::encode(jsUndefined());
+
+ JSValue value = exec->uncheckedArgument(0);
+ if (!value.isUInt32())
+ return JSValue::encode(jsUndefined());
+
+ // We need to inc the frame number because the caller would consider
+ // its own frame as frame 0. Hence, we need discount the frame for this
+ // function.
+ unsigned frameNumber = value.asUInt32() + 1;
+ CodeBlock* codeBlock = JSDollarVMPrototype::codeBlockForFrame(exec, frameNumber);
+ return JSValue::encode(JSValue(bitwise_cast<double>(reinterpret_cast<uint64_t>(codeBlock))));
+}
+
+static CodeBlock* codeBlockFromArg(ExecState* exec)
+{
+ if (exec->argumentCount() < 1)
+ return nullptr;
+
+ JSValue value = exec->uncheckedArgument(0);
+ if (!value.isDouble()) {
+ dataLog("Invalid codeBlock: ", value, "\n");
+ return nullptr;
+ }
+
+ CodeBlock* codeBlock = reinterpret_cast<CodeBlock*>(bitwise_cast<uint64_t>(value.asDouble()));
+ if (JSDollarVMPrototype::isValidCodeBlock(exec, codeBlock))
+ return codeBlock;
+
+ dataLogF("Invalid codeBlock: %p ", codeBlock);
+ dataLog(value, "\n");
+ return nullptr;
+
+}
+
+static EncodedJSValue JSC_HOST_CALL functionPrintSourceFor(ExecState* exec)
+{
+ CodeBlock* codeBlock = codeBlockFromArg(exec);
+ if (codeBlock)
+ codeBlock->dumpSource();
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL functionPrintByteCodeFor(ExecState* exec)
+{
+ CodeBlock* codeBlock = codeBlockFromArg(exec);
+ if (codeBlock)
+ codeBlock->dumpBytecode();
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
+{
+ for (unsigned i = 0; i < exec->argumentCount(); ++i) {
+ if (i)
+ dataLog(" ");
+ dataLog(exec->uncheckedArgument(i).toString(exec)->value(exec));
+ }
+ return JSValue::encode(jsUndefined());
+}
+
+class PrintFrameFunctor {
+public:
+ enum Action {
+ PrintOne,
+ PrintAll
+ };
+
+ PrintFrameFunctor(Action action, unsigned framesToSkip)
+ : m_action(action)
+ , m_framesToSkip(framesToSkip)
+ {
+ }
+
+ StackVisitor::Status operator()(StackVisitor& visitor)
+ {
+ m_currentFrame++;
+ if (m_currentFrame > m_framesToSkip)
+ visitor->print(2);
+
+ if (m_action == PrintOne && m_currentFrame > m_framesToSkip)
+ return StackVisitor::Done;
+ return StackVisitor::Continue;
+ }
+
+private:
+ Action m_action;
+ unsigned m_framesToSkip;
+ unsigned m_currentFrame { 0 };
+};
+
+static void printCallFrame(CallFrame* callFrame, unsigned framesToSkip)
+{
+ if (!ensureCurrentThreadOwnsJSLock(callFrame))
+ return;
+ PrintFrameFunctor functor(PrintFrameFunctor::PrintOne, framesToSkip);
+ callFrame->iterate(functor);
+}
+
+void JSDollarVMPrototype::printCallFrame(CallFrame* callFrame)
+{
+ JSC::printCallFrame(callFrame, 0);
+}
+
+static void printStack(CallFrame* topCallFrame, unsigned framesToSkip)
+{
+ if (!ensureCurrentThreadOwnsJSLock(topCallFrame))
+ return;
+ if (!topCallFrame)
+ return;
+ PrintFrameFunctor functor(PrintFrameFunctor::PrintAll, framesToSkip);
+ topCallFrame->iterate(functor);
+}
+
+void JSDollarVMPrototype::printStack(CallFrame* topCallFrame)
+{
+ JSC::printStack(topCallFrame, 0);
+}
+
+static EncodedJSValue JSC_HOST_CALL functionPrintCallFrame(ExecState* exec)
+{
+ // When the callers call this function, they are expecting to print their
+ // own frame. So skip 1 for this frame.
+ printCallFrame(exec, 1);
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL functionPrintStack(ExecState* exec)
+{
+ // When the callers call this function, they are expecting to print the
+ // stack starting their own frame. So skip 1 for this frame.
+ printStack(exec, 1);
+ return JSValue::encode(jsUndefined());
+}
+
+void JSDollarVMPrototype::printValue(JSValue value)
+{
+ dataLog(value);
+}
+
+static EncodedJSValue JSC_HOST_CALL functionPrintValue(ExecState* exec)
+{
+ for (unsigned i = 0; i < exec->argumentCount(); ++i) {
+ if (i)
+ dataLog(" ");
+ dataLog(exec->uncheckedArgument(i));
+ }
+ return JSValue::encode(jsUndefined());
+}
+
+void JSDollarVMPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
+{
+ Base::finishCreation(vm);
+
+ addFunction(vm, globalObject, "crash", functionCrash, 0);
+
+ putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "dfgTrue"), 0, functionDFGTrue, DFGTrueIntrinsic, DontEnum | JSC::Function);
+
+ addFunction(vm, globalObject, "llintTrue", functionLLintTrue, 0);
+ addFunction(vm, globalObject, "jitTrue", functionJITTrue, 0);
+
+ addFunction(vm, globalObject, "gc", functionGC, 0);
+ addFunction(vm, globalObject, "edenGC", functionEdenGC, 0);
+
+ addFunction(vm, globalObject, "codeBlockForFrame", functionCodeBlockForFrame, 1);
+ addFunction(vm, globalObject, "printSourceFor", functionPrintSourceFor, 1);
+ addFunction(vm, globalObject, "printByteCodeFor", functionPrintByteCodeFor, 1);
+
+ addFunction(vm, globalObject, "print", functionPrint, 1);
+ addFunction(vm, globalObject, "printCallFrame", functionPrintCallFrame, 0);
+ addFunction(vm, globalObject, "printStack", functionPrintStack, 0);
+
+ addFunction(vm, globalObject, "printValue", functionPrintValue, 1);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/tools/JSDollarVMPrototype.h b/Source/JavaScriptCore/tools/JSDollarVMPrototype.h
new file mode 100644
index 000000000..4c58be299
--- /dev/null
+++ b/Source/JavaScriptCore/tools/JSDollarVMPrototype.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSDollarVMPrototype_h
+#define JSDollarVMPrototype_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class Heap;
+
+class JSDollarVMPrototype : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+
+ DECLARE_INFO;
+
+ static JSDollarVMPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+ {
+ JSDollarVMPrototype* prototype = new (NotNull, allocateCell<JSDollarVMPrototype>(vm.heap)) JSDollarVMPrototype(vm, structure);
+ prototype->finishCreation(vm, globalObject);
+ return prototype;
+ }
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ // The following are exported because they are designed to be callable from
+ // lldb. The JS versions are implemented on top of these.
+
+ JS_EXPORT_PRIVATE static bool currentThreadOwnsJSLock(ExecState*);
+ JS_EXPORT_PRIVATE static void gc(ExecState*);
+ JS_EXPORT_PRIVATE static void edenGC(ExecState*);
+ JS_EXPORT_PRIVATE static bool isInHeap(Heap*, void*);
+ JS_EXPORT_PRIVATE static bool isInObjectSpace(Heap*, void*);
+ JS_EXPORT_PRIVATE static bool isInStorageSpace(Heap*, void*);
+ JS_EXPORT_PRIVATE static bool isValidCell(Heap*, JSCell*);
+ JS_EXPORT_PRIVATE static bool isValidCodeBlock(ExecState*, CodeBlock*);
+ JS_EXPORT_PRIVATE static CodeBlock* codeBlockForFrame(CallFrame* topCallFrame, unsigned frameNumber);
+ JS_EXPORT_PRIVATE static void printCallFrame(CallFrame*);
+ JS_EXPORT_PRIVATE static void printStack(CallFrame* topCallFrame);
+ JS_EXPORT_PRIVATE static void printValue(JSValue);
+
+private:
+ JSDollarVMPrototype(VM& vm, Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+
+ void finishCreation(VM&, JSGlobalObject*);
+ void addFunction(VM&, JSGlobalObject*, const char* name, NativeFunction, unsigned arguments);
+};
+
+} // namespace JSC
+
+#endif // JSDollarVMPrototype_h
diff --git a/Source/JavaScriptCore/tools/ProfileTreeNode.h b/Source/JavaScriptCore/tools/ProfileTreeNode.h
new file mode 100644
index 000000000..88d57f3dd
--- /dev/null
+++ b/Source/JavaScriptCore/tools/ProfileTreeNode.h
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ProfileTreeNode_h
+#define ProfileTreeNode_h
+
+namespace JSC {
+
+class ProfileTreeNode {
+ typedef HashMap<String, ProfileTreeNode> Map;
+ typedef Map::KeyValuePairType MapEntry;
+
+public:
+ ProfileTreeNode()
+ : m_count(0)
+ , m_children(0)
+ {
+ }
+
+ ~ProfileTreeNode()
+ {
+ delete m_children;
+ }
+
+ ProfileTreeNode* sampleChild(const char* name)
+ {
+ if (!m_children)
+ m_children = new Map();
+
+ ProfileTreeNode newEntry;
+ Map::AddResult result = m_children->add(String(name), newEntry);
+ ProfileTreeNode* childInMap = &result.iterator->value;
+ ++childInMap->m_count;
+ return childInMap;
+ }
+
+ void dump()
+ {
+ dumpInternal(0);
+ }
+
+ uint64_t count()
+ {
+ return m_count;
+ }
+
+ uint64_t childCount()
+ {
+ if (!m_children)
+ return 0;
+ uint64_t childCount = 0;
+ for (Map::iterator it = m_children->begin(); it != m_children->end(); ++it)
+ childCount += it->value.count();
+ return childCount;
+ }
+
+private:
+ void dumpInternal(unsigned indent)
+ {
+ if (!m_children)
+ return;
+
+ // Copy pointers to all children into a vector, and sort the vector by sample count.
+ Vector<MapEntry*> entries;
+ for (Map::iterator it = m_children->begin(); it != m_children->end(); ++it)
+ entries.append(&*it);
+ qsort(entries.begin(), entries.size(), sizeof(MapEntry*), compareEntries);
+
+ // Iterate over the children in sample-frequency order.
+ for (size_t e = 0; e < entries.size(); ++e) {
+ MapEntry* entry = entries[e];
+
+ // Print the number of samples, the name of this node, and the number of samples that are stack-top
+ // in this node (samples directly within this node, excluding samples in children.
+ for (unsigned i = 0; i < indent; ++i)
+ dataLogF(" ");
+ dataLogF("% 8lld: %s (%lld stack top)\n",
+ static_cast<long long>(entry->value.count()),
+ entry->key.utf8().data(),
+ static_cast<long long>(entry->value.count() - entry->value.childCount()));
+
+ // Recursively dump the child nodes.
+ entry->value.dumpInternal(indent + 1);
+ }
+ }
+
+ static int compareEntries(const void* a, const void* b)
+ {
+ uint64_t da = (*static_cast<MapEntry* const *>(a))->value.count();
+ uint64_t db = (*static_cast<MapEntry* const *>(b))->value.count();
+ return (da < db) - (da > db);
+ }
+
+ uint64_t m_count;
+ Map* m_children;
+};
+
+}
+
+#endif // ProfileTreeNode_h
+
diff --git a/Source/JavaScriptCore/tools/TieredMMapArray.h b/Source/JavaScriptCore/tools/TieredMMapArray.h
new file mode 100644
index 000000000..e0dfa3628
--- /dev/null
+++ b/Source/JavaScriptCore/tools/TieredMMapArray.h
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TieredMMapArray_h
+#define TieredMMapArray_h
+
+#include <wtf/OSAllocator.h>
+
+namespace JSC {
+
+// This class implements a simple array class that can be grown by appending items to the end.
+// This class is implemented purely in terms of system allocations, with no malloc/free, so that
+// it can safely be used from a secondary thread whilst the main thrad is paused (potentially
+// holding the fast malloc heap lock).
+template<typename T>
+class TieredMMapArray {
+ static const size_t entriesPerBlock = 4096;
+
+public:
+ TieredMMapArray()
+ : m_directoryCount(4096)
+ , m_directory(static_cast<T**>(OSAllocator::reserveAndCommit(m_directoryCount * sizeof(T*))))
+ , m_size(0)
+ {
+ for (size_t block = 0; block < m_directoryCount; ++block)
+ m_directory[block] = 0;
+ }
+
+ ~TieredMMapArray()
+ {
+ size_t usedCount = (m_size + (entriesPerBlock - 1)) / entriesPerBlock;
+ ASSERT(usedCount == m_directoryCount || !m_directory[usedCount]);
+
+ for (size_t block = 0; block < usedCount; ++block) {
+ ASSERT(m_directory[block]);
+ OSAllocator::decommitAndRelease(m_directory[block], entriesPerBlock * sizeof(T));
+ }
+
+ OSAllocator::decommitAndRelease(m_directory, m_directoryCount * sizeof(T*));
+ }
+
+ T& operator[](size_t index)
+ {
+ ASSERT(index < m_size);
+ size_t block = index / entriesPerBlock;
+ size_t offset = index % entriesPerBlock;
+
+ ASSERT(m_directory[block]);
+ return m_directory[block][offset];
+ }
+
+ void append(const T& value)
+ {
+ // Check if the array is completely full, if so create more capacity in the directory.
+ if (m_size == m_directoryCount * entriesPerBlock) {
+ // Reallocate the directory.
+ size_t oldDirectorySize = m_directoryCount * sizeof(T*);
+ size_t newDirectorySize = oldDirectorySize * 2;
+ RELEASE_ASSERT(newDirectorySize < oldDirectorySize);
+ m_directory = OSAllocator::reallocateCommitted(m_directory, oldDirectorySize, newDirectorySize);
+
+ //
+ size_t newDirectoryCount = m_directoryCount * 2;
+ for (size_t block = m_directoryCount; block < newDirectoryCount; ++block)
+ m_directory[block] = 0;
+ m_directoryCount = newDirectoryCount;
+ }
+
+ size_t index = m_size;
+ size_t block = index / entriesPerBlock;
+ size_t offset = index % entriesPerBlock;
+
+ if (!offset) {
+ ASSERT(!m_directory[block]);
+ m_directory[block] = static_cast<T*>(OSAllocator::reserveAndCommit(entriesPerBlock * sizeof(T)));
+ }
+
+ ASSERT(m_directory[block]);
+ ++m_size;
+ m_directory[block][offset] = value;
+ }
+
+ size_t size() const { return m_size; }
+
+private:
+ size_t m_directoryCount;
+ T** m_directory;
+ size_t m_size;
+};
+
+}
+
+#endif // TieredMMapArray_h
+