Commit aec7e0c4 authored by fpizlo@apple.com's avatar fpizlo@apple.com

There is no facility for profiling how the write barrier is used

https://bugs.webkit.org/show_bug.cgi?id=66747

Reviewed by Geoffrey Garen.

Added facilities for the JIT to specify the kind of write barrier
being executed.  Added code for profiling the number of each kind
of barrier encountered.

* GNUmakefile.list.am:
* JavaScriptCore.exp:
* JavaScriptCore.pro:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGJITCodeGenerator.cpp:
(JSC::DFG::JITCodeGenerator::writeBarrier):
(JSC::DFG::JITCodeGenerator::cachedPutById):
* dfg/DFGJITCodeGenerator.h:
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::emitCount):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::emitCount):
* dfg/DFGNonSpeculativeJIT.cpp:
(JSC::DFG::NonSpeculativeJIT::compile):
* dfg/DFGRepatch.cpp:
(JSC::DFG::tryCachePutByID):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* heap/Heap.h:
(JSC::Heap::writeBarrier):
* heap/WriteBarrierSupport.cpp: Added.
(JSC::WriteBarrierCounters::initialize):
* heap/WriteBarrierSupport.h: Added.
(JSC::WriteBarrierCounters::WriteBarrierCounters):
(JSC::WriteBarrierCounters::jitCounterFor):
(JSC::WriteBarrierCounters::countWriteBarrier):
* jit/JIT.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::privateCompilePutByIdTransition):
(JSC::JIT::emit_op_put_scoped_var):
(JSC::JIT::emit_op_put_global_var):
(JSC::JIT::emitWriteBarrier):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::privateCompilePutByIdTransition):
(JSC::JIT::emit_op_put_scoped_var):
(JSC::JIT::emit_op_put_global_var):
(JSC::JIT::emitWriteBarrier):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreadingOnce):
* runtime/WriteBarrier.h:
(JSC::WriteBarrierBase::setWithoutWriteBarrier):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@93698 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent af331a5a
2011-08-24 Filip Pizlo <fpizlo@apple.com>
There is no facility for profiling how the write barrier is used
https://bugs.webkit.org/show_bug.cgi?id=66747
Reviewed by Geoffrey Garen.
Added facilities for the JIT to specify the kind of write barrier
being executed. Added code for profiling the number of each kind
of barrier encountered.
* GNUmakefile.list.am:
* JavaScriptCore.exp:
* JavaScriptCore.pro:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGJITCodeGenerator.cpp:
(JSC::DFG::JITCodeGenerator::writeBarrier):
(JSC::DFG::JITCodeGenerator::cachedPutById):
* dfg/DFGJITCodeGenerator.h:
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::emitCount):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::emitCount):
* dfg/DFGNonSpeculativeJIT.cpp:
(JSC::DFG::NonSpeculativeJIT::compile):
* dfg/DFGRepatch.cpp:
(JSC::DFG::tryCachePutByID):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* heap/Heap.h:
(JSC::Heap::writeBarrier):
* heap/WriteBarrierSupport.cpp: Added.
(JSC::WriteBarrierCounters::initialize):
* heap/WriteBarrierSupport.h: Added.
(JSC::WriteBarrierCounters::WriteBarrierCounters):
(JSC::WriteBarrierCounters::jitCounterFor):
(JSC::WriteBarrierCounters::countWriteBarrier):
* jit/JIT.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::privateCompilePutByIdTransition):
(JSC::JIT::emit_op_put_scoped_var):
(JSC::JIT::emit_op_put_global_var):
(JSC::JIT::emitWriteBarrier):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::privateCompilePutByIdTransition):
(JSC::JIT::emit_op_put_scoped_var):
(JSC::JIT::emit_op_put_global_var):
(JSC::JIT::emitWriteBarrier):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreadingOnce):
* runtime/WriteBarrier.h:
(JSC::WriteBarrierBase::setWithoutWriteBarrier):
2011-08-23 Mark Hahnenberg <mhahnenberg@apple.com>
Add checks to ensure allocation does not take place during initialization of GC-managed objects
......
......@@ -150,6 +150,8 @@ javascriptcore_sources += \
Source/JavaScriptCore/heap/OldSpace.h \
Source/JavaScriptCore/heap/Strong.h \
Source/JavaScriptCore/heap/Weak.h \
Source/JavaScriptCore/heap/WriteBarrierSupport.cpp \
Source/JavaScriptCore/heap/WriteBarrierSupport.h \
Source/JavaScriptCore/config.h \
Source/JavaScriptCore/debugger/DebuggerActivation.cpp \
Source/JavaScriptCore/debugger/DebuggerActivation.h \
......
......@@ -210,6 +210,8 @@ __ZN3JSC19SourceProviderCacheD1Ev
__ZN3JSC19initializeThreadingEv
__ZN3JSC20MarkedArgumentBuffer10slowAppendENS_7JSValueE
__ZN3JSC20createReferenceErrorEPNS_9ExecStateERKNS_7UStringE
__ZN3JSC20WriteBarrierCounters22usesWithBarrierFromCppE
__ZN3JSC20WriteBarrierCounters25usesWithoutBarrierFromCppE
__ZN3JSC22globalMemoryStatisticsEv
__ZN3JSC22objectConstructorTableE
__ZN3JSC23AbstractSamplingCounter4dumpEv
......
......@@ -79,6 +79,7 @@ SOURCES += \
heap/MarkedBlock.cpp \
heap/NewSpace.cpp \
heap/OldSpace.cpp \
heap/WriteBarrierSupport.cpp \
debugger/DebuggerActivation.cpp \
debugger/DebuggerCallFrame.cpp \
debugger/Debugger.cpp \
......
......@@ -1969,6 +1969,14 @@
RelativePath="..\..\heap\Weak.h"
>
</File>
<File
RelativePath="..\..\heap\WriteBarrierSupport.cpp"
>
</File>
<File
RelativePath="..\..\heap\WriteBarrierSupport.h"
>
</File>
</Filter>
<File
RelativePath="..\..\config.h"
......
......@@ -49,9 +49,11 @@
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 */; };
0F7700901402FDE40078EB39 /* SamplingCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F77008E1402FDD60078EB39 /* SamplingCounter.h */; };
0F7700901402FDE40078EB39 /* SamplingCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F77008E1402FDD60078EB39 /* SamplingCounter.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F7700921402FF3C0078EB39 /* SamplingCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7700911402FF280078EB39 /* SamplingCounter.cpp */; };
0F963B3813FC6FE90002D9B2 /* ValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FC8150A14043BF500CFA603 /* WriteBarrierSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FC8150B14043C0E00CFA603 /* WriteBarrierSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC8150814043BCA00CFA603 /* WriteBarrierSupport.cpp */; };
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 */; };
......@@ -735,6 +737,8 @@
0F77008E1402FDD60078EB39 /* SamplingCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SamplingCounter.h; sourceTree = "<group>"; };
0F7700911402FF280078EB39 /* SamplingCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SamplingCounter.cpp; sourceTree = "<group>"; };
0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ValueProfile.h; sourceTree = "<group>"; };
0FC8150814043BCA00CFA603 /* WriteBarrierSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WriteBarrierSupport.cpp; sourceTree = "<group>"; };
0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WriteBarrierSupport.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>"; };
......@@ -1505,6 +1509,8 @@
142E312A134FF0A600AFADB5 /* heap */ = {
isa = PBXGroup;
children = (
0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */,
0FC8150814043BCA00CFA603 /* WriteBarrierSupport.cpp */,
146B14DB12EB5B12001BEC1B /* ConservativeRoots.cpp */,
149DAAF212EB559D0083B12B /* ConservativeRoots.h */,
142E312B134FF0A600AFADB5 /* Handle.h */,
......@@ -2239,6 +2245,7 @@
86D3B2C410156BDE002865E7 /* ARMAssembler.h in Headers */,
86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */,
BC18C3E60E16F5CD00B34460 /* ArrayConstructor.h in Headers */,
0FC8150A14043BF500CFA603 /* WriteBarrierSupport.h in Headers */,
0F963B3813FC6FE90002D9B2 /* ValueProfile.h in Headers */,
BC18C3E70E16F5CD00B34460 /* ArrayPrototype.h in Headers */,
BC18C5240E16FC8A00B34460 /* ArrayPrototype.lut.h in Headers */,
......@@ -2848,6 +2855,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0FC8150B14043C0E00CFA603 /* WriteBarrierSupport.cpp in Sources */,
0F7700921402FF3C0078EB39 /* SamplingCounter.cpp in Sources */,
147F39BD107EC37600427A48 /* ArgList.cpp in Sources */,
147F39BE107EC37600427A48 /* Arguments.cpp in Sources */,
......
......@@ -465,11 +465,17 @@ JITCompiler::Call JITCodeGenerator::cachedGetById(GPRReg baseGPR, GPRReg resultG
return functionCall;
}
void JITCodeGenerator::writeBarrier(MacroAssembler&, GPRReg owner, GPRReg scratch)
void JITCodeGenerator::writeBarrier(MacroAssembler& jit, GPRReg owner, GPRReg scratch, WriteBarrierUseKind useKind)
{
UNUSED_PARAM(jit);
UNUSED_PARAM(owner);
UNUSED_PARAM(scratch);
UNUSED_PARAM(useKind);
ASSERT(owner != scratch);
#if ENABLE(WRITE_BARRIER_PROFILING)
JITCompiler::emitCount(jit, WriteBarrierCounters::jitCounterFor(useKind));
#endif
}
void JITCodeGenerator::cachedPutById(GPRReg baseGPR, GPRReg valueGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget)
......@@ -477,7 +483,7 @@ void JITCodeGenerator::cachedPutById(GPRReg baseGPR, GPRReg valueGPR, GPRReg scr
JITCompiler::DataLabelPtr structureToCompare;
JITCompiler::Jump structureCheck = m_jit.branchPtrWithPatch(JITCompiler::NotEqual, JITCompiler::Address(baseGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
writeBarrier(m_jit, baseGPR, scratchGPR);
writeBarrier(m_jit, baseGPR, scratchGPR, WriteBarrierForPropertyAccess);
m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
JITCompiler::DataLabel32 storeWithPatch = m_jit.storePtrWithAddressOffsetPatch(valueGPR, JITCompiler::Address(scratchGPR, 0));
......
......@@ -176,7 +176,7 @@ public:
m_gprs.release(info.gpr());
}
static void writeBarrier(MacroAssembler&, GPRReg ownerGPR, GPRReg scratchGPR);
static void writeBarrier(MacroAssembler&, GPRReg ownerGPR, GPRReg scratchGPR, WriteBarrierUseKind);
static GPRReg selectScratchGPR(GPRReg preserve1 = InvalidGPRReg, GPRReg preserve2 = InvalidGPRReg, GPRReg preserve3 = InvalidGPRReg)
{
......
......@@ -1041,18 +1041,18 @@ void JITCompiler::jitAssertIsCell(GPRReg gpr)
#endif
#if ENABLE(SAMPLING_COUNTERS) && CPU(X86_64) // Or any other 64-bit platform!
void JITCompiler::emitCount(AbstractSamplingCounter& counter, uint32_t increment)
void JITCompiler::emitCount(MacroAssembler& jit, AbstractSamplingCounter& counter, uint32_t increment)
{
addPtr(TrustedImm32(increment), AbsoluteAddress(counter.addressOfCounter()));
jit.addPtr(TrustedImm32(increment), AbsoluteAddress(counter.addressOfCounter()));
}
#endif
#if ENABLE(SAMPLING_COUNTERS) && CPU(X86) // Or any other little-endian 32-bit platform!
void JITCompiler::emitCount(AbstractSamplingCounter& counter, uint32_t increment)
void JITCompiler::emitCount(MacroAsembler& jit, AbstractSamplingCounter& counter, uint32_t increment)
{
intptr_t hiWord = reinterpret_cast<intptr_t>(counter.addressOfCounter()) + sizeof(int32_t);
add32(TrustedImm32(increment), AbsoluteAddress(counter.addressOfCounter()));
addWithCarry32(TrustedImm32(0), AbsoluteAddress(reinterpret_cast<void*>(hiWord)));
jit.add32(TrustedImm32(increment), AbsoluteAddress(counter.addressOfCounter()));
jit.addWithCarry32(TrustedImm32(0), AbsoluteAddress(reinterpret_cast<void*>(hiWord)));
}
#endif
......
......@@ -273,7 +273,11 @@ public:
#if ENABLE(SAMPLING_COUNTERS)
// Debug profiling tool.
void emitCount(AbstractSamplingCounter&, uint32_t increment = 1);
static void emitCount(MacroAssembler&, AbstractSamplingCounter&, uint32_t increment = 1);
void emitCount(AbstractSamplingCounter& counter, uint32_t increment = 1)
{
emitCount(*this, counter, increment);
}
#endif
#if ENABLE(SAMPLING_FLAGS)
......
......@@ -903,7 +903,7 @@ void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator, No
property.use();
value.use();
writeBarrier(m_jit, baseGPR, storageGPR);
writeBarrier(m_jit, baseGPR, storageGPR, WriteBarrierForPropertyAccess);
JITCompiler::Jump baseNotCell = m_jit.branchTestPtr(MacroAssembler::NonZero, baseGPR, GPRInfo::tagMaskRegister);
......@@ -1050,7 +1050,7 @@ void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator, No
m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.codeBlock()->globalObject()), globalObjectReg);
writeBarrier(m_jit, globalObjectReg, scratchReg);
writeBarrier(m_jit, globalObjectReg, scratchReg, WriteBarrierForVariableAccess);
m_jit.loadPtr(MacroAssembler::Address(globalObjectReg, JSVariableObject::offsetOfRegisters()), scratchReg);
m_jit.storePtr(value.gpr(), JITCompiler::addressForGlobalVar(scratchReg, node.varNumber()));
......
......@@ -525,7 +525,7 @@ static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier
testPrototype(stubJit, scratchGPR, (*it)->storedPrototype(), failureCases);
}
JITCodeGenerator::writeBarrier(stubJit, baseGPR, scratchGPR);
JITCodeGenerator::writeBarrier(stubJit, baseGPR, scratchGPR, WriteBarrierForPropertyAccess);
stubJit.storePtr(MacroAssembler::TrustedImmPtr(structure), MacroAssembler::Address(baseGPR, JSCell::structureOffset()));
if (structure->isUsingInlineStorage())
......
......@@ -945,7 +945,7 @@ void SpeculativeJIT::compile(Node& node)
if (!m_compileOkay)
return;
writeBarrier(m_jit, baseReg, scratchReg);
writeBarrier(m_jit, baseReg, scratchReg, WriteBarrierForPropertyAccess);
// Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
// If we have predicted the base to be type array, we can skip the check.
......@@ -1004,7 +1004,7 @@ void SpeculativeJIT::compile(Node& node)
GPRReg baseReg = base.gpr();
GPRReg scratchReg = scratch.gpr();
writeBarrier(m_jit, baseReg, scratchReg);
writeBarrier(m_jit, baseReg, scratchReg, WriteBarrierForPropertyAccess);
// Get the array storage.
GPRReg storageReg = scratchReg;
......@@ -1165,7 +1165,7 @@ void SpeculativeJIT::compile(Node& node)
m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.codeBlock()->globalObject()), globalObjectReg);
writeBarrier(m_jit, globalObjectReg, scratchReg);
writeBarrier(m_jit, globalObjectReg, scratchReg, WriteBarrierForVariableAccess);
m_jit.loadPtr(MacroAssembler::Address(globalObjectReg, JSVariableObject::offsetOfRegisters()), scratchReg);
m_jit.storePtr(value.gpr(), JITCompiler::addressForGlobalVar(scratchReg, node.varNumber()));
......
......@@ -28,6 +28,7 @@
#include "MarkedBlockSet.h"
#include "NewSpace.h"
#include "SlotVisitor.h"
#include "WriteBarrierSupport.h"
#include <wtf/Forward.h>
#include <wtf/HashCountedSet.h>
#include <wtf/HashSet.h>
......@@ -129,6 +130,10 @@ namespace JSC {
static const size_t maxExtraCost = 1024 * 1024;
enum AllocationEffort { AllocationMustSucceed, AllocationCanFail };
#if ENABLE(GGC)
static void writeBarrierFastCase(const JSCell* owner, JSCell*);
#endif
bool isValidAllocation(size_t);
void reportExtraMemoryCostSlowCase(size_t);
......@@ -236,30 +241,38 @@ namespace JSC {
}
#if ENABLE(GGC)
inline void Heap::writeBarrier(const JSCell* owner, JSCell* cell)
inline void Heap::writeBarrierFastCase(const JSCell* owner, JSCell* cell)
{
if (MarkedBlock::blockFor(owner)->inNewSpace())
return;
writeBarrierSlowCase(owner, cell);
}
inline void Heap::writeBarrier(const JSCell* owner, JSCell* cell)
{
WriteBarrierCounters::countWriteBarrier();
writeBarrierFastCase(owner, cell);
}
inline void Heap::writeBarrier(const JSCell* owner, JSValue value)
{
WriteBarrierCounters::countWriteBarrier();
if (!value)
return;
if (!value.isCell())
return;
writeBarrier(owner, value.asCell());
writeBarrierFastCase(owner, value.asCell());
}
#else
inline void Heap::writeBarrier(const JSCell*, JSCell*)
{
WriteBarrierCounters::countWriteBarrier();
}
inline void Heap::writeBarrier(const JSCell*, JSValue)
{
WriteBarrierCounters::countWriteBarrier();
}
#endif
......
/*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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.
*/
#include "config.h"
#include "WriteBarrierSupport.h"
namespace JSC {
#if ENABLE(WRITE_BARRIER_PROFILING)
GlobalSamplingCounter WriteBarrierCounters::usesWithBarrierFromCpp;
GlobalSamplingCounter WriteBarrierCounters::usesWithoutBarrierFromCpp;
GlobalSamplingCounter WriteBarrierCounters::usesWithBarrierFromJit;
GlobalSamplingCounter WriteBarrierCounters::usesForPropertiesFromJit;
GlobalSamplingCounter WriteBarrierCounters::usesForVariablesFromJit;
GlobalSamplingCounter WriteBarrierCounters::usesWithoutBarrierFromJit;
void WriteBarrierCounters::initialize()
{
usesWithBarrierFromCpp.name("WithBarrierFromCpp");
usesWithoutBarrierFromCpp.name("WithoutBarrierFromCpp");
usesWithBarrierFromJit.name("WithBarrierFromJit");
usesForPropertiesFromJit.name("WriteForPropertiesFromJit");
usesForVariablesFromJit.name("WriteForVariablesFromJit");
usesWithoutBarrierFromJit.name("WithoutBarrierFromJit");
}
#else
char WriteBarrierCounters::usesWithBarrierFromCpp;
char WriteBarrierCounters::usesWithoutBarrierFromCpp;
#endif
} // namespace JSC
/*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 WriteBarrierSupport_h
#define WriteBarrierSupport_h
#include "SamplingCounter.h"
#include <wtf/Assertions.h>
namespace JSC {
// This allows the JIT to distinguish between uses of the barrier for different
// kinds of writes. This is used by the JIT for profiling, and may be appropriate
// for allowing the GC implementation to specialize the JIT's write barrier code
// for different kinds of target objects.
enum WriteBarrierUseKind {
// This allows specialization for access to the property storage (either
// array element or property), but not for any other kind of property
// accesses (such as writes that are a consequence of setter execution).
WriteBarrierForPropertyAccess,
// This allows specialization for variable accesses (such as global or
// scoped variables).
WriteBarrierForVariableAccess,
// This captures all other forms of write barriers. It should always be
// correct to use a generic access write barrier, even when storing to
// properties. Hence, if optimization is not necessary, it is preferable
// to just use a generic access.
WriteBarrierForGenericAccess
};
class WriteBarrierCounters {
private:
WriteBarrierCounters() { }
public:
#if ENABLE(WRITE_BARRIER_PROFILING)
static GlobalSamplingCounter usesWithBarrierFromCpp;
static GlobalSamplingCounter usesWithoutBarrierFromCpp;
static GlobalSamplingCounter usesWithBarrierFromJit;
static GlobalSamplingCounter usesForPropertiesFromJit;
static GlobalSamplingCounter usesForVariablesFromJit;
static GlobalSamplingCounter usesWithoutBarrierFromJit;
static void initialize();
static GlobalSamplingCounter& jitCounterFor(WriteBarrierUseKind useKind)
{
switch (useKind) {
case WriteBarrierForPropertyAccess:
return usesForPropertiesFromJit;
case WriteBarrierForVariableAccess:
return usesForVariablesFromJit;
default:
ASSERT(useKind == WriteBarrierForGenericAccess);
return usesWithBarrierFromJit;
}
}
#else
// These are necessary to work around not having conditional exports.
static char usesWithBarrierFromCpp;
static char usesWithoutBarrierFromCpp;
#endif // ENABLE(WRITE_BARRIER_PROFILING)
static void countWriteBarrier()
{
#if ENABLE(WRITE_BARRIER_PROFILING)
WriteBarrierCounters::usesWithBarrierFromCpp.count();
#endif
}
};
} // namespace JSC
#endif // WriteBarrierSupport_h
......@@ -299,7 +299,7 @@ namespace JSC {
void testPrototype(JSValue, JumpList& failureCases);
void emitWriteBarrier(RegisterID owner, RegisterID scratch);
void emitWriteBarrier(RegisterID owner, RegisterID scratch, WriteBarrierUseKind);
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);
......
......@@ -438,7 +438,7 @@ void JIT::emit_op_put_by_id(Instruction* currentInstruction)
// Jump to a slow case if either the base object is an immediate, or if the Structure does not match.
emitJumpSlowCaseIfNotJSCell(regT0, baseVReg);
emitWriteBarrier(regT0, regT2);
emitWriteBarrier(regT0, regT2, WriteBarrierForPropertyAccess);
BEGIN_UNINTERRUPTED_SEQUENCE(sequencePutById);
......@@ -543,7 +543,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure
restoreReturnAddressBeforeReturn(regT3);
}
emitWriteBarrier(regT0, regT2);
emitWriteBarrier(regT0, regT2, WriteBarrierForPropertyAccess);
storePtr(TrustedImmPtr(newStructure), Address(regT0, JSCell::structureOffset()));
compilePutDirectOffset(regT0, regT1, newStructure, cachedOffset);
......@@ -996,7 +996,7 @@ void JIT::emit_op_put_scoped_var(Instruction* currentInstruction)
loadPtr(Address(regT1, OBJECT_OFFSETOF(ScopeChainNode, next)), regT1);
loadPtr(Address(regT1, OBJECT_OFFSETOF(ScopeChainNode, object)), regT1);
emitWriteBarrier(regT1, regT2);
emitWriteBarrier(regT1, regT2, WriteBarrierForVariableAccess);
loadPtr(Address(regT1, JSVariableObject::offsetOfRegisters()), regT1);
storePtr(regT0, Address(regT1, currentInstruction[1].u.operand * sizeof(Register)));
......@@ -1017,17 +1017,22 @@ void JIT::emit_op_put_global_var(Instruction* currentInstruction)
emitGetVirtualRegister(currentInstruction[2].u.operand, regT0);
move(TrustedImmPtr(globalObject), regT1);
emitWriteBarrier(regT1, regT2);
emitWriteBarrier(regT1, regT2, WriteBarrierForVariableAccess);
loadPtr(Address(regT1, JSVariableObject::offsetOfRegisters()), regT1);
storePtr(regT0, Address(regT1, currentInstruction[1].u.operand * sizeof(Register)));
}
void JIT::emitWriteBarrier(RegisterID owner, RegisterID scratch)
void JIT::emitWriteBarrier(RegisterID owner, RegisterID scratch, WriteBarrierUseKind useKind)
{
UNUSED_PARAM(owner);
UNUSED_PARAM(scratch);
UNUSED_PARAM(useKind);
ASSERT(owner != scratch);
#if ENABLE(WRITE_BARRIER_PROFILING)
emitCount(WriteBarrierCounters::jitCounterFor(useKind));
#endif
}
#endif // USE(JSVALUE64)
......
......@@ -259,7 +259,7 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
emitJumpSlowCaseIfNotJSCell(base, regT1);
emitWriteBarrier(regT0, regT1);
emitWriteBarrier(regT0, regT1, WriteBarrierForPropertyAccess);
addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsArrayVPtr)));
addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, JSArray::vectorLengthOffset())));
......@@ -395,7 +395,7 @@ void JIT::emit_op_put_by_id(Instruction* currentInstruction)
emitJumpSlowCaseIfNotJSCell(base, regT1);
emitWriteBarrier(regT0, regT1);
emitWriteBarrier(regT0, regT1, WriteBarrierForPropertyAccess);
BEGIN_UNINTERRUPTED_SEQUENCE(sequencePutById);
......@@ -521,7 +521,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure
#endif
}
emitWriteBarrier(regT0, regT1);
emitWriteBarrier(regT0, regT1, WriteBarrierForPropertyAccess);
storePtr(TrustedImmPtr(newStructure), Address(regT0, JSCell::structureOffset()));
#if CPU(MIPS) || CPU(SH4) || CPU(ARM)
......@@ -1051,7 +1051,7 @@ void JIT::emit_op_put_scoped_var(Instruction* currentInstruction)
loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2);
loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, object)), regT2);
emitWriteBarrier(regT2, regT3);
emitWriteBarrier(regT2, regT3, WriteBarrierForVariableAccess);
loadPtr(Address(regT2, JSVariableObject::offsetOfRegisters()), regT2);
emitStore(index, regT1, regT0, regT2);
......@@ -1082,18 +1082,23 @@ void JIT::emit_op_put_global_var(Instruction* currentInstruction)
emitLoad(value, regT1, regT0);
move(TrustedImmPtr(globalObject), regT2);
emitWriteBarrier(regT2, regT3);
emitWriteBarrier(regT2, regT3, WriteBarrierForVariableAccess);
loadPtr(Address(regT2, JSVariableObject::offsetOfRegisters()), regT2);
emitStore(index, regT1, regT0, regT2);
map(m_bytecodeOffset + OPCODE_LENGTH(op_put_global_var), value, regT1, regT0);
}
void JIT::emitWriteBarrier(RegisterID owner, RegisterID scratch)
void JIT::emitWriteBarrier(RegisterID owner, RegisterID scratch, WriteBarrierUseKind useKind)
{