]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - bytecode/SamplingTool.h
JavaScriptCore-7600.1.4.11.8.tar.gz
[apple/javascriptcore.git] / bytecode / SamplingTool.h
index 7d7dc9c9593321c60689bed39418e4299bfa340c..678af85a45ffb8a2b7bc20d4b3585e2100f9ab1f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
  * 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
+ * 3.  Neither the name of Apple 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.
  *
 #ifndef SamplingTool_h
 #define SamplingTool_h
 
+#include "Strong.h"
+#include "Opcode.h"
+#include "SamplingCounter.h"
 #include <wtf/Assertions.h>
+#include <wtf/Atomics.h>
 #include <wtf/HashMap.h>
+#include <wtf/MainThread.h>
+#include <wtf/Spectrum.h>
 #include <wtf/Threading.h>
 
-#include "Nodes.h"
-#include "Opcode.h"
-
 namespace JSC {
 
+    class ScriptExecutable;
+
     class SamplingFlags {
-        friend class JIT;
     public:
-        static void start();
-        static void stop();
+        JS_EXPORT_PRIVATE static void start();
+        JS_EXPORT_PRIVATE static void stop();
 
 #if ENABLE(SAMPLING_FLAGS)
         static void setFlag(unsigned flag)
@@ -78,23 +82,111 @@ namespace JSC {
             int m_flag;
         };
     
+        static const void* addressOfFlags()
+        {
+            return &s_flags;
+        }
+
 #endif
     private:
-        static uint32_t s_flags;
+        JS_EXPORTDATA static uint32_t s_flags;
 #if ENABLE(SAMPLING_FLAGS)
         static uint64_t s_flagCounts[33];
 #endif
     };
 
+#if ENABLE(SAMPLING_REGIONS)
+    class SamplingRegion {
+    public:
+        // Create a scoped sampling region using a C string constant name that describes
+        // what you are doing. This must be a string constant that persists for the
+        // lifetime of the process and is immutable.
+        SamplingRegion(const char* name)
+        {
+            if (!isMainThread()) {
+                m_name = 0;
+                return;
+            }
+            
+            m_name = name;
+            exchangeCurrent(this, &m_previous);
+            ASSERT(!m_previous || m_previous > this);
+        }
+        
+        ~SamplingRegion()
+        {
+            if (!m_name)
+                return;
+            
+            ASSERT(bitwise_cast<SamplingRegion*>(s_currentOrReserved & ~1) == this);
+            exchangeCurrent(m_previous);
+        }
+        
+        static void sample();
+        
+        JS_EXPORT_PRIVATE static void dump();
+        
+    private:
+        const char* m_name;
+        SamplingRegion* m_previous;
+
+        static void exchangeCurrent(SamplingRegion* current, SamplingRegion** previousPtr = 0)
+        {
+            uintptr_t previous;
+            while (true) {
+                previous = s_currentOrReserved;
+                
+                // If it's reserved (i.e. sampling thread is reading it), loop around.
+                if (previous & 1) {
+#if OS(UNIX)
+                    sched_yield();
+#endif
+                    continue;
+                }
+                
+                // If we're going to CAS, then make sure previous is set.
+                if (previousPtr)
+                    *previousPtr = bitwise_cast<SamplingRegion*>(previous);
+                
+                if (WTF::weakCompareAndSwapUIntPtr(&s_currentOrReserved, previous, bitwise_cast<uintptr_t>(current)))
+                    break;
+            }
+        }
+        
+        static void dumpInternal();
+
+        class Locker {
+        public:
+            Locker();
+            ~Locker();
+        };
+
+        static volatile uintptr_t s_currentOrReserved;
+        
+        // rely on identity hashing of string constants
+        static Spectrum<const char*>* s_spectrum;
+        
+        static unsigned long s_noneOfTheAbove;
+        
+        static unsigned s_numberOfSamplesSinceDump;
+    };
+#else // ENABLE(SAMPLING_REGIONS)
+    class SamplingRegion {
+    public:
+        SamplingRegion(const char*) { }
+        JS_EXPORT_PRIVATE void dump();
+    };
+#endif // ENABLE(SAMPLING_REGIONS)
+
     class CodeBlock;
     class ExecState;
     class Interpreter;
     class ScopeNode;
     struct Instruction;
 
-    struct ScopeSampleRecord {
-        ScopeSampleRecord(ScopeNode* scope)
-            : m_scope(scope)
+    struct ScriptSampleRecord {
+        ScriptSampleRecord(VM& vm, ScriptExecutable* executable)
+            : m_executable(vm, executable)
             , m_codeBlock(0)
             , m_sampleCount(0)
             , m_opcodeSampleCount(0)
@@ -103,7 +195,7 @@ namespace JSC {
         {
         }
         
-        ~ScopeSampleRecord()
+        ~ScriptSampleRecord()
         {
             if (m_samples)
                 free(m_samples);
@@ -111,7 +203,7 @@ namespace JSC {
         
         void sample(CodeBlock*, Instruction*);
 
-        RefPtr<ScopeNode> m_scope;
+        Strong<ScriptExecutable> m_executable;
         CodeBlock* m_codeBlock;
         int m_sampleCount;
         int m_opcodeSampleCount;
@@ -119,7 +211,7 @@ namespace JSC {
         unsigned m_size;
     };
 
-    typedef WTF::HashMap<ScopeNode*, ScopeSampleRecord*> ScopeSampleRecordMap;
+    typedef HashMap<ScriptExecutable*, std::unique_ptr<ScriptSampleRecord>> ScriptSampleRecordMap;
 
     class SamplingThread {
     public:
@@ -128,25 +220,27 @@ namespace JSC {
         static unsigned s_hertz;
         static ThreadIdentifier s_samplingThread;
 
-        static void start(unsigned hertz=10000);
-        static void stop();
+        JS_EXPORT_PRIVATE static void start(unsigned hertz=10000);
+        JS_EXPORT_PRIVATE static void stop();
 
-        static void* threadStartFunc(void*);
+        static void threadStartFunc(void*);
     };
 
     class SamplingTool {
     public:
-        friend class CallRecord;
-        friend class HostCallRecord;
+        friend struct CallRecord;
         
 #if ENABLE(OPCODE_SAMPLING)
-        class CallRecord : Noncopyable {
+        class CallRecord {
+            WTF_MAKE_NONCOPYABLE(CallRecord);
         public:
-            CallRecord(SamplingTool* samplingTool)
+            CallRecord(SamplingTool* samplingTool, bool isHostCall = false)
                 : m_samplingTool(samplingTool)
                 , m_savedSample(samplingTool->m_sample)
                 , m_savedCodeBlock(samplingTool->m_codeBlock)
             {
+                if (isHostcall)
+                    samplingTool->m_sample |= 0x1;
             }
 
             ~CallRecord()
@@ -160,31 +254,15 @@ namespace JSC {
             intptr_t m_savedSample;
             CodeBlock* m_savedCodeBlock;
         };
-        
-        class HostCallRecord : public CallRecord {
-        public:
-            HostCallRecord(SamplingTool* samplingTool)
-                : CallRecord(samplingTool)
-            {
-                samplingTool->m_sample |= 0x1;
-            }
-        };
 #else
-        class CallRecord : Noncopyable {
+        class CallRecord {
+            WTF_MAKE_NONCOPYABLE(CallRecord);
         public:
-            CallRecord(SamplingTool*)
+            CallRecord(SamplingTool*, bool = false)
             {
             }
         };
-
-        class HostCallRecord : public CallRecord {
-        public:
-            HostCallRecord(SamplingTool* samplingTool)
-                : CallRecord(samplingTool)
-            {
-            }
-        };
-#endif        
+#endif
 
         SamplingTool(Interpreter* interpreter)
             : m_interpreter(interpreter)
@@ -193,24 +271,17 @@ namespace JSC {
             , m_sampleCount(0)
             , m_opcodeSampleCount(0)
 #if ENABLE(CODEBLOCK_SAMPLING)
-            , m_scopeSampleMap(new ScopeSampleRecordMap())
+            , m_scopeSampleMap(adoptPtr(new ScriptSampleRecordMap))
 #endif
         {
             memset(m_opcodeSamples, 0, sizeof(m_opcodeSamples));
             memset(m_opcodeSamplesInCTIFunctions, 0, sizeof(m_opcodeSamplesInCTIFunctions));
         }
 
-        ~SamplingTool()
-        {
-#if ENABLE(CODEBLOCK_SAMPLING)
-            deleteAllValues(*m_scopeSampleMap);
-#endif
-        }
-
-        void setup();
+        JS_EXPORT_PRIVATE void setup();
         void dump(ExecState*);
 
-        void notifyOfScope(ScopeNode* scope);
+        void notifyOfScope(VM&, ScriptExecutable* scope);
 
         void sample(CodeBlock* codeBlock, Instruction* vPC)
         {
@@ -266,147 +337,11 @@ namespace JSC {
         unsigned m_opcodeSamplesInCTIFunctions[numOpcodeIDs];
         
 #if ENABLE(CODEBLOCK_SAMPLING)
-        Mutex m_scopeSampleMapMutex;
-        OwnPtr<ScopeSampleRecordMap> m_scopeSampleMap;
+        Mutex m_scriptSampleMapMutex;
+        OwnPtr<ScriptSampleRecordMap> m_scopeSampleMap;
 #endif
     };
 
-    // AbstractSamplingCounter:
-    //
-    // Implements a named set of counters, printed on exit if ENABLE(SAMPLING_COUNTERS).
-    // See subclasses below, SamplingCounter, GlobalSamplingCounter and DeletableSamplingCounter.
-    class AbstractSamplingCounter {
-        friend class JIT;
-        friend class DeletableSamplingCounter;
-    public:
-        void count(uint32_t count = 1)
-        {
-            m_counter += count;
-        }
-
-        static void dump();
-
-    protected:
-        // Effectively the contructor, however called lazily in the case of GlobalSamplingCounter.
-        void init(const char* name)
-        {
-            m_counter = 0;
-            m_name = name;
-
-            // Set m_next to point to the head of the chain, and inform whatever is
-            // currently at the head that this node will now hold the pointer to it.
-            m_next = s_abstractSamplingCounterChain;
-            s_abstractSamplingCounterChain->m_referer = &m_next;
-            // Add this node to the head of the list.
-            s_abstractSamplingCounterChain = this;
-            m_referer = &s_abstractSamplingCounterChain;
-        }
-
-        int64_t m_counter;
-        const char* m_name;
-        AbstractSamplingCounter* m_next;
-        // This is a pointer to the pointer to this node in the chain; used to
-        // allow fast linked list deletion.
-        AbstractSamplingCounter** m_referer;
-        // Null object used to detect end of static chain.
-        static AbstractSamplingCounter s_abstractSamplingCounterChainEnd;
-        static AbstractSamplingCounter* s_abstractSamplingCounterChain;
-        static bool s_completed;
-    };
-
-#if ENABLE(SAMPLING_COUNTERS)
-    // SamplingCounter:
-    //
-    // This class is suitable and (hopefully!) convenient for cases where a counter is
-    // required within the scope of a single function.  It can be instantiated as a
-    // static variable since it contains a constructor but not a destructor (static
-    // variables in WebKit cannot have destructors).
-    //
-    // For example:
-    //
-    // void someFunction()
-    // {
-    //     static SamplingCounter countMe("This is my counter.  There are many like it, but this one is mine.");
-    //     countMe.count();
-    //     // ...
-    // }
-    //
-    class SamplingCounter : public AbstractSamplingCounter {
-    public:
-        SamplingCounter(const char* name) { init(name); }
-    };
-
-    // GlobalSamplingCounter:
-    //
-    // This class is suitable for use where a counter is to be declared globally,
-    // since it contains neither a constructor nor destructor.  Instead, ensure
-    // that 'name()' is called to provide the counter with a name (and also to
-    // allow it to be printed out on exit).
-    //
-    // GlobalSamplingCounter globalCounter;
-    //
-    // void firstFunction()
-    // {
-    //     // Put this within a function that is definitely called!
-    //     // (Or alternatively alongside all calls to 'count()').
-    //     globalCounter.name("I Name You Destroyer.");
-    //     globalCounter.count();
-    //     // ...
-    // }
-    //
-    // void secondFunction()
-    // {
-    //     globalCounter.count();
-    //     // ...
-    // }
-    //
-    class GlobalSamplingCounter : public AbstractSamplingCounter {
-    public:
-        void name(const char* name)
-        {
-            // Global objects should be mapped in zero filled memory, so this should
-            // be a safe (albeit not necessarily threadsafe) check for 'first call'.
-            if (!m_next)
-                init(name);
-        }
-    };
-
-    // DeletableSamplingCounter:
-    //
-    // The above classes (SamplingCounter, GlobalSamplingCounter), are intended for
-    // use within a global or static scope, and as such cannot have a destructor.
-    // This means there is no convenient way for them to remove themselves from the
-    // static list of counters, and should an instance of either class be freed
-    // before 'dump()' has walked over the list it will potentially walk over an
-    // invalid pointer.
-    //
-    // This class is intended for use where the counter may possibly be deleted before
-    // the program exits.  Should this occur, the counter will print it's value to
-    // stderr, and remove itself from the static list.  Example:
-    //
-    // DeletableSamplingCounter* counter = new DeletableSamplingCounter("The Counter With No Name");
-    // counter->count();
-    // delete counter;
-    //
-    class DeletableSamplingCounter : public AbstractSamplingCounter {
-    public:
-        DeletableSamplingCounter(const char* name) { init(name); }
-
-        ~DeletableSamplingCounter()
-        {
-            if (!s_completed)
-                fprintf(stderr, "DeletableSamplingCounter \"%s\" deleted early (with count %lld)\n", m_name, m_counter);
-            // Our m_referer pointer should know where the pointer to this node is,
-            // and m_next should know that this node is the previous node in the list.
-            ASSERT(*m_referer == this);
-            ASSERT(m_next->m_referer == &m_next);
-            // Remove this node from the list, and inform m_next that we have done so.
-            m_next->m_referer = m_referer;
-            *m_referer = m_next;
-        }
-    };
-#endif
-
 } // namespace JSC
 
 #endif // SamplingTool_h