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;