Value Profiles for arguments should be more easily accessible to the interpreter
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 21 Dec 2011 02:29:15 +0000 (02:29 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 21 Dec 2011 02:29:15 +0000 (02:29 +0000)
https://bugs.webkit.org/show_bug.cgi?id=74984
<rdar://problem/10611364>

Reviewed by Gavin Barraclough.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::stronglyVisitStrongReferences):
(JSC::CodeBlock::shouldOptimizeNow):
(JSC::CodeBlock::dumpValueProfiles):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::setArgumentValueProfileSize):
(JSC::CodeBlock::numberOfArgumentValueProfiles):
(JSC::CodeBlock::valueProfileForArgument):
(JSC::CodeBlock::addValueProfile):
(JSC::CodeBlock::valueProfile):
(JSC::CodeBlock::valueProfileForBytecodeOffset):
(JSC::CodeBlock::totalNumberOfValueProfiles):
(JSC::CodeBlock::getFromAllValueProfiles):
* bytecode/ValueProfile.h:
(JSC::ValueProfile::ValueProfile):
* jit/JIT.cpp:
(JSC::JIT::privateCompile):
* jit/JIT.h:
* jit/JITInlineMethods.h:
(JSC::JIT::emitValueProfilingSite):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@103384 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/ValueProfile.h
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITInlineMethods.h

index 20f7a3a..78ca26c 100644 (file)
@@ -1,3 +1,32 @@
+2011-12-20  Filip Pizlo  <fpizlo@apple.com>
+
+        Value Profiles for arguments should be more easily accessible to the interpreter
+        https://bugs.webkit.org/show_bug.cgi?id=74984
+        <rdar://problem/10611364>
+
+        Reviewed by Gavin Barraclough.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::stronglyVisitStrongReferences):
+        (JSC::CodeBlock::shouldOptimizeNow):
+        (JSC::CodeBlock::dumpValueProfiles):
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::setArgumentValueProfileSize):
+        (JSC::CodeBlock::numberOfArgumentValueProfiles):
+        (JSC::CodeBlock::valueProfileForArgument):
+        (JSC::CodeBlock::addValueProfile):
+        (JSC::CodeBlock::valueProfile):
+        (JSC::CodeBlock::valueProfileForBytecodeOffset):
+        (JSC::CodeBlock::totalNumberOfValueProfiles):
+        (JSC::CodeBlock::getFromAllValueProfiles):
+        * bytecode/ValueProfile.h:
+        (JSC::ValueProfile::ValueProfile):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompile):
+        * jit/JIT.h:
+        * jit/JITInlineMethods.h:
+        (JSC::JIT::emitValueProfilingSite):
+
 2011-12-20  Gavin Barraclough  <barraclough@apple.com>
 
         JSC shell should accept utf8 input.
index 74dcf1b..535b0dc 100644 (file)
@@ -1835,6 +1835,8 @@ void CodeBlock::stronglyVisitStrongReferences(SlotVisitor& visitor)
 #endif
 
 #if ENABLE(VALUE_PROFILER)
+    for (unsigned profileIndex = 0; profileIndex < numberOfArgumentValueProfiles(); ++profileIndex)
+        valueProfileForArgument(profileIndex)->computeUpdatedPrediction();
     for (unsigned profileIndex = 0; profileIndex < numberOfValueProfiles(); ++profileIndex)
         valueProfile(profileIndex)->computeUpdatedPrediction();
 #endif
@@ -2206,11 +2208,10 @@ bool CodeBlock::shouldOptimizeNow()
     if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay)
         return true;
     
-    unsigned numberOfNonArgumentValueProfiles = 0;
     unsigned numberOfLiveNonArgumentValueProfiles = 0;
     unsigned numberOfSamplesInProfiles = 0; // If this divided by ValueProfile::numberOfBuckets equals numberOfValueProfiles() then value profiles are full.
-    for (unsigned i = 0; i < numberOfValueProfiles(); ++i) {
-        ValueProfile* profile = valueProfile(i);
+    for (unsigned i = 0; i < totalNumberOfValueProfiles(); ++i) {
+        ValueProfile* profile = getFromAllValueProfiles(i);
         unsigned numSamples = profile->totalNumberOfSamples();
         if (numSamples > ValueProfile::numberOfBuckets)
             numSamples = ValueProfile::numberOfBuckets; // We don't want profiles that are extremely hot to be given more weight.
@@ -2219,18 +2220,17 @@ bool CodeBlock::shouldOptimizeNow()
             profile->computeUpdatedPrediction();
             continue;
         }
-        numberOfNonArgumentValueProfiles++;
         if (profile->numberOfSamples() || profile->m_prediction != PredictNone)
             numberOfLiveNonArgumentValueProfiles++;
         profile->computeUpdatedPrediction();
     }
 
 #if ENABLE(JIT_VERBOSE_OSR)
-    printf("Profile hotness: %lf, %lf\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfNonArgumentValueProfiles, (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles());
+    printf("Profile hotness: %lf, %lf\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles());
 #endif
 
-    if ((!numberOfNonArgumentValueProfiles || (double)numberOfLiveNonArgumentValueProfiles / numberOfNonArgumentValueProfiles >= Options::desiredProfileLivenessRate)
-        && (!numberOfValueProfiles() || (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles() >= Options::desiredProfileFullnessRate)
+    if ((!numberOfValueProfiles() || (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles() >= Options::desiredProfileLivenessRate)
+        && (!totalNumberOfValueProfiles() || (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / totalNumberOfValueProfiles() >= Options::desiredProfileFullnessRate)
         && static_cast<unsigned>(m_optimizationDelayCounter) + 1 >= Options::minimumOptimizationDelay)
         return true;
     
@@ -2267,8 +2267,8 @@ void CodeBlock::tallyFrequentExitSites()
 void CodeBlock::dumpValueProfiles()
 {
     fprintf(stderr, "ValueProfile for %p:\n", this);
-    for (unsigned i = 0; i < numberOfValueProfiles(); ++i) {
-        ValueProfile* profile = valueProfile(i);
+    for (unsigned i = 0; i < totalNumberOfValueProfiles(); ++i) {
+        ValueProfile* profile = getFromAllValueProfiles(i);
         if (profile->m_bytecodeOffset < 0) {
             ASSERT(profile->m_bytecodeOffset == -1);
             fprintf(stderr, "   arg = %u: ", i);
index 04319d5..159cb65 100644 (file)
@@ -657,28 +657,52 @@ namespace JSC {
 #endif
         
 #if ENABLE(VALUE_PROFILER)
+        void setArgumentValueProfileSize(unsigned size)
+        {
+            m_argumentValueProfiles.resize(size);
+        }
+        unsigned numberOfArgumentValueProfiles()
+        {
+            return m_argumentValueProfiles.size();
+        }
+        ValueProfile* valueProfileForArgument(unsigned argumentIndex)
+        {
+            ValueProfile* result = &m_argumentValueProfiles[argumentIndex];
+            ASSERT(result->m_bytecodeOffset == -1);
+            return result;
+        }
+        
         ValueProfile* addValueProfile(int bytecodeOffset)
         {
+            ASSERT(bytecodeOffset != -1);
             m_valueProfiles.append(ValueProfile(bytecodeOffset));
             return &m_valueProfiles.last();
         }
         unsigned numberOfValueProfiles() { return m_valueProfiles.size(); }
-        ValueProfile* valueProfile(int index) { return &m_valueProfiles[index]; }
-        ValueProfile* valueProfileForBytecodeOffset(int bytecodeOffset)
+        ValueProfile* valueProfile(int index)
         {
-            return WTF::genericBinarySearch<ValueProfile, int, getValueProfileBytecodeOffset>(m_valueProfiles, m_valueProfiles.size(), bytecodeOffset);
+            ValueProfile* result = &m_valueProfiles[index];
+            ASSERT(result->m_bytecodeOffset != -1);
+            return result;
         }
-        ValueProfile* valueProfileForArgument(int argument)
+        ValueProfile* valueProfileForBytecodeOffset(int bytecodeOffset)
         {
-            size_t index = argument;
-            if (index >= m_valueProfiles.size())
-                return 0;
-            ValueProfile* result = valueProfile(index);
-            if (result->m_bytecodeOffset != -1)
-                return 0;
+            ValueProfile* result = WTF::genericBinarySearch<ValueProfile, int, getValueProfileBytecodeOffset>(m_valueProfiles, m_valueProfiles.size(), bytecodeOffset);
+            ASSERT(result->m_bytecodeOffset != -1);
             return result;
         }
         
+        unsigned totalNumberOfValueProfiles()
+        {
+            return numberOfArgumentValueProfiles() + numberOfValueProfiles();
+        }
+        ValueProfile* getFromAllValueProfiles(unsigned index)
+        {
+            if (index < numberOfArgumentValueProfiles())
+                return valueProfileForArgument(index);
+            return valueProfile(index - numberOfArgumentValueProfiles());
+        }
+        
         RareCaseProfile* addRareCaseProfile(int bytecodeOffset)
         {
             m_rareCaseProfiles.append(RareCaseProfile(bytecodeOffset));
@@ -1251,6 +1275,7 @@ namespace JSC {
         DFG::ExitProfile m_exitProfile;
 #endif
 #if ENABLE(VALUE_PROFILER)
+        Vector<ValueProfile> m_argumentValueProfiles;
         SegmentedVector<ValueProfile, 8> m_valueProfiles;
         SegmentedVector<RareCaseProfile, 8> m_rareCaseProfiles;
         SegmentedVector<RareCaseProfile, 8> m_specialFastCaseProfiles;
index 4c41e6a..02a1d6b 100644 (file)
@@ -44,6 +44,15 @@ struct ValueProfile {
     static const unsigned bucketIndexMask = numberOfBuckets - 1;
     static const unsigned totalNumberOfBuckets = numberOfBuckets + numberOfSpecFailBuckets;
     
+    ValueProfile()
+        : m_bytecodeOffset(-1)
+        , m_prediction(PredictNone)
+        , m_numberOfSamplesInPrediction(0)
+    {
+        for (unsigned i = 0; i < totalNumberOfBuckets; ++i)
+            m_buckets[i] = JSValue::encode(JSValue());
+    }
+    
     ValueProfile(int bytecodeOffset)
         : m_bytecodeOffset(bytecodeOffset)
         , m_prediction(PredictNone)
index bd73ce0..64f808f 100644 (file)
@@ -557,21 +557,20 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck)
 #if ENABLE(VALUE_PROFILER)
         ASSERT(m_bytecodeOffset == (unsigned)-1);
         if (shouldEmitProfiling()) {
+            m_codeBlock->setArgumentValueProfileSize(m_codeBlock->m_numParameters);
             for (int argument = 0; argument < m_codeBlock->m_numParameters; ++argument) {
                 // If this is a constructor, then we want to put in a dummy profiling site (to
                 // keep things consistent) but we don't actually want to record the dummy value.
                 if (m_codeBlock->m_isConstructor && !argument)
-                    m_codeBlock->addValueProfile(-1);
-                else {
-                    int offset = CallFrame::argumentOffsetIncludingThis(argument) * static_cast<int>(sizeof(Register));
+                    continue;
+                int offset = CallFrame::argumentOffsetIncludingThis(argument) * static_cast<int>(sizeof(Register));
 #if USE(JSVALUE64)
-                    loadPtr(Address(callFrameRegister, offset), regT0);
+                loadPtr(Address(callFrameRegister, offset), regT0);
 #elif USE(JSVALUE32_64)
-                    load32(Address(callFrameRegister, offset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
-                    load32(Address(callFrameRegister, offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
+                load32(Address(callFrameRegister, offset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
+                load32(Address(callFrameRegister, offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
 #endif
-                    emitValueProfilingSite(FirstProfilingSite);
-                }
+                emitValueProfilingSite(m_codeBlock->valueProfileForArgument(argument));
             }
         }
 #endif
index e64e690..750b9d8 100644 (file)
@@ -337,6 +337,7 @@ namespace JSC {
 #if ENABLE(VALUE_PROFILER)
         // This assumes that the value to profile is in regT0 and that regT3 is available for
         // scratch.
+        void emitValueProfilingSite(ValueProfile*);
         void emitValueProfilingSite(ValueProfilingSiteKind);
 #else
         void emitValueProfilingSite(ValueProfilingSiteKind) { }
index f485157..5540ffa 100644 (file)
@@ -448,27 +448,17 @@ inline void JIT::emitAllocateJSFunction(FunctionExecutable* executable, Register
 }
 
 #if ENABLE(VALUE_PROFILER)
-inline void JIT::emitValueProfilingSite(ValueProfilingSiteKind siteKind)
+inline void JIT::emitValueProfilingSite(ValueProfile* valueProfile)
 {
-    if (!shouldEmitProfiling())
-        return;
-    
+    ASSERT(shouldEmitProfiling());
+    ASSERT(valueProfile);
+
     const RegisterID value = regT0;
 #if USE(JSVALUE32_64)
     const RegisterID valueTag = regT1;
 #endif
     const RegisterID scratch = regT3;
     
-    ValueProfile* valueProfile;
-    if (siteKind == FirstProfilingSite)
-        valueProfile = m_codeBlock->addValueProfile(m_bytecodeOffset);
-    else {
-        ASSERT(siteKind == SubsequentProfilingSite);
-        valueProfile = m_codeBlock->valueProfileForBytecodeOffset(m_bytecodeOffset);
-    }
-    
-    ASSERT(valueProfile);
-    
     if (ValueProfile::numberOfBuckets == 1) {
         // We're in a simple configuration: only one bucket, so we can just do a direct
         // store.
@@ -495,6 +485,22 @@ inline void JIT::emitValueProfilingSite(ValueProfilingSiteKind siteKind)
     store32(valueTag, BaseIndex(scratch, bucketCounterRegister, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
 #endif
 }
+
+inline void JIT::emitValueProfilingSite(ValueProfilingSiteKind siteKind)
+{
+    if (!shouldEmitProfiling())
+        return;
+    
+    ValueProfile* valueProfile;
+    if (siteKind == FirstProfilingSite)
+        valueProfile = m_codeBlock->addValueProfile(m_bytecodeOffset);
+    else {
+        ASSERT(siteKind == SubsequentProfilingSite);
+        valueProfile = m_codeBlock->valueProfileForBytecodeOffset(m_bytecodeOffset);
+    }
+    
+    emitValueProfilingSite(valueProfile);
+}
 #endif
 
 #if USE(JSVALUE32_64)