Title: [93466] trunk/Source/_javascript_Core
Revision
93466
Author
[email protected]
Date
2011-08-19 19:17:49 -0700 (Fri, 19 Aug 2011)

Log Message

The JSC JIT currently has no facility to profile and report
the types of values
https://bugs.webkit.org/show_bug.cgi?id=65901

Reviewed by Gavin Barraclough.

Added the ability to profile the values seen at function calls (both
arguments and results) and heap loads.  This is done with emphasis
on performance.  A value profiling site consists of: add, and,
move, and store; no branching is necessary.  Each value profiling
site (called a ValueProfile) has a ring buffer of 8 recently-seen
values.  ValueProfiles are stored in the CodeBlock; there will be
one for each argument (excluding this) and each heap load or callsite.
Each time a value profiling site executes, it stores the value into
a pseudo-random element in the ValueProfile buffer.  The point is
that for frequently executed code, we will have 8 somewhat recent
values in the buffer and will be able to not only figure out what
type it is, but also to be able to reason about the actual values
if we wish to do so.

This feature is currently disabled by default.  When enabled, it
results in a 3.7% slow-down on SunSpider.

* _javascript_Core.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::~CodeBlock):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::addValueProfile):
(JSC::CodeBlock::numberOfValueProfiles):
(JSC::CodeBlock::valueProfile):
(JSC::CodeBlock::valueProfileForBytecodeOffset):
* bytecode/ValueProfile.h: Added.
(JSC::ValueProfile::ValueProfile):
(JSC::ValueProfile::numberOfSamples):
(JSC::ValueProfile::computeProbability):
(JSC::ValueProfile::numberOfInt32s):
(JSC::ValueProfile::numberOfDoubles):
(JSC::ValueProfile::numberOfCells):
(JSC::ValueProfile::probabilityOfInt32):
(JSC::ValueProfile::probabilityOfDouble):
(JSC::ValueProfile::probabilityOfCell):
(JSC::getValueProfileBytecodeOffset):
* jit/JIT.cpp:
(JSC::JIT::privateCompileSlowCases):
(JSC::JIT::privateCompile):
* jit/JIT.h:
(JSC::JIT::emitValueProfilingSite):
* jit/JITCall.cpp:
(JSC::JIT::emit_op_call_put_result):
* jit/JITInlineMethods.h:
(JSC::JIT::emitValueProfilingSite):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emitSlow_op_get_by_val):
(JSC::JIT::emit_op_method_check):
(JSC::JIT::emit_op_get_by_id):
(JSC::JIT::emitSlow_op_get_by_id):
* jit/JSInterfaceJIT.h:
* wtf/Platform.h:
* wtf/StdLibExtras.h:
(WTF::binarySearch):
(WTF::genericBinarySearch):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (93465 => 93466)


--- trunk/Source/_javascript_Core/ChangeLog	2011-08-20 01:47:51 UTC (rev 93465)
+++ trunk/Source/_javascript_Core/ChangeLog	2011-08-20 02:17:49 UTC (rev 93466)
@@ -1,3 +1,68 @@
+2011-08-19  Filip Pizlo  <[email protected]>
+
+        The JSC JIT currently has no facility to profile and report
+        the types of values
+        https://bugs.webkit.org/show_bug.cgi?id=65901
+
+        Reviewed by Gavin Barraclough.
+        
+        Added the ability to profile the values seen at function calls (both
+        arguments and results) and heap loads.  This is done with emphasis
+        on performance.  A value profiling site consists of: add, and,
+        move, and store; no branching is necessary.  Each value profiling
+        site (called a ValueProfile) has a ring buffer of 8 recently-seen
+        values.  ValueProfiles are stored in the CodeBlock; there will be
+        one for each argument (excluding this) and each heap load or callsite.
+        Each time a value profiling site executes, it stores the value into
+        a pseudo-random element in the ValueProfile buffer.  The point is
+        that for frequently executed code, we will have 8 somewhat recent
+        values in the buffer and will be able to not only figure out what
+        type it is, but also to be able to reason about the actual values
+        if we wish to do so.
+        
+        This feature is currently disabled by default.  When enabled, it
+        results in a 3.7% slow-down on SunSpider.
+
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::~CodeBlock):
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::addValueProfile):
+        (JSC::CodeBlock::numberOfValueProfiles):
+        (JSC::CodeBlock::valueProfile):
+        (JSC::CodeBlock::valueProfileForBytecodeOffset):
+        * bytecode/ValueProfile.h: Added.
+        (JSC::ValueProfile::ValueProfile):
+        (JSC::ValueProfile::numberOfSamples):
+        (JSC::ValueProfile::computeProbability):
+        (JSC::ValueProfile::numberOfInt32s):
+        (JSC::ValueProfile::numberOfDoubles):
+        (JSC::ValueProfile::numberOfCells):
+        (JSC::ValueProfile::probabilityOfInt32):
+        (JSC::ValueProfile::probabilityOfDouble):
+        (JSC::ValueProfile::probabilityOfCell):
+        (JSC::getValueProfileBytecodeOffset):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileSlowCases):
+        (JSC::JIT::privateCompile):
+        * jit/JIT.h:
+        (JSC::JIT::emitValueProfilingSite):
+        * jit/JITCall.cpp:
+        (JSC::JIT::emit_op_call_put_result):
+        * jit/JITInlineMethods.h:
+        (JSC::JIT::emitValueProfilingSite):
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_get_by_val):
+        (JSC::JIT::emitSlow_op_get_by_val):
+        (JSC::JIT::emit_op_method_check):
+        (JSC::JIT::emit_op_get_by_id):
+        (JSC::JIT::emitSlow_op_get_by_id):
+        * jit/JSInterfaceJIT.h:
+        * wtf/Platform.h:
+        * wtf/StdLibExtras.h:
+        (WTF::binarySearch):
+        (WTF::genericBinarySearch):
+
 2011-08-19  Daniel Bates  <[email protected]>
 
         Don't include DisallowCType.h when building on QNX

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (93465 => 93466)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2011-08-20 01:47:51 UTC (rev 93465)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2011-08-20 02:17:49 UTC (rev 93466)
@@ -49,6 +49,7 @@
 		0BDFFAE10FC6193100D69EF4 /* OwnFastMallocPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BDFFAD10FC616EC00D69EF4 /* OwnFastMallocPtr.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0BF28A2911A33DC300638F84 /* SizeLimits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0BF28A2811A33DC300638F84 /* SizeLimits.cpp */; };
 		0F29479C126E698C00B3ABF5 /* DecimalNumber.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F29479B126E698C00B3ABF5 /* DecimalNumber.cpp */; };
+		0F963B3813FC6FE90002D9B2 /* ValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		1400067712A6F7830064D123 /* OSAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 1400067612A6F7830064D123 /* OSAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		1400069312A6F9E10064D123 /* OSAllocatorPosix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1400069212A6F9E10064D123 /* OSAllocatorPosix.cpp */; };
 		140566C4107EC255005DBC8D /* JSAPIValueWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC0894D50FAFBA2D00001865 /* JSAPIValueWrapper.cpp */; };
@@ -729,6 +730,7 @@
 		0BDFFAD40FC6171000D69EF4 /* CrossThreadRefCounted.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CrossThreadRefCounted.h; sourceTree = "<group>"; };
 		0BF28A2811A33DC300638F84 /* SizeLimits.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SizeLimits.cpp; sourceTree = "<group>"; };
 		0F29479B126E698C00B3ABF5 /* DecimalNumber.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DecimalNumber.cpp; sourceTree = "<group>"; };
+		0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ValueProfile.h; sourceTree = "<group>"; };
 		1400067612A6F7830064D123 /* OSAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OSAllocator.h; sourceTree = "<group>"; };
 		1400069212A6F9E10064D123 /* OSAllocatorPosix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OSAllocatorPosix.cpp; sourceTree = "<group>"; };
 		140D17D60E8AD4A9000CD17D /* JSBasePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSBasePrivate.h; sourceTree = "<group>"; };
@@ -2163,6 +2165,7 @@
 		969A078F0ED1D3AE00F1F681 /* bytecode */ = {
 			isa = PBXGroup;
 			children = (
+				0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */,
 				969A07900ED1D3AE00F1F681 /* CodeBlock.cpp */,
 				969A07910ED1D3AE00F1F681 /* CodeBlock.h */,
 				969A07920ED1D3AE00F1F681 /* EvalCodeCache.h */,
@@ -2230,6 +2233,7 @@
 				86D3B2C410156BDE002865E7 /* ARMAssembler.h in Headers */,
 				86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */,
 				BC18C3E60E16F5CD00B34460 /* ArrayConstructor.h in Headers */,
+				0F963B3813FC6FE90002D9B2 /* ValueProfile.h in Headers */,
 				BC18C3E70E16F5CD00B34460 /* ArrayPrototype.h in Headers */,
 				BC18C5240E16FC8A00B34460 /* ArrayPrototype.lut.h in Headers */,
 				BC18C3E90E16F5CD00B34460 /* ASCIICType.h in Headers */,

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (93465 => 93466)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2011-08-20 01:47:51 UTC (rev 93465)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2011-08-20 02:17:49 UTC (rev 93466)
@@ -1432,6 +1432,23 @@
 
 CodeBlock::~CodeBlock()
 {
+#if ENABLE(VERBOSE_VALUE_PROFILE)
+    printf("ValueProfile for %p:\n", this);
+    for (unsigned i = 0; i < numberOfValueProfiles(); ++i) {
+        ValueProfile* profile = ""
+        if (profile->bytecodeOffset < 0) {
+            ASSERT(profile->bytecodeOffset == -1);
+            printf("   arg = %u: ", i + 1);
+        } else
+            printf("   bc = %d: ", profile->bytecodeOffset);
+        printf("samples = %u, int32 = %u, double = %u, cell = %u\n",
+               profile->numberOfSamples(),
+               profile->probabilityOfInt32(),
+               profile->probabilityOfDouble(),
+               profile->probabilityOfCell());
+    }
+#endif
+
 #if ENABLE(JIT)
     for (size_t size = m_structureStubInfos.size(), i = 0; i < size; ++i)
         m_structureStubInfos[i].deref();

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.h (93465 => 93466)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.h	2011-08-20 01:47:51 UTC (rev 93465)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.h	2011-08-20 02:17:49 UTC (rev 93466)
@@ -39,9 +39,11 @@
 #include "Nodes.h"
 #include "RegExpObject.h"
 #include "UString.h"
+#include "ValueProfile.h"
 #include <wtf/FastAllocBase.h>
 #include <wtf/PassOwnPtr.h>
 #include <wtf/RefPtr.h>
+#include <wtf/SegmentedVector.h>
 #include <wtf/Vector.h>
 
 #if ENABLE(JIT)
@@ -381,6 +383,21 @@
         void addMethodCallLinkInfos(unsigned n) { ASSERT(m_globalData->canUseJIT()); m_methodCallLinkInfos.grow(n); }
         MethodCallLinkInfo& methodCallLinkInfo(int index) { return m_methodCallLinkInfos[index]; }
 #endif
+        
+#if ENABLE(VALUE_PROFILER)
+        ValueProfile* addValueProfile(int bytecodeOffset)
+        {
+            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)
+        {
+            return WTF::genericBinarySearch<ValueProfile, int, getValueProfileBytecodeOffset>(m_valueProfiles, m_valueProfiles.size(), bytecodeOffset);
+        }
+#endif
+
         unsigned globalResolveInfoCount() const
         {
 #if ENABLE(JIT)    
@@ -576,6 +593,9 @@
         Vector<CallLinkInfo> m_callLinkInfos;
         Vector<MethodCallLinkInfo> m_methodCallLinkInfos;
 #endif
+#if ENABLE(VALUE_PROFILER)
+        SegmentedVector<ValueProfile, 8> m_valueProfiles;
+#endif
 
         Vector<unsigned> m_jumpTargets;
 

Added: trunk/Source/_javascript_Core/bytecode/ValueProfile.h (0 => 93466)


--- trunk/Source/_javascript_Core/bytecode/ValueProfile.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/bytecode/ValueProfile.h	2011-08-20 02:17:49 UTC (rev 93466)
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ValueProfile_h
+#define ValueProfile_h
+
+#include "WriteBarrier.h"
+
+namespace JSC {
+
+#if ENABLE(VALUE_PROFILER)
+struct ValueProfile {
+    static const unsigned logNumberOfBuckets = 3; // 8 buckets
+    static const unsigned numberOfBuckets = 1 << logNumberOfBuckets;
+    static const unsigned bucketIndexMask = numberOfBuckets - 1;
+    static const unsigned certainty = numberOfBuckets * numberOfBuckets;
+    static const unsigned majority = certainty / 2;
+    
+    ValueProfile(int bytecodeOffset)
+        : bytecodeOffset(bytecodeOffset)
+    {
+        for (unsigned i = 0; i < numberOfBuckets; ++i)
+            buckets[i].setWithoutWriteBarrier(JSValue());
+    }
+    
+    unsigned numberOfSamples() const
+    {
+        unsigned result = 0;
+        for (unsigned i = 0; i < numberOfBuckets; ++i) {
+            if (!!buckets[i])
+                result++;
+        }
+        return result;
+    }
+    
+    static unsigned computeProbability(unsigned counts, unsigned numberOfSamples)
+    {
+        if (!numberOfSamples)
+            return 0;
+        return counts * certainty / numberOfSamples;
+    }
+        
+    unsigned numberOfInt32s() const
+    {
+        unsigned result = 0;
+        for (unsigned i = 0; i < numberOfBuckets; ++i) {
+            if (!!buckets[i] && buckets[i].get().isInt32())
+                result++;
+        }
+        return result;
+    }
+        
+    unsigned numberOfDoubles() const
+    {
+        unsigned result = 0;
+        for (unsigned i = 0; i < numberOfBuckets; ++i) {
+            if (!!buckets[i] && buckets[i].get().isDouble())
+                result++;
+        }
+        return result;
+    }
+        
+    unsigned numberOfCells() const
+    {
+        unsigned result = 0;
+        for (unsigned i = 0; i < numberOfBuckets; ++i) {
+            if (!!buckets[i] && buckets[i].get().isCell())
+                result++;
+        }
+        return result;
+    }
+        
+    // These methods are not particularly optimized, in that they will each
+    // perform two passes over the buckets array. However, they are
+    // probably the best bet unless you are sure that you will be making
+    // these calls with high frequency.
+        
+    unsigned probabilityOfInt32() const
+    {
+        return computeProbability(numberOfInt32s(), numberOfSamples());
+    }
+        
+    unsigned probabilityOfDouble() const
+    {
+        return computeProbability(numberOfDoubles(), numberOfSamples());
+    }
+    
+    unsigned probabilityOfCell() const
+    {
+        return computeProbability(numberOfCells(), numberOfSamples());
+    }
+    
+    int bytecodeOffset; // -1 for prologue
+    WriteBarrierBase<Unknown> buckets[numberOfBuckets];
+};
+
+inline int getValueProfileBytecodeOffset(ValueProfile* valueProfile)
+{
+    return valueProfile->bytecodeOffset;
+}
+#endif
+
+}
+
+#endif
+

Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (93465 => 93466)


--- trunk/Source/_javascript_Core/jit/JIT.cpp	2011-08-20 01:47:51 UTC (rev 93465)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp	2011-08-20 02:17:49 UTC (rev 93466)
@@ -372,6 +372,16 @@
     m_propertyAccessInstructionIndex = 0;
     m_globalResolveInfoIndex = 0;
     m_callLinkInfoIndex = 0;
+    
+#if !ASSERT_DISABLED && ENABLE(VALUE_PROFILER)
+    // Use this to assert that slow-path code associates new profiling sites with existing
+    // ValueProfiles rather than creating new ones. This ensures that for a given instruction
+    // (say, get_by_id) we get combined statistics for both the fast-path executions of that
+    // instructions and the slow-path executions. Furthermore, if the slow-path code created
+    // new ValueProfiles then the ValueProfiles would no longer be sorted by bytecode offset,
+    // which would break the invariant necessary to use CodeBlock::valueProfileForBytecodeOffset().
+    unsigned numberOfValueProfiles = m_codeBlock->numberOfValueProfiles();
+#endif
 
     for (Vector<SlowCaseEntry>::iterator iter = m_slowCases.begin(); iter != m_slowCases.end();) {
 #if USE(JSVALUE64)
@@ -461,6 +471,9 @@
 
     ASSERT(m_propertyAccessInstructionIndex == m_propertyAccessCompilationInfo.size());
     ASSERT(m_callLinkInfoIndex == m_callStructureStubCompilationInfo.size());
+#if ENABLE(VALUE_PROFILER)
+    ASSERT(numberOfValueProfiles == m_codeBlock->numberOfValueProfiles());
+#endif
 
 #ifndef NDEBUG
     // Reset this, in order to guard its use with ASSERTs.
@@ -492,6 +505,14 @@
         emitCount(counter);
 #endif
 
+#if ENABLE(VALUE_PROFILER)
+        ASSERT(m_bytecodeOffset == (unsigned)-1);
+        for (int argumentRegister = -RegisterFile::CallFrameHeaderSize - m_codeBlock->m_numParameters + 1; argumentRegister < -RegisterFile::CallFrameHeaderSize; ++argumentRegister) {
+            loadPtr(Address(callFrameRegister, argumentRegister * sizeof(Register)), regT0);
+            emitValueProfilingSite(FirstProfilingSite);
+        }
+#endif
+
         // In the case of a fast linked call, we do not set this up in the caller.
         emitPutImmediateToCallFrameHeader(m_codeBlock, RegisterFile::CodeBlock);
 

Modified: trunk/Source/_javascript_Core/jit/JIT.h (93465 => 93466)


--- trunk/Source/_javascript_Core/jit/JIT.h	2011-08-20 01:47:51 UTC (rev 93465)
+++ trunk/Source/_javascript_Core/jit/JIT.h	2011-08-20 02:17:49 UTC (rev 93466)
@@ -304,6 +304,15 @@
         template<typename ClassType, typename StructureType> void emitAllocateBasicJSObject(StructureType, void* vtable, RegisterID result, RegisterID storagePtr);
         template<typename T> void emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID storagePtr);
         void emitAllocateJSFunction(FunctionExecutable*, RegisterID scopeChain, RegisterID result, RegisterID storagePtr);
+        
+        enum ValueProfilingSiteKind { FirstProfilingSite, SubsequentProfilingSite };
+#if ENABLE(VALUE_PROFILER)
+        // This assumes that the value to profile is in regT0 and that regT3 is available for
+        // scratch.
+        void emitValueProfilingSite(ValueProfilingSiteKind);
+#else
+        void emitValueProfilingSite(ValueProfilingSiteKind) { }
+#endif
 
 #if USE(JSVALUE32_64)
         bool getOperandConstantImmediateInt(unsigned op1, unsigned op2, unsigned& op, int32_t& constant);

Modified: trunk/Source/_javascript_Core/jit/JITCall.cpp (93465 => 93466)


--- trunk/Source/_javascript_Core/jit/JITCall.cpp	2011-08-20 01:47:51 UTC (rev 93465)
+++ trunk/Source/_javascript_Core/jit/JITCall.cpp	2011-08-20 02:17:49 UTC (rev 93466)
@@ -58,6 +58,7 @@
 void JIT::emit_op_call_put_result(Instruction* instruction)
 {
     int dst = instruction[1].u.operand;
+    emitValueProfilingSite(FirstProfilingSite);
     emitPutVirtualRegister(dst);
 }
 

Modified: trunk/Source/_javascript_Core/jit/JITInlineMethods.h (93465 => 93466)


--- trunk/Source/_javascript_Core/jit/JITInlineMethods.h	2011-08-20 01:47:51 UTC (rev 93465)
+++ trunk/Source/_javascript_Core/jit/JITInlineMethods.h	2011-08-20 02:17:49 UTC (rev 93466)
@@ -430,6 +430,32 @@
 #endif
 }
 
+#if ENABLE(VALUE_PROFILER)
+inline void JIT::emitValueProfilingSite(ValueProfilingSiteKind siteKind)
+{
+    const RegisterID value = regT0;
+    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 (m_randomGenerator.getUint32() & 1)
+        add32(Imm32(1), bucketCounterRegister);
+    else
+        add32(Imm32(3), bucketCounterRegister);
+    and32(Imm32(ValueProfile::bucketIndexMask), bucketCounterRegister);
+    move(ImmPtr(valueProfile->buckets), scratch);
+    storePtr(value, BaseIndex(scratch, bucketCounterRegister, TimesEight));
+}
+#endif
+
 #if USE(JSVALUE32_64)
 
 inline void JIT::emitLoadTag(unsigned index, RegisterID tag)

Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp (93465 => 93466)


--- trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2011-08-20 01:47:51 UTC (rev 93465)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2011-08-20 02:17:49 UTC (rev 93466)
@@ -107,6 +107,7 @@
     loadPtr(BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0);
     addSlowCase(branchTestPtr(Zero, regT0));
 
+    emitValueProfilingSite(FirstProfilingSite);
     emitPutVirtualRegister(dst);
 }
 
@@ -136,6 +137,8 @@
     stubCall.addArgument(base, regT2);
     stubCall.addArgument(property, regT2);
     stubCall.call(dst);
+
+    emitValueProfilingSite(SubsequentProfilingSite);
 }
 
 void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID offset, RegisterID scratch)
@@ -318,6 +321,7 @@
     compileGetByIdHotPath(baseVReg, ident);
 
     match.link(this);
+    emitValueProfilingSite(FirstProfilingSite);
     emitPutVirtualRegister(resultVReg);
 
     // We've already generated the following get_by_id, so make sure it's skipped over.
@@ -345,6 +349,7 @@
 
     emitGetVirtualRegister(baseVReg, regT0);
     compileGetByIdHotPath(baseVReg, ident);
+    emitValueProfilingSite(FirstProfilingSite);
     emitPutVirtualRegister(resultVReg);
 }
 
@@ -387,6 +392,7 @@
     Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand));
 
     compileGetByIdSlowCase(resultVReg, baseVReg, ident, iter, false);
+    emitValueProfilingSite(SubsequentProfilingSite);
 }
 
 void JIT::compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident, Vector<SlowCaseEntry>::iterator& iter, bool isMethodCheck)

Modified: trunk/Source/_javascript_Core/jit/JSInterfaceJIT.h (93465 => 93466)


--- trunk/Source/_javascript_Core/jit/JSInterfaceJIT.h	2011-08-20 01:47:51 UTC (rev 93465)
+++ trunk/Source/_javascript_Core/jit/JSInterfaceJIT.h	2011-08-20 02:17:49 UTC (rev 93466)
@@ -55,6 +55,10 @@
         static const RegisterID cachedResultRegister = X86Registers::eax;
         static const RegisterID firstArgumentRegister = X86Registers::edi;
         
+#if ENABLE(VALUE_PROFILER)
+        static const RegisterID bucketCounterRegister = X86Registers::r10;
+#endif
+        
         static const RegisterID timeoutCheckRegister = X86Registers::r12;
         static const RegisterID callFrameRegister = X86Registers::r13;
         static const RegisterID tagTypeNumberRegister = X86Registers::r14;

Modified: trunk/Source/_javascript_Core/wtf/Platform.h (93465 => 93466)


--- trunk/Source/_javascript_Core/wtf/Platform.h	2011-08-20 01:47:51 UTC (rev 93465)
+++ trunk/Source/_javascript_Core/wtf/Platform.h	2011-08-20 02:17:49 UTC (rev 93466)
@@ -968,6 +968,15 @@
 #define ENABLE_DFG_JIT 1
 #endif
 
+/* Currently only implemented for JSVALUE64, only tested on PLATFORM(MAC) */
+#if !defined(ENABLE_VALUE_PROFILER) && ENABLE(JIT) && USE(JSVALUE64) && PLATFORM(MAC)
+#define ENABLE_VALUE_PROFILER 0
+#endif
+
+#if !defined(ENABLE_VERBOSE_VALUE_PROFILE) && ENABLE(VALUE_PROFILER)
+#define ENABLE_VERBOSE_VALUE_PROFILE 0
+#endif
+
 /* Ensure that either the JIT or the interpreter has been enabled. */
 #if !defined(ENABLE_INTERPRETER) && !ENABLE(JIT)
 #define ENABLE_INTERPRETER 1

Modified: trunk/Source/_javascript_Core/wtf/StdLibExtras.h (93465 => 93466)


--- trunk/Source/_javascript_Core/wtf/StdLibExtras.h	2011-08-20 01:47:51 UTC (rev 93465)
+++ trunk/Source/_javascript_Core/wtf/StdLibExtras.h	2011-08-20 02:17:49 UTC (rev 93466)
@@ -130,8 +130,8 @@
 
 // Binary search algorithm, calls extractKey on pre-sorted elements in array,
 // compares result with key (KeyTypes should be comparable with '--', '<', '>').
-template<typename ArrayType, typename KeyType, KeyType(*extractKey)(ArrayType*)>
-inline ArrayType* binarySearch(ArrayType* array, size_t size, KeyType key, BinarySearchMode mode = KeyMustBePresentInArray)
+template<typename ArrayElementType, typename KeyType, KeyType(*extractKey)(ArrayElementType*)>
+inline ArrayElementType* binarySearch(ArrayElementType* array, size_t size, KeyType key, BinarySearchMode mode = KeyMustBePresentInArray)
 {
     // The array must contain at least one element (pre-condition, array does contain key).
     // If the array contains only one element, no need to do the comparison.
@@ -168,6 +168,43 @@
     return &array[0];
 }
 
+// Modified binarySearch() algorithm designed for array-like classes that support
+// operator[] but not operator+=. One example of a class that qualifies is
+// SegmentedVector.
+template<typename ArrayElementType, typename KeyType, KeyType(*extractKey)(ArrayElementType*), typename ArrayType>
+inline ArrayElementType* genericBinarySearch(ArrayType& array, size_t size, KeyType key)
+{
+    // The array must contain at least one element (pre-condition, array does conatin key).
+    // If the array only contains one element, no need to do the comparison.
+    size_t offset = 0;
+    while (size > 1) {
+        // Pick an element to check, half way through the array, and read the value.
+        int pos = (size - 1) >> 1;
+        KeyType val = extractKey(&array[offset + pos]);
+        
+        // If the key matches, success!
+        if (val == key)
+            return &array[offset + pos];
+        // The item we are looking for is smaller than the item being check; reduce the value of 'size',
+        // chopping off the right hand half of the array.
+        if (key < val)
+            size = pos;
+        // Discard all values in the left hand half of the array, up to and including the item at pos.
+        else {
+            size -= (pos + 1);
+            offset += (pos + 1);
+        }
+
+        // 'size' should never reach zero.
+        ASSERT(size);
+    }
+    
+    // If we reach this point we've chopped down to one element, no need to check it matches
+    ASSERT(size == 1);
+    ASSERT(key == extractKey(&array[offset]));
+    return &array[offset];
+}
+
 } // namespace WTF
 
 using WTF::binarySearch;
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to