]> 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 d1cf2e88901b32874f6767e1eb426db1fea51840..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 {
+    public:
+        JS_EXPORT_PRIVATE static void start();
+        JS_EXPORT_PRIVATE static void stop();
+
+#if ENABLE(SAMPLING_FLAGS)
+        static void setFlag(unsigned flag)
+        {
+            ASSERT(flag >= 1);
+            ASSERT(flag <= 32);
+            s_flags |= 1u << (flag - 1);
+        }
+
+        static void clearFlag(unsigned flag)
+        {
+            ASSERT(flag >= 1);
+            ASSERT(flag <= 32);
+            s_flags &= ~(1u << (flag - 1));
+        }
+
+        static void sample();
+
+        class ScopedFlag {
+        public:
+            ScopedFlag(int flag)
+                : m_flag(flag)
+            {
+                setFlag(flag);
+            }
+
+            ~ScopedFlag()
+            {
+                clearFlag(m_flag);
+            }
+
+        private:
+            int m_flag;
+        };
+    
+        static const void* addressOfFlags()
+        {
+            return &s_flags;
+        }
+
+#endif
+    private:
+        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)
@@ -55,7 +195,7 @@ namespace JSC {
         {
         }
         
-        ~ScopeSampleRecord()
+        ~ScriptSampleRecord()
         {
             if (m_samples)
                 free(m_samples);
@@ -63,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;
@@ -71,21 +211,36 @@ namespace JSC {
         unsigned m_size;
     };
 
-    typedef WTF::HashMap<ScopeNode*, ScopeSampleRecord*> ScopeSampleRecordMap;
+    typedef HashMap<ScriptExecutable*, std::unique_ptr<ScriptSampleRecord>> ScriptSampleRecordMap;
+
+    class SamplingThread {
+    public:
+        // Sampling thread state.
+        static bool s_running;
+        static unsigned s_hertz;
+        static ThreadIdentifier s_samplingThread;
+
+        JS_EXPORT_PRIVATE static void start(unsigned hertz=10000);
+        JS_EXPORT_PRIVATE static void stop();
+
+        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()
@@ -99,55 +254,34 @@ 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 {
-        public:
-            CallRecord(SamplingTool*)
-            {
-            }
-        };
-
-        class HostCallRecord : public CallRecord {
+        class CallRecord {
+            WTF_MAKE_NONCOPYABLE(CallRecord);
         public:
-            HostCallRecord(SamplingTool* samplingTool)
-                : CallRecord(samplingTool)
+            CallRecord(SamplingTool*, bool = false)
             {
             }
         };
-#endif        
+#endif
 
         SamplingTool(Interpreter* interpreter)
             : m_interpreter(interpreter)
-            , m_running(false)
             , m_codeBlock(0)
             , m_sample(0)
             , m_sampleCount(0)
             , m_opcodeSampleCount(0)
-            , m_scopeSampleMap(new ScopeSampleRecordMap())
+#if ENABLE(CODEBLOCK_SAMPLING)
+            , m_scopeSampleMap(adoptPtr(new ScriptSampleRecordMap))
+#endif
         {
             memset(m_opcodeSamples, 0, sizeof(m_opcodeSamples));
             memset(m_opcodeSamplesInCTIFunctions, 0, sizeof(m_opcodeSamplesInCTIFunctions));
         }
 
-        ~SamplingTool()
-        {
-            deleteAllValues(*m_scopeSampleMap);
-        }
-
-        void start(unsigned hertz=10000);
-        void stop();
+        JS_EXPORT_PRIVATE void setup();
         void dump(ExecState*);
 
-        void notifyOfScope(ScopeNode* scope);
+        void notifyOfScope(VM&, ScriptExecutable* scope);
 
         void sample(CodeBlock* codeBlock, Instruction* vPC)
         {
@@ -165,6 +299,8 @@ namespace JSC {
             return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(vPC) | (static_cast<intptr_t>(inCTIFunction) << 1) | static_cast<intptr_t>(inHostFunction));
         }
 
+        static void sample();
+
     private:
         class Sample {
         public:
@@ -174,7 +310,7 @@ namespace JSC {
             {
             }
             
-            bool isNull() { return !m_sample || !m_codeBlock; }
+            bool isNull() { return !m_sample; }
             CodeBlock* codeBlock() { return m_codeBlock; }
             Instruction* vPC() { return reinterpret_cast<Instruction*>(m_sample & ~0x3); }
             bool inHostFunction() { return m_sample & 0x1; }
@@ -184,17 +320,12 @@ namespace JSC {
             intptr_t m_sample;
             CodeBlock* m_codeBlock;
         };
-        
-        static void* threadStartFunc(void*);
-        void run();
+
+        void doRun();
+        static SamplingTool* s_samplingTool;
         
         Interpreter* m_interpreter;
         
-        // Sampling thread state.
-        bool m_running;
-        unsigned m_hertz;
-        ThreadIdentifier m_samplingThread;
-
         // State tracked by the main thread, used by the sampling thread.
         CodeBlock* m_codeBlock;
         intptr_t m_sample;
@@ -205,8 +336,10 @@ namespace JSC {
         unsigned m_opcodeSamples[numOpcodeIDs];
         unsigned m_opcodeSamplesInCTIFunctions[numOpcodeIDs];
         
-        Mutex m_scopeSampleMapMutex;
-        OwnPtr<ScopeSampleRecordMap> m_scopeSampleMap;
+#if ENABLE(CODEBLOCK_SAMPLING)
+        Mutex m_scriptSampleMapMutex;
+        OwnPtr<ScriptSampleRecordMap> m_scopeSampleMap;
+#endif
     };
 
 } // namespace JSC