JSC should have a simple way of gathering IC statistics
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Apr 2016 02:02:47 +0000 (02:02 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Apr 2016 02:02:47 +0000 (02:02 +0000)
https://bugs.webkit.org/show_bug.cgi?id=156317

Reviewed by Benjamin Poulain.
Source/JavaScriptCore:

This adds a cheap, runtime-enabled way of gathering statistics about why we take the slow
paths for inline caches. This is complementary to our existing bytecode profiler. Eventually
we may want to combine the two things.

This is not a slow-down on anything because we only do extra work on IC slow paths and if
it's disabled it's just a load-and-branch to skip the stats gathering code.

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* jit/ICStats.cpp: Added.
* jit/ICStats.h: Added.
* jit/JITOperations.cpp:
* runtime/JSCJSValue.h:
* runtime/JSCJSValueInlines.h:
(JSC::JSValue::inherits):
(JSC::JSValue::classInfoOrNull):
(JSC::JSValue::toThis):
* runtime/Options.h:

Source/WTF:

Make it easier to do relative sleeping on a condition. Previously you could do this using
std::chrono. I now believe that std::chrono is just a bad decision, and I always want to
use doubles instead. This makes it easier to do the right thing and use doubles.

* wtf/Condition.h:
(WTF::ConditionBase::waitUntilMonotonicClockSeconds):
(WTF::ConditionBase::waitForSeconds):

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

Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/jit/ICStats.cpp [new file with mode: 0644]
Source/JavaScriptCore/jit/ICStats.h [new file with mode: 0644]
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/runtime/JSCJSValue.h
Source/JavaScriptCore/runtime/JSCJSValueInlines.h
Source/JavaScriptCore/runtime/Options.h
Source/WTF/ChangeLog
Source/WTF/wtf/Condition.h

index b95ce25..95d1151 100644 (file)
@@ -524,6 +524,7 @@ set(JavaScriptCore_SOURCES
     jit/GCAwareJITStubRoutine.cpp
     jit/GPRInfo.cpp
     jit/HostCallReturnValue.cpp
+    jit/ICStats.cpp
     jit/IntrinsicEmitter.cpp
     jit/JIT.cpp
     jit/JITAddGenerator.cpp
index 183db99..66bdee5 100644 (file)
@@ -1,5 +1,31 @@
 2016-04-06  Filip Pizlo  <fpizlo@apple.com>
 
+        JSC should have a simple way of gathering IC statistics
+        https://bugs.webkit.org/show_bug.cgi?id=156317
+
+        Reviewed by Benjamin Poulain.
+
+        This adds a cheap, runtime-enabled way of gathering statistics about why we take the slow
+        paths for inline caches. This is complementary to our existing bytecode profiler. Eventually
+        we may want to combine the two things.
+        
+        This is not a slow-down on anything because we only do extra work on IC slow paths and if
+        it's disabled it's just a load-and-branch to skip the stats gathering code.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * jit/ICStats.cpp: Added.
+        * jit/ICStats.h: Added.
+        * jit/JITOperations.cpp:
+        * runtime/JSCJSValue.h:
+        * runtime/JSCJSValueInlines.h:
+        (JSC::JSValue::inherits):
+        (JSC::JSValue::classInfoOrNull):
+        (JSC::JSValue::toThis):
+        * runtime/Options.h:
+
+2016-04-06  Filip Pizlo  <fpizlo@apple.com>
+
         32-bit JSC stress/multi-put-by-offset-multiple-transitions.js failing
         https://bugs.webkit.org/show_bug.cgi?id=156292
 
index 0f83e68..8ac82da 100644 (file)
                DE5A0A001BA3AC3E003D4424 /* IntrinsicEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE5A09FF1BA3AC3E003D4424 /* IntrinsicEmitter.cpp */; };
                DEA7E2441BBC677200D78440 /* JSTypedArrayViewPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53F256E11B87E28000B4B768 /* JSTypedArrayViewPrototype.cpp */; };
                DEA7E2451BBC677F00D78440 /* JSTypedArrayViewPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 53917E7C1B791106000EBD33 /* JSTypedArrayViewPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               DC2143071CA32E55000A8869 /* ICStats.h in Headers */ = {isa = PBXBuildFile; fileRef = DC2143061CA32E52000A8869 /* ICStats.h */; };
+               DC2143081CA32E58000A8869 /* ICStats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC2143051CA32E52000A8869 /* ICStats.cpp */; };
                E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */ = {isa = PBXBuildFile; fileRef = E124A8F50E555775003091F1 /* OpaqueJSString.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E124A8F80E555775003091F1 /* OpaqueJSString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E124A8F60E555775003091F1 /* OpaqueJSString.cpp */; };
                E18E3A590DF9278C00D90B34 /* VM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E18E3A570DF9278C00D90B34 /* VM.cpp */; };
                D21202280AD4310C00ED79B6 /* DateConversion.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DateConversion.cpp; sourceTree = "<group>"; };
                D21202290AD4310C00ED79B6 /* DateConversion.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DateConversion.h; sourceTree = "<group>"; };
                DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPreciseLocalClobberize.h; path = dfg/DFGPreciseLocalClobberize.h; sourceTree = "<group>"; };
+               DC2143051CA32E52000A8869 /* ICStats.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ICStats.cpp; sourceTree = "<group>"; };
+               DC2143061CA32E52000A8869 /* ICStats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICStats.h; sourceTree = "<group>"; };
                DC17E8131C9C7FD4008A6AB3 /* ShadowChicken.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ShadowChicken.cpp; sourceTree = "<group>"; };
                DC17E8141C9C7FD4008A6AB3 /* ShadowChicken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShadowChicken.h; sourceTree = "<group>"; };
                DC17E8151C9C7FD4008A6AB3 /* ShadowChickenInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShadowChickenInlines.h; sourceTree = "<group>"; };
                                0F24E53F17EA9F5900ABB217 /* GPRInfo.h */,
                                0F4680D014BBC5F800BFE272 /* HostCallReturnValue.cpp */,
                                0F4680D114BBC5F800BFE272 /* HostCallReturnValue.h */,
+                               DC2143051CA32E52000A8869 /* ICStats.cpp */,
+                               DC2143061CA32E52000A8869 /* ICStats.h */,
                                DE5A09FF1BA3AC3E003D4424 /* IntrinsicEmitter.cpp */,
                                1429D92D0ED22D7000B89619 /* JIT.cpp */,
                                1429D92E0ED22D7000B89619 /* JIT.h */,
                                A5BA15EB182340B400A82E69 /* RemoteConnectionToTarget.h in Headers */,
                                A5BA15ED182340B400A82E69 /* RemoteInspectorXPCConnection.h in Headers */,
                                0F24E55117EE274900ABB217 /* Repatch.h in Headers */,
+                               DC2143071CA32E55000A8869 /* ICStats.h in Headers */,
                                869EBCB70E8C6D4A008722CC /* ResultType.h in Headers */,
                                70B0A9D11A9B66460001306A /* RuntimeFlags.h in Headers */,
                                52C0611F1AA51E1C00B4ADBA /* RuntimeType.h in Headers */,
                                FE3A06B11C10CB8400390FDD /* JITBitAndGenerator.cpp in Sources */,
                                0FC09776146943B000CF2442 /* DFGOSRExitCompiler32_64.cpp in Sources */,
                                0FC0977214693AF900CF2442 /* DFGOSRExitCompiler64.cpp in Sources */,
+                               DC2143081CA32E58000A8869 /* ICStats.cpp in Sources */,
                                0F7025A91714B0FA00382C0E /* DFGOSRExitCompilerCommon.cpp in Sources */,
                                0F392C891B46188400844728 /* DFGOSRExitFuzz.cpp in Sources */,
                                0FEFC9AA1681A3B300567F53 /* DFGOSRExitJumpPlaceholder.cpp in Sources */,
diff --git a/Source/JavaScriptCore/jit/ICStats.cpp b/Source/JavaScriptCore/jit/ICStats.cpp
new file mode 100644 (file)
index 0000000..4036794
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
+ * 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. 
+ */
+
+#include "config.h"
+#include "ICStats.h"
+
+namespace JSC {
+
+bool ICEvent::operator<(const ICEvent& other) const
+{
+    if (m_classInfo != other.m_classInfo) {
+        if (!m_classInfo)
+            return true;
+        if (!other.m_classInfo)
+            return false;
+        return strcmp(m_classInfo->className, other.m_classInfo->className) < 0;
+    }
+    
+    if (m_propertyName != other.m_propertyName)
+        return codePointCompare(m_propertyName.string(), other.m_propertyName.string()) < 0;
+    
+    return m_kind < other.m_kind;
+}
+
+void ICEvent::dump(PrintStream& out) const
+{
+    out.print(m_kind, "(", m_classInfo ? m_classInfo->className : "<null>", ", ", m_propertyName, ")");
+}
+
+void ICEvent::log() const
+{
+    ICStats::instance().add(*this);
+}
+
+Atomic<ICStats*> ICStats::s_instance;
+
+ICStats::ICStats()
+{
+    m_thread = createThread(
+        "JSC ICStats",
+        [this] () {
+            LockHolder locker(m_lock);
+            for (;;) {
+                m_condition.waitForSeconds(m_lock, 1, [this] () -> bool { return m_shouldStop; });
+                if (m_shouldStop)
+                    break;
+                
+                dataLog("ICStats:\n");
+                auto list = m_spectrum.buildList();
+                for (unsigned i = list.size(); i--;)
+                    dataLog("    ", list[i].key, ": ", list[i].count, "\n");
+            }
+        });
+}
+
+ICStats::~ICStats()
+{
+    {
+        LockHolder locker(m_lock);
+        m_shouldStop = true;
+        m_condition.notifyAll();
+    }
+    
+    waitForThreadCompletion(m_thread);
+}
+
+void ICStats::add(const ICEvent& event)
+{
+    m_spectrum.add(event);
+}
+
+ICStats& ICStats::instance()
+{
+    for (;;) {
+        ICStats* result = s_instance.load();
+        if (result)
+            return *result;
+        
+        ICStats* newStats = new ICStats();
+        if (s_instance.compareExchangeWeak(nullptr, newStats))
+            return *newStats;
+        
+        delete newStats;
+    }
+}
+
+} // namespace JSC
+
+namespace WTF {
+
+using namespace JSC;
+
+void printInternal(PrintStream& out, ICEvent::Kind kind)
+{
+    switch (kind) {
+#define ICEVENT_KIND_DUMP(name) case ICEvent::name: out.print(#name); return;
+        FOR_EACH_ICEVENT_KIND(ICEVENT_KIND_DUMP);
+#undef ICEVENT_KIND_DUMP
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace WTF
+
+
diff --git a/Source/JavaScriptCore/jit/ICStats.h b/Source/JavaScriptCore/jit/ICStats.h
new file mode 100644 (file)
index 0000000..c53f619
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2016 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
+ * 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 ICStats_h
+#define ICStats_h
+
+#include "ClassInfo.h"
+#include "Identifier.h"
+#include <wtf/Condition.h>
+#include <wtf/HashTable.h>
+#include <wtf/FastMalloc.h>
+#include <wtf/Lock.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/PrintStream.h>
+#include <wtf/Spectrum.h>
+
+namespace JSC {
+
+#define FOR_EACH_ICEVENT_KIND(macro) \
+    macro(InvalidKind) \
+    macro(OperationGetById) \
+    macro(OperationGetByIdGeneric) \
+    macro(OperationGetByIdBuildList) \
+    macro(OperationGetByIdOptimize) \
+    macro(OperationInOptimize) \
+    macro(OperationIn) \
+    macro(OperationGenericIn) \
+    macro(OperationPutByIdStrict) \
+    macro(OperationPutByIdNonStrict) \
+    macro(OperationPutByIdDirectStrict) \
+    macro(OperationPutByIdDirectNonStrict) \
+    macro(OperationPutByIdStrictOptimize) \
+    macro(OperationPutByIdNonStrictOptimize) \
+    macro(OperationPutByIdDirectStrictOptimize) \
+    macro(OperationPutByIdDirectNonStrictOptimize) \
+    macro(OperationPutByIdStrictBuildList) \
+    macro(OperationPutByIdNonStrictBuildList) \
+    macro(OperationPutByIdDirectStrictBuildList) \
+    macro(OperationPutByIdDirectNonStrictBuildList)
+
+class ICEvent {
+public:
+    enum Kind {
+#define ICEVENT_KIND_DECLARATION(name) name,
+        FOR_EACH_ICEVENT_KIND(ICEVENT_KIND_DECLARATION)
+#undef ICEVENT_KIND_DECLARATION
+    };
+    
+    ICEvent()
+    {
+    }
+    
+    ICEvent(Kind kind, const ClassInfo* classInfo, const Identifier propertyName)
+        : m_kind(kind)
+        , m_classInfo(classInfo)
+        , m_propertyName(propertyName)
+    {
+    }
+
+    ICEvent(WTF::HashTableDeletedValueType)
+        : m_kind(OperationGetById)
+    {
+    }
+    
+    bool operator==(const ICEvent& other) const
+    {
+        return m_kind == other.m_kind
+            && m_classInfo == other.m_classInfo
+            && m_propertyName == other.m_propertyName;
+    }
+    
+    bool operator!=(const ICEvent& other) const
+    {
+        return !(*this == other);
+    }
+    
+    bool operator<(const ICEvent& other) const;
+    bool operator>(const ICEvent& other) const { return other < *this; }
+    bool operator<=(const ICEvent& other) const { return !(*this > other); }
+    bool operator>=(const ICEvent& other) const { return !(*this < other); }
+    
+    explicit operator bool() const
+    {
+        return *this != ICEvent();
+    }
+    
+    Kind kind() const { return m_kind; }
+    const ClassInfo* classInfo() const { return m_classInfo; }
+    const Identifier& propertyName() const { return m_propertyName; }
+    
+    unsigned hash() const
+    {
+        return m_kind + WTF::PtrHash<const ClassInfo*>::hash(m_classInfo) + StringHash::hash(m_propertyName.string());
+    }
+    
+    bool isHashTableDeletedValue() const
+    {
+        return *this == ICEvent(WTF::HashTableDeletedValue);
+    }
+    
+    void dump(PrintStream&) const;
+    
+    void log() const;
+    
+private:
+    
+    Kind m_kind { InvalidKind };
+    const ClassInfo* m_classInfo { nullptr };
+    Identifier m_propertyName;
+};
+
+struct ICEventHash {
+    static unsigned hash(const ICEvent& key) { return key.hash(); }
+    static bool equal(const ICEvent& a, const ICEvent& b) { return a == b; }
+    static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+} // namespace JSC
+
+namespace WTF {
+
+void printInternal(PrintStream&, JSC::ICEvent::Kind);
+
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<JSC::ICEvent> {
+    typedef JSC::ICEventHash Hash;
+};
+
+template<typename T> struct HashTraits;
+template<> struct HashTraits<JSC::ICEvent> : SimpleClassHashTraits<JSC::ICEvent> {
+    static const bool emptyValueIsZero = false;
+};
+
+} // namespace WTF
+
+namespace JSC {
+
+class ICStats {
+    WTF_MAKE_NONCOPYABLE(ICStats);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    ICStats();
+    ~ICStats();
+    
+    void add(const ICEvent& event);
+    
+    static ICStats& instance();
+    
+private:
+
+    Spectrum<ICEvent, uint64_t> m_spectrum;
+    ThreadIdentifier m_thread;
+    Lock m_lock;
+    Condition m_condition;
+    bool m_shouldStop { false };
+    
+    static Atomic<ICStats*> s_instance;
+};
+
+#define LOG_IC(arguments) do {                  \
+        if (Options::useICStats())              \
+            (ICEvent arguments).log();          \
+    } while (false)
+
+} // namespace JSC
+
+#endif // ICStats_h
+
index 9db8c72..21b9ad4 100644 (file)
@@ -42,6 +42,7 @@
 #include "ExceptionFuzz.h"
 #include "GetterSetter.h"
 #include "HostCallReturnValue.h"
+#include "ICStats.h"
 #include "JIT.h"
 #include "JITExceptions.h"
 #include "JITToDFGDeferredCompilationCallback.h"
@@ -54,6 +55,7 @@
 #include "JSWithScope.h"
 #include "LegacyProfiler.h"
 #include "ObjectConstructor.h"
+#include "PolymorphicAccess.h"
 #include "PropertyName.h"
 #include "Repatch.h"
 #include "ScopedArguments.h"
@@ -164,6 +166,8 @@ EncodedJSValue JIT_OPERATION operationGetById(ExecState* exec, StructureStubInfo
     JSValue baseValue = JSValue::decode(base);
     PropertySlot slot(baseValue, PropertySlot::InternalMethodType::Get);
     Identifier ident = Identifier::fromUid(vm, uid);
+    
+    LOG_IC((ICEvent::OperationGetById, baseValue.classInfoOrNull(), ident));
     return JSValue::encode(baseValue.get(exec, ident, slot));
 }
 
@@ -175,6 +179,7 @@ EncodedJSValue JIT_OPERATION operationGetByIdGeneric(ExecState* exec, EncodedJSV
     JSValue baseValue = JSValue::decode(base);
     PropertySlot slot(baseValue, PropertySlot::InternalMethodType::Get);
     Identifier ident = Identifier::fromUid(vm, uid);
+    LOG_IC((ICEvent::OperationGetByIdGeneric, baseValue.classInfoOrNull(), ident));
     return JSValue::encode(baseValue.get(exec, ident, slot));
 }
 
@@ -185,6 +190,7 @@ EncodedJSValue JIT_OPERATION operationGetByIdOptimize(ExecState* exec, Structure
     Identifier ident = Identifier::fromUid(vm, uid);
 
     JSValue baseValue = JSValue::decode(base);
+    LOG_IC((ICEvent::OperationGetByIdOptimize, baseValue.classInfoOrNull(), ident));
     PropertySlot slot(baseValue, PropertySlot::InternalMethodType::Get);
     
     bool hasResult = baseValue.getPropertySlot(exec, ident, slot);
@@ -207,6 +213,7 @@ EncodedJSValue JIT_OPERATION operationInOptimize(ExecState* exec, StructureStubI
     AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
 
     Identifier ident = Identifier::fromUid(vm, key);
+    LOG_IC((ICEvent::OperationInOptimize, base->classInfo(), ident));
     PropertySlot slot(base, PropertySlot::InternalMethodType::HasProperty);
     bool result = asObject(base)->getPropertySlot(exec, ident, slot);
     
@@ -231,6 +238,7 @@ EncodedJSValue JIT_OPERATION operationIn(ExecState* exec, StructureStubInfo* stu
     }
 
     Identifier ident = Identifier::fromUid(vm, key);
+    LOG_IC((ICEvent::OperationIn, base->classInfo(), ident));
     return JSValue::encode(jsBoolean(asObject(base)->hasProperty(exec, ident)));
 }
 
@@ -249,9 +257,12 @@ void JIT_OPERATION operationPutByIdStrict(ExecState* exec, StructureStubInfo* st
     
     stubInfo->tookSlowPath = true;
     
+    JSValue baseValue = JSValue::decode(encodedBase);
     Identifier ident = Identifier::fromUid(vm, uid);
-    PutPropertySlot slot(JSValue::decode(encodedBase), true, exec->codeBlock()->putByIdContext());
-    JSValue::decode(encodedBase).putInline(exec, ident, JSValue::decode(encodedValue), slot);
+    LOG_IC((ICEvent::OperationPutByIdStrict, baseValue.classInfoOrNull(), ident));
+
+    PutPropertySlot slot(baseValue, true, exec->codeBlock()->putByIdContext());
+    baseValue.putInline(exec, ident, JSValue::decode(encodedValue), slot);
 }
 
 void JIT_OPERATION operationPutByIdNonStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
@@ -261,9 +272,11 @@ void JIT_OPERATION operationPutByIdNonStrict(ExecState* exec, StructureStubInfo*
     
     stubInfo->tookSlowPath = true;
     
+    JSValue baseValue = JSValue::decode(encodedBase);
     Identifier ident = Identifier::fromUid(vm, uid);
-    PutPropertySlot slot(JSValue::decode(encodedBase), false, exec->codeBlock()->putByIdContext());
-    JSValue::decode(encodedBase).putInline(exec, ident, JSValue::decode(encodedValue), slot);
+    LOG_IC((ICEvent::OperationPutByIdNonStrict, baseValue.classInfoOrNull(), ident));
+    PutPropertySlot slot(baseValue, false, exec->codeBlock()->putByIdContext());
+    baseValue.putInline(exec, ident, JSValue::decode(encodedValue), slot);
 }
 
 void JIT_OPERATION operationPutByIdDirectStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
@@ -273,9 +286,11 @@ void JIT_OPERATION operationPutByIdDirectStrict(ExecState* exec, StructureStubIn
     
     stubInfo->tookSlowPath = true;
     
+    JSValue baseValue = JSValue::decode(encodedBase);
     Identifier ident = Identifier::fromUid(vm, uid);
-    PutPropertySlot slot(JSValue::decode(encodedBase), true, exec->codeBlock()->putByIdContext());
-    asObject(JSValue::decode(encodedBase))->putDirect(exec->vm(), ident, JSValue::decode(encodedValue), slot);
+    LOG_IC((ICEvent::OperationPutByIdDirectStrict, baseValue.classInfoOrNull(), ident));
+    PutPropertySlot slot(baseValue, true, exec->codeBlock()->putByIdContext());
+    asObject(baseValue)->putDirect(exec->vm(), ident, JSValue::decode(encodedValue), slot);
 }
 
 void JIT_OPERATION operationPutByIdDirectNonStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
@@ -285,9 +300,11 @@ void JIT_OPERATION operationPutByIdDirectNonStrict(ExecState* exec, StructureStu
     
     stubInfo->tookSlowPath = true;
     
+    JSValue baseValue = JSValue::decode(encodedBase);
     Identifier ident = Identifier::fromUid(vm, uid);
-    PutPropertySlot slot(JSValue::decode(encodedBase), false, exec->codeBlock()->putByIdContext());
-    asObject(JSValue::decode(encodedBase))->putDirect(exec->vm(), ident, JSValue::decode(encodedValue), slot);
+    LOG_IC((ICEvent::OperationPutByIdDirectNonStrict, baseValue.classInfoOrNull(), ident));
+    PutPropertySlot slot(baseValue, false, exec->codeBlock()->putByIdContext());
+    asObject(baseValue)->putDirect(exec->vm(), ident, JSValue::decode(encodedValue), slot);
 }
 
 void JIT_OPERATION operationPutByIdStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
@@ -300,6 +317,7 @@ void JIT_OPERATION operationPutByIdStrictOptimize(ExecState* exec, StructureStub
 
     JSValue value = JSValue::decode(encodedValue);
     JSValue baseValue = JSValue::decode(encodedBase);
+    LOG_IC((ICEvent::OperationPutByIdStrictOptimize, baseValue.classInfoOrNull(), ident));
     PutPropertySlot slot(baseValue, true, exec->codeBlock()->putByIdContext());
 
     Structure* structure = baseValue.isCell() ? baseValue.asCell()->structure(*vm) : nullptr;
@@ -322,6 +340,7 @@ void JIT_OPERATION operationPutByIdNonStrictOptimize(ExecState* exec, StructureS
 
     JSValue value = JSValue::decode(encodedValue);
     JSValue baseValue = JSValue::decode(encodedBase);
+    LOG_IC((ICEvent::OperationPutByIdNonStrictOptimize, baseValue.classInfoOrNull(), ident));
     PutPropertySlot slot(baseValue, false, exec->codeBlock()->putByIdContext());
 
     Structure* structure = baseValue.isCell() ? baseValue.asCell()->structure(*vm) : nullptr;    
@@ -344,6 +363,7 @@ void JIT_OPERATION operationPutByIdDirectStrictOptimize(ExecState* exec, Structu
 
     JSValue value = JSValue::decode(encodedValue);
     JSObject* baseObject = asObject(JSValue::decode(encodedBase));
+    LOG_IC((ICEvent::OperationPutByIdDirectStrictOptimize, baseObject->classInfo(), ident));
     PutPropertySlot slot(baseObject, true, exec->codeBlock()->putByIdContext());
     
     Structure* structure = baseObject->structure(*vm);
@@ -366,6 +386,7 @@ void JIT_OPERATION operationPutByIdDirectNonStrictOptimize(ExecState* exec, Stru
 
     JSValue value = JSValue::decode(encodedValue);
     JSObject* baseObject = asObject(JSValue::decode(encodedBase));
+    LOG_IC((ICEvent::OperationPutByIdDirectNonStrictOptimize, baseObject->classInfo(), ident));
     PutPropertySlot slot(baseObject, false, exec->codeBlock()->putByIdContext());
     
     Structure* structure = baseObject->structure(*vm);
index ef4d66a..35cc039 100644 (file)
@@ -241,6 +241,7 @@ public:
     bool isCustomGetterSetter() const;
     bool isObject() const;
     bool inherits(const ClassInfo*) const;
+    const ClassInfo* classInfoOrNull() const;
         
     // Extracting the value.
     bool getString(ExecState*, WTF::String&) const;
index 91999f3..8886642 100644 (file)
@@ -746,6 +746,11 @@ inline bool JSValue::inherits(const ClassInfo* classInfo) const
     return isCell() && asCell()->inherits(classInfo);
 }
 
+inline const ClassInfo* JSValue::classInfoOrNull() const
+{
+    return isCell() ? asCell()->classInfo() : nullptr;
+}
+
 inline JSValue JSValue::toThis(ExecState* exec, ECMAMode ecmaMode) const
 {
     return isCell() ? asCell()->methodTable(exec->vm())->toThis(asCell(), exec, ecmaMode) : toThisSlowCase(exec, ecmaMode);
index f98192e..8988f4f 100644 (file)
@@ -351,6 +351,8 @@ typedef const char* optionString;
     \
     v(unsigned, watchdog, 0, "watchdog timeout (0 = Disabled, N = a timeout period of N milliseconds)") \
     \
+    v(bool, useICStats, false, nullptr) \
+    \
     v(bool, dumpModuleRecord, false, nullptr) \
     v(bool, dumpModuleLoadingState, false, nullptr) \
     v(bool, exposeInternalModuleLoader, false, "expose the internal module loader object to the global space for debugging") \
index d49539d..30ab069 100644 (file)
@@ -1,3 +1,18 @@
+2016-04-06  Filip Pizlo  <fpizlo@apple.com>
+
+        JSC should have a simple way of gathering IC statistics
+        https://bugs.webkit.org/show_bug.cgi?id=156317
+
+        Reviewed by Benjamin Poulain.
+        
+        Make it easier to do relative sleeping on a condition. Previously you could do this using
+        std::chrono. I now believe that std::chrono is just a bad decision, and I always want to
+        use doubles instead. This makes it easier to do the right thing and use doubles.
+
+        * wtf/Condition.h:
+        (WTF::ConditionBase::waitUntilMonotonicClockSeconds):
+        (WTF::ConditionBase::waitForSeconds):
+
 2016-04-06  Simon Fraser  <simon.fraser@apple.com>
 
         Fix Windows build by converting clampToInteger() into a template that only
index 80c0729..b811372 100644 (file)
@@ -141,6 +141,31 @@ struct ConditionBase {
     {
         return waitForSecondsImpl(lock, absoluteTimeoutSeconds - monotonicallyIncreasingTime());
     }
+    
+    template<typename LockType, typename Functor>
+    bool waitForSeconds(LockType& lock, double relativeTimeoutSeconds, const Functor& predicate)
+    {
+        double relativeTimeoutNanoseconds = relativeTimeoutSeconds * (1000.0 * 1000.0 * 1000.0);
+        
+        if (!(relativeTimeoutNanoseconds > 0)) {
+            // This handles insta-timeouts as well as NaN.
+            lock.unlock();
+            lock.lock();
+            return false;
+        }
+
+        if (relativeTimeoutNanoseconds > static_cast<double>(std::numeric_limits<int64_t>::max())) {
+            // If the timeout in nanoseconds cannot be expressed using a 64-bit integer, then we
+            // might as well wait forever.
+            wait(lock, predicate);
+            return true;
+        }
+        
+        auto relativeTimeout =
+            std::chrono::nanoseconds(static_cast<int64_t>(relativeTimeoutNanoseconds));
+
+        return waitFor(lock, relativeTimeout, predicate);
+    }
 
     // Note that this method is extremely fast when nobody is waiting. It is not necessary to try to
     // avoid calling this method.