fourthTier: value profiles and array profiles should be thread-safe enough to be...
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 25 Jul 2013 03:58:47 +0000 (03:58 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 25 Jul 2013 03:58:47 +0000 (03:58 +0000)
https://bugs.webkit.org/show_bug.cgi?id=114906

Source/JavaScriptCore:

Reviewed by Oliver Hunt.

This introduces thread safety to value profiles, array profiles, and
array allocation profiles.

We already have three separate operations that happen on profiles:
(1) writing, which the JIT, LLInt, and OSR exit do; (2) updating,
which happens during GC, from OSR entry slow-paths, and in the DFG;
and (3) reading, which happens in the DFG. For example, the JIT/LLInt
and OSR exit write to ValueProfile::m_buckets, which gets synthesized
into ValueProfile::m_prediction (and other fields) during update, and
the latter gets read by the DFG. Note that (2) must also happen in
the DFG since only the DFG knows which code blocks it will inline,
and those blocks' profiles may not have otherwise been updated via
any other mechanism.

I refer to these three operations as writing, updating, and reading.

Consequently, both profile updating and profile reading may happen
asynchronously, if the JIT is asynchronous.

The locking protocol for profiles works as follows:

- Writing does not require locking, but is only allowed on the main
  thread. We require that these fields can be stored atomically by
  the profiling code, even without locks. For value profiles, this
  only works on 64-bit platforms, currently. For array profiles,
  which consist of multiple separate fields, this means that an
  asynchronous update of the profile may see slight inconsistencies
  (like a structure that doesn't quite match the array modes bits),
  but these should be harmless: at worst, the DFG will specialize
  too much and we'll have OSR exits.

- Updating a value profile requires holding a lock, but must assume
  that the fields written by the profiling code in JIT/LLInt may
  be written to without locking.

- Reading a value profile requires holding a lock.

The one major exception to these rules is the ArrayAllocationProfile,
which requires no locking. We do this because it's used so often and
in places where we don't necessarily have access to the owning
CodeBlock, so if we did want it to be locked it would have to have
its own lock. Also, I believe that it is sound to just make this
profile racy and not worry about locking at all. All that was needed
were some changes to ensure that we explicitly read some raced-over
fields only once.

Two additional interesting things in this change:

- To make it easy to see which profile methods require locking, they
  take a const CodeBlockLocker& as an argument. I saw this idiom for
  identifying which methods require which locks to be held being used
  in LLVM, and I quite like it.

- Lazy operand value profiles, which are created lazily and at any
  time, require the CodeBlockLock to be held when they are being
  created. Writes to them are lockless and main-thread-only, but as
  with other profiles, updates and reads require locking.

* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/ArrayAllocationProfile.cpp:
(JSC::ArrayAllocationProfile::updateIndexingType):
* bytecode/ArrayAllocationProfile.h:
(JSC::ArrayAllocationProfile::selectIndexingType):
* bytecode/ArrayProfile.cpp:
(JSC::ArrayProfile::computeUpdatedPrediction):
(JSC::ArrayProfile::briefDescription):
* bytecode/ArrayProfile.h:
(ArrayProfile):
(JSC::ArrayProfile::expectedStructure):
(JSC::ArrayProfile::structureIsPolymorphic):
(JSC::ArrayProfile::hasDefiniteStructure):
(JSC::ArrayProfile::observedArrayModes):
(JSC::ArrayProfile::mayInterceptIndexedAccesses):
(JSC::ArrayProfile::mayStoreToHole):
(JSC::ArrayProfile::outOfBounds):
(JSC::ArrayProfile::usesOriginalArrayStructures):
* bytecode/CallLinkStatus.cpp:
(JSC::CallLinkStatus::computeFor):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpValueProfiling):
(JSC::CodeBlock::dumpArrayProfiling):
(JSC::CodeBlock::updateAllPredictionsAndCountLiveness):
(JSC::CodeBlock::updateAllArrayPredictions):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::valueProfilePredictionForBytecodeOffset):
(JSC::CodeBlock::updateAllPredictionsAndCheckIfShouldOptimizeNow):
(CodeBlock):
* bytecode/CodeBlockLock.h: Added.
(JSC):
* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::computeFor):
* bytecode/LazyOperandValueProfile.cpp:
(JSC::CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions):
(JSC::CompressedLazyOperandValueProfileHolder::add):
(JSC::LazyOperandValueProfileParser::LazyOperandValueProfileParser):
(JSC::LazyOperandValueProfileParser::~LazyOperandValueProfileParser):
(JSC):
(JSC::LazyOperandValueProfileParser::initialize):
(JSC::LazyOperandValueProfileParser::prediction):
* bytecode/LazyOperandValueProfile.h:
(CompressedLazyOperandValueProfileHolder):
(LazyOperandValueProfileParser):
* bytecode/MethodOfGettingAValueProfile.cpp:
(JSC::MethodOfGettingAValueProfile::getSpecFailBucket):
* bytecode/PutByIdStatus.cpp:
(JSC::PutByIdStatus::computeFor):
* bytecode/ResolveGlobalStatus.cpp:
(JSC::ResolveGlobalStatus::computeFor):
* bytecode/ValueProfile.h:
(JSC::ValueProfileBase::briefDescription):
(ValueProfileBase):
(JSC::ValueProfileBase::computeUpdatedPrediction):
* dfg/DFGArrayMode.cpp:
(JSC::DFG::ArrayMode::fromObserved):
* dfg/DFGArrayMode.h:
(ArrayMode):
(JSC::DFG::ArrayMode::withProfile):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::injectLazyOperandSpeculation):
(JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit):
(JSC::DFG::ByteCodeParser::getArrayMode):
(JSC::DFG::ByteCodeParser::getArrayModeAndEmitChecks):
(JSC::DFG::ByteCodeParser::parseResolveOperations):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGOSRExitPreparation.cpp:
(JSC::DFG::prepareCodeOriginForOSRExit):
* dfg/DFGPredictionInjectionPhase.cpp:
(JSC::DFG::PredictionInjectionPhase::run):
* jit/JITInlines.h:
(JSC::JIT::chooseArrayMode):
* jit/JITStubs.cpp:
(JSC::tryCachePutByID):
(JSC::tryCacheGetByID):
(JSC::DEFINE_STUB_FUNCTION):
(JSC::lazyLinkFor):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
(JSC::LLInt::setUpCall):
* profiler/ProfilerBytecodeSequence.cpp:
(JSC::Profiler::BytecodeSequence::BytecodeSequence):
* runtime/JSScope.cpp:
(JSC::JSScope::resolveContainingScopeInternal):
(JSC::JSScope::resolvePut):

Source/WTF:

Reviewed by Oliver Hunt.

Add ability to abstract whether or not the CodeBlock requires locking at all,
since some platforms may not support the byte spin-locking and/or may not want
to, if they turn off concurrent JIT.

* WTF.xcodeproj/project.pbxproj:
* wtf/ByteSpinLock.h:
* wtf/NoLock.h: Added.
(WTF):
(NoLock):
(WTF::NoLock::lock):
(WTF::NoLock::unlock):
(WTF::NoLock::isHeld):
* wtf/Platform.h:

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

33 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp
Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h
Source/JavaScriptCore/bytecode/ArrayProfile.cpp
Source/JavaScriptCore/bytecode/ArrayProfile.h
Source/JavaScriptCore/bytecode/CallLinkStatus.cpp
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/CodeBlockLock.h [new file with mode: 0644]
Source/JavaScriptCore/bytecode/GetByIdStatus.cpp
Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp
Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h
Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.cpp
Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
Source/JavaScriptCore/bytecode/ResolveGlobalStatus.cpp
Source/JavaScriptCore/bytecode/ValueProfile.h
Source/JavaScriptCore/dfg/DFGArrayMode.cpp
Source/JavaScriptCore/dfg/DFGArrayMode.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGOSRExitPreparation.cpp
Source/JavaScriptCore/dfg/DFGPredictionInjectionPhase.cpp
Source/JavaScriptCore/jit/JITInlines.h
Source/JavaScriptCore/jit/JITStubs.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp
Source/JavaScriptCore/runtime/JSScope.cpp
Source/WTF/ChangeLog
Source/WTF/WTF.xcodeproj/project.pbxproj
Source/WTF/wtf/ByteSpinLock.h
Source/WTF/wtf/NoLock.h [new file with mode: 0644]
Source/WTF/wtf/Platform.h

index ae6872d..d4c1838 100644 (file)
@@ -1,3 +1,157 @@
+2013-04-20  Filip Pizlo  <fpizlo@apple.com>
+
+        fourthTier: value profiles and array profiles should be thread-safe enough to be accessible in a concurrent compilation thread
+        https://bugs.webkit.org/show_bug.cgi?id=114906
+
+        Reviewed by Oliver Hunt.
+        
+        This introduces thread safety to value profiles, array profiles, and
+        array allocation profiles.
+        
+        We already have three separate operations that happen on profiles:
+        (1) writing, which the JIT, LLInt, and OSR exit do; (2) updating,
+        which happens during GC, from OSR entry slow-paths, and in the DFG;
+        and (3) reading, which happens in the DFG. For example, the JIT/LLInt
+        and OSR exit write to ValueProfile::m_buckets, which gets synthesized
+        into ValueProfile::m_prediction (and other fields) during update, and
+        the latter gets read by the DFG. Note that (2) must also happen in
+        the DFG since only the DFG knows which code blocks it will inline,
+        and those blocks' profiles may not have otherwise been updated via
+        any other mechanism.
+        
+        I refer to these three operations as writing, updating, and reading.
+        
+        Consequently, both profile updating and profile reading may happen
+        asynchronously, if the JIT is asynchronous.
+        
+        The locking protocol for profiles works as follows:
+        
+        - Writing does not require locking, but is only allowed on the main
+          thread. We require that these fields can be stored atomically by
+          the profiling code, even without locks. For value profiles, this
+          only works on 64-bit platforms, currently. For array profiles,
+          which consist of multiple separate fields, this means that an
+          asynchronous update of the profile may see slight inconsistencies
+          (like a structure that doesn't quite match the array modes bits),
+          but these should be harmless: at worst, the DFG will specialize
+          too much and we'll have OSR exits.
+        
+        - Updating a value profile requires holding a lock, but must assume
+          that the fields written by the profiling code in JIT/LLInt may
+          be written to without locking.
+        
+        - Reading a value profile requires holding a lock.
+        
+        The one major exception to these rules is the ArrayAllocationProfile,
+        which requires no locking. We do this because it's used so often and
+        in places where we don't necessarily have access to the owning
+        CodeBlock, so if we did want it to be locked it would have to have
+        its own lock. Also, I believe that it is sound to just make this
+        profile racy and not worry about locking at all. All that was needed
+        were some changes to ensure that we explicitly read some raced-over
+        fields only once.
+
+        Two additional interesting things in this change:
+        
+        - To make it easy to see which profile methods require locking, they
+          take a const CodeBlockLocker& as an argument. I saw this idiom for
+          identifying which methods require which locks to be held being used
+          in LLVM, and I quite like it.
+        
+        - Lazy operand value profiles, which are created lazily and at any
+          time, require the CodeBlockLock to be held when they are being
+          created. Writes to them are lockless and main-thread-only, but as
+          with other profiles, updates and reads require locking.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/ArrayAllocationProfile.cpp:
+        (JSC::ArrayAllocationProfile::updateIndexingType):
+        * bytecode/ArrayAllocationProfile.h:
+        (JSC::ArrayAllocationProfile::selectIndexingType):
+        * bytecode/ArrayProfile.cpp:
+        (JSC::ArrayProfile::computeUpdatedPrediction):
+        (JSC::ArrayProfile::briefDescription):
+        * bytecode/ArrayProfile.h:
+        (ArrayProfile):
+        (JSC::ArrayProfile::expectedStructure):
+        (JSC::ArrayProfile::structureIsPolymorphic):
+        (JSC::ArrayProfile::hasDefiniteStructure):
+        (JSC::ArrayProfile::observedArrayModes):
+        (JSC::ArrayProfile::mayInterceptIndexedAccesses):
+        (JSC::ArrayProfile::mayStoreToHole):
+        (JSC::ArrayProfile::outOfBounds):
+        (JSC::ArrayProfile::usesOriginalArrayStructures):
+        * bytecode/CallLinkStatus.cpp:
+        (JSC::CallLinkStatus::computeFor):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpValueProfiling):
+        (JSC::CodeBlock::dumpArrayProfiling):
+        (JSC::CodeBlock::updateAllPredictionsAndCountLiveness):
+        (JSC::CodeBlock::updateAllArrayPredictions):
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::valueProfilePredictionForBytecodeOffset):
+        (JSC::CodeBlock::updateAllPredictionsAndCheckIfShouldOptimizeNow):
+        (CodeBlock):
+        * bytecode/CodeBlockLock.h: Added.
+        (JSC):
+        * bytecode/GetByIdStatus.cpp:
+        (JSC::GetByIdStatus::computeFor):
+        * bytecode/LazyOperandValueProfile.cpp:
+        (JSC::CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions):
+        (JSC::CompressedLazyOperandValueProfileHolder::add):
+        (JSC::LazyOperandValueProfileParser::LazyOperandValueProfileParser):
+        (JSC::LazyOperandValueProfileParser::~LazyOperandValueProfileParser):
+        (JSC):
+        (JSC::LazyOperandValueProfileParser::initialize):
+        (JSC::LazyOperandValueProfileParser::prediction):
+        * bytecode/LazyOperandValueProfile.h:
+        (CompressedLazyOperandValueProfileHolder):
+        (LazyOperandValueProfileParser):
+        * bytecode/MethodOfGettingAValueProfile.cpp:
+        (JSC::MethodOfGettingAValueProfile::getSpecFailBucket):
+        * bytecode/PutByIdStatus.cpp:
+        (JSC::PutByIdStatus::computeFor):
+        * bytecode/ResolveGlobalStatus.cpp:
+        (JSC::ResolveGlobalStatus::computeFor):
+        * bytecode/ValueProfile.h:
+        (JSC::ValueProfileBase::briefDescription):
+        (ValueProfileBase):
+        (JSC::ValueProfileBase::computeUpdatedPrediction):
+        * dfg/DFGArrayMode.cpp:
+        (JSC::DFG::ArrayMode::fromObserved):
+        * dfg/DFGArrayMode.h:
+        (ArrayMode):
+        (JSC::DFG::ArrayMode::withProfile):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::injectLazyOperandSpeculation):
+        (JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit):
+        (JSC::DFG::ByteCodeParser::getArrayMode):
+        (JSC::DFG::ByteCodeParser::getArrayModeAndEmitChecks):
+        (JSC::DFG::ByteCodeParser::parseResolveOperations):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGOSRExitPreparation.cpp:
+        (JSC::DFG::prepareCodeOriginForOSRExit):
+        * dfg/DFGPredictionInjectionPhase.cpp:
+        (JSC::DFG::PredictionInjectionPhase::run):
+        * jit/JITInlines.h:
+        (JSC::JIT::chooseArrayMode):
+        * jit/JITStubs.cpp:
+        (JSC::tryCachePutByID):
+        (JSC::tryCacheGetByID):
+        (JSC::DEFINE_STUB_FUNCTION):
+        (JSC::lazyLinkFor):
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        (JSC::LLInt::setUpCall):
+        * profiler/ProfilerBytecodeSequence.cpp:
+        (JSC::Profiler::BytecodeSequence::BytecodeSequence):
+        * runtime/JSScope.cpp:
+        (JSC::JSScope::resolveContainingScopeInternal):
+        (JSC::JSScope::resolvePut):
+
 2013-04-17  Filip Pizlo  <fpizlo@apple.com>
 
         fourthTier: all inline caches should thread-safe enough to allow a concurrent compilation thread to read them safely
index f82446e..75e845e 100644 (file)
@@ -73,6 +73,7 @@
                0F0B83B914BCF95F00885B4F /* CallReturnOffsetToBytecodeOffset.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0B83B814BCF95B00885B4F /* CallReturnOffsetToBytecodeOffset.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F0CD4C215F1A6070032F1C0 /* PutDirectIndexMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0CD4C015F1A6040032F1C0 /* PutDirectIndexMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F0CD4C415F6B6BB0032F1C0 /* SparseArrayValueMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F0CD4C315F6B6B50032F1C0 /* SparseArrayValueMap.cpp */; };
+               0F0D85B21723455400338210 /* CodeBlockLock.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0D85B11723455100338210 /* CodeBlockLock.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F0FC45A14BD15F500B81154 /* LLIntCallLinkInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0FC45814BD15F100B81154 /* LLIntCallLinkInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F13912916771C33009CCB07 /* ProfilerBytecodeSequence.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F13912416771C30009CCB07 /* ProfilerBytecodeSequence.cpp */; };
                0F13912A16771C36009CCB07 /* ProfilerBytecodeSequence.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F13912516771C30009CCB07 /* ProfilerBytecodeSequence.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F0B83B814BCF95B00885B4F /* CallReturnOffsetToBytecodeOffset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallReturnOffsetToBytecodeOffset.h; sourceTree = "<group>"; };
                0F0CD4C015F1A6040032F1C0 /* PutDirectIndexMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutDirectIndexMode.h; sourceTree = "<group>"; };
                0F0CD4C315F6B6B50032F1C0 /* SparseArrayValueMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SparseArrayValueMap.cpp; sourceTree = "<group>"; };
+               0F0D85B11723455100338210 /* CodeBlockLock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CodeBlockLock.h; sourceTree = "<group>"; };
                0F0FC45814BD15F100B81154 /* LLIntCallLinkInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLIntCallLinkInfo.h; sourceTree = "<group>"; };
                0F13912416771C30009CCB07 /* ProfilerBytecodeSequence.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProfilerBytecodeSequence.cpp; path = profiler/ProfilerBytecodeSequence.cpp; sourceTree = "<group>"; };
                0F13912516771C30009CCB07 /* ProfilerBytecodeSequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProfilerBytecodeSequence.h; path = profiler/ProfilerBytecodeSequence.h; sourceTree = "<group>"; };
                                969A07910ED1D3AE00F1F681 /* CodeBlock.h */,
                                0F8F943D1667632D00D61971 /* CodeBlockHash.cpp */,
                                0F8F943E1667632D00D61971 /* CodeBlockHash.h */,
+                               0F0D85B11723455100338210 /* CodeBlockLock.h */,
                                0F96EBB116676EF4008BADE3 /* CodeBlockWithJITType.h */,
                                0F8F9445166764EE00D61971 /* CodeOrigin.cpp */,
                                0FBD7E671447998F00481315 /* CodeOrigin.h */,
                                0F8335B81639C1EA001443B5 /* ArrayAllocationProfile.h in Headers */,
                                BC18C3E60E16F5CD00B34460 /* ArrayConstructor.h in Headers */,
                                0FB7F39515ED8E4600F167B2 /* ArrayConventions.h in Headers */,
+                               0F0D85B21723455400338210 /* CodeBlockLock.h in Headers */,
                                0F63945515D07057006A597C /* ArrayProfile.h in Headers */,
                                BC18C3E70E16F5CD00B34460 /* ArrayPrototype.h in Headers */,
                                BC18C5240E16FC8A00B34460 /* ArrayPrototype.lut.h in Headers */,
index 6d9afda..4a008e0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,9 +32,24 @@ namespace JSC {
 
 void ArrayAllocationProfile::updateIndexingType()
 {
-    if (!m_lastArray)
+    // This is awkwardly racy but totally sound even when executed concurrently. The
+    // worst cases go something like this:
+    //
+    // - Two threads race to execute this code; one of them succeeds in updating the
+    //   m_currentIndexingType and the other either updates it again, or sees a null
+    //   m_lastArray; if it updates it again then at worst it will cause the profile
+    //   to "forget" some array. That's still sound, since we don't promise that
+    //   this profile is a reflection of any kind of truth.
+    //
+    // - A concurrent thread reads m_lastArray, but that array is now dead. While
+    //   it's possible for that array to no longer be reachable, it cannot actually
+    //   be freed, since we require the GC to wait until all concurrent JITing
+    //   finishes.
+    
+    JSArray* lastArray = m_lastArray;
+    if (!lastArray)
         return;
-    m_currentIndexingType = leastUpperBoundOfIndexingTypes(m_currentIndexingType, m_lastArray->structure()->indexingType());
+    m_currentIndexingType = leastUpperBoundOfIndexingTypes(m_currentIndexingType, lastArray->structure()->indexingType());
     m_lastArray = 0;
 }
 
index a1647fa..f77b92a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -41,7 +41,8 @@ public:
     
     IndexingType selectIndexingType()
     {
-        if (m_lastArray && UNLIKELY(m_lastArray->structure()->indexingType() != m_currentIndexingType))
+        JSArray* lastArray = m_lastArray;
+        if (lastArray && UNLIKELY(lastArray->structure()->indexingType() != m_currentIndexingType))
             updateIndexingType();
         return m_currentIndexingType;
     }
index ae3c8f9..9f6b935 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -74,53 +74,35 @@ void dumpArrayModes(PrintStream& out, ArrayModes arrayModes)
         out.print("ArrayWithSlowPutArrayStorage");
 }
 
-ArrayModes ArrayProfile::updatedObservedArrayModes() const
+void ArrayProfile::computeUpdatedPrediction(const CodeBlockLocker& locker, CodeBlock* codeBlock, OperationInProgress operation)
 {
-    if (m_lastSeenStructure)
-        return m_observedArrayModes | arrayModeFromStructure(m_lastSeenStructure);
-    return m_observedArrayModes;
-}
-
-void ArrayProfile::computeUpdatedPrediction(CodeBlock* codeBlock, OperationInProgress operation)
-{
-    const bool verbose = false;
-    
     if (m_lastSeenStructure) {
         m_observedArrayModes |= arrayModeFromStructure(m_lastSeenStructure);
         m_mayInterceptIndexedAccesses |=
             m_lastSeenStructure->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero();
         if (!codeBlock->globalObject()->isOriginalArrayStructure(m_lastSeenStructure))
             m_usesOriginalArrayStructures = false;
-        if (!structureIsPolymorphic()) {
+        if (!structureIsPolymorphic(locker)) {
             if (!m_expectedStructure)
                 m_expectedStructure = m_lastSeenStructure;
-            else if (m_expectedStructure != m_lastSeenStructure) {
-                if (verbose)
-                    dataLog(*codeBlock, " bc#", m_bytecodeOffset, ": making structure polymorphic because ", RawPointer(m_expectedStructure), " (", m_expectedStructure->classInfo()->className, ") != ", RawPointer(m_lastSeenStructure), " (", m_lastSeenStructure->classInfo()->className, ")\n");
+            else if (m_expectedStructure != m_lastSeenStructure)
                 m_expectedStructure = polymorphicStructure();
-            }
         }
         m_lastSeenStructure = 0;
     }
     
-    if (hasTwoOrMoreBitsSet(m_observedArrayModes)) {
-        if (verbose)
-            dataLog(*codeBlock, " bc#", m_bytecodeOffset, ": making structure polymorphic because two or more bits are set in m_observedArrayModes\n");
+    if (hasTwoOrMoreBitsSet(m_observedArrayModes))
         m_expectedStructure = polymorphicStructure();
-    }
-    
+
     if (operation == Collection
-        && expectedStructure()
-        && !Heap::isMarked(m_expectedStructure)) {
-        if (verbose)
-            dataLog(*codeBlock, " bc#", m_bytecodeOffset, ": making structure during GC\n");
+        && expectedStructure(locker)
+        && !Heap::isMarked(m_expectedStructure))
         m_expectedStructure = polymorphicStructure();
-    }
 }
 
-CString ArrayProfile::briefDescription(CodeBlock* codeBlock)
+CString ArrayProfile::briefDescription(const CodeBlockLocker& locker, CodeBlock* codeBlock)
 {
-    computeUpdatedPrediction(codeBlock);
+    computeUpdatedPrediction(locker, codeBlock);
     
     StringPrintStream out;
     
@@ -133,7 +115,7 @@ CString ArrayProfile::briefDescription(CodeBlock* codeBlock)
         hasPrinted = true;
     }
     
-    if (structureIsPolymorphic()) {
+    if (structureIsPolymorphic(locker)) {
         if (hasPrinted)
             out.print(", ");
         out.print("struct = TOP");
index 3842756..d2c754b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,6 +26,7 @@
 #ifndef ArrayProfile_h
 #define ArrayProfile_h
 
+#include "CodeBlockLock.h"
 #include "JSArray.h"
 #include "Structure.h"
 #include <wtf/HashMap.h>
@@ -163,32 +164,31 @@ public:
         m_lastSeenStructure = structure;
     }
     
-    void computeUpdatedPrediction(CodeBlock*, OperationInProgress = NoOperation);
+    void computeUpdatedPrediction(const CodeBlockLocker&, CodeBlock*, OperationInProgress = NoOperation);
     
-    Structure* expectedStructure() const
+    Structure* expectedStructure(const CodeBlockLocker& locker) const
     {
-        if (structureIsPolymorphic())
+        if (structureIsPolymorphic(locker))
             return 0;
         return m_expectedStructure;
     }
-    bool structureIsPolymorphic() const
+    bool structureIsPolymorphic(const CodeBlockLocker&) const
     {
         return m_expectedStructure == polymorphicStructure();
     }
-    bool hasDefiniteStructure() const
+    bool hasDefiniteStructure(const CodeBlockLocker& locker) const
     {
-        return !structureIsPolymorphic() && m_expectedStructure;
+        return !structureIsPolymorphic(locker) && m_expectedStructure;
     }
-    ArrayModes observedArrayModes() const { return m_observedArrayModes; }
-    ArrayModes updatedObservedArrayModes() const; // Computes the observed array modes without updating the profile.
-    bool mayInterceptIndexedAccesses() const { return m_mayInterceptIndexedAccesses; }
+    ArrayModes observedArrayModes(const CodeBlockLocker&) const { return m_observedArrayModes; }
+    bool mayInterceptIndexedAccesses(const CodeBlockLocker&) const { return m_mayInterceptIndexedAccesses; }
     
-    bool mayStoreToHole() const { return m_mayStoreToHole; }
-    bool outOfBounds() const { return m_outOfBounds; }
+    bool mayStoreToHole(const CodeBlockLocker&) const { return m_mayStoreToHole; }
+    bool outOfBounds(const CodeBlockLocker&) const { return m_outOfBounds; }
     
-    bool usesOriginalArrayStructures() const { return m_usesOriginalArrayStructures; }
+    bool usesOriginalArrayStructures(const CodeBlockLocker&) const { return m_usesOriginalArrayStructures; }
     
-    CString briefDescription(CodeBlock*);
+    CString briefDescription(const CodeBlockLocker&, CodeBlock*);
     
 private:
     friend class LLIntOffsetsExtractor;
index 99b836f..bfbc10b 100644 (file)
@@ -97,7 +97,7 @@ CallLinkStatus CallLinkStatus::computeFromLLInt(CodeBlock* profiledBlock, unsign
 
 CallLinkStatus CallLinkStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex)
 {
-    CodeBlock::Locker locker(profiledBlock->m_lock);
+    CodeBlockLocker locker(profiledBlock->m_lock);
     
     UNUSED_PARAM(profiledBlock);
     UNUSED_PARAM(bytecodeIndex);
index 356b0cd..618f9f5 100644 (file)
@@ -661,9 +661,11 @@ void CodeBlock::beginDumpProfiling(PrintStream& out, bool& hasPrintedProfiling)
 
 void CodeBlock::dumpValueProfiling(PrintStream& out, const Instruction*& it, bool& hasPrintedProfiling)
 {
+    CodeBlockLocker locker(m_lock);
+    
     ++it;
 #if ENABLE(VALUE_PROFILER)
-    CString description = it->u.profile->briefDescription();
+    CString description = it->u.profile->briefDescription(locker);
     if (!description.length())
         return;
     beginDumpProfiling(out, hasPrintedProfiling);
@@ -676,9 +678,11 @@ void CodeBlock::dumpValueProfiling(PrintStream& out, const Instruction*& it, boo
 
 void CodeBlock::dumpArrayProfiling(PrintStream& out, const Instruction*& it, bool& hasPrintedProfiling)
 {
+    CodeBlockLocker locker(m_lock);
+    
     ++it;
 #if ENABLE(VALUE_PROFILER)
-    CString description = it->u.arrayProfile->briefDescription(this);
+    CString description = it->u.arrayProfile->briefDescription(locker, this);
     if (!description.length())
         return;
     beginDumpProfiling(out, hasPrintedProfiling);
@@ -3145,6 +3149,8 @@ ArrayProfile* CodeBlock::getOrAddArrayProfile(unsigned bytecodeOffset)
 void CodeBlock::updateAllPredictionsAndCountLiveness(
     OperationInProgress operation, unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles)
 {
+    CodeBlockLock locker(m_lock);
+    
     numberOfLiveNonArgumentValueProfiles = 0;
     numberOfSamplesInProfiles = 0; // If this divided by ValueProfile::numberOfBuckets equals numberOfValueProfiles() then value profiles are full.
     for (unsigned i = 0; i < totalNumberOfValueProfiles(); ++i) {
@@ -3154,16 +3160,16 @@ void CodeBlock::updateAllPredictionsAndCountLiveness(
             numSamples = ValueProfile::numberOfBuckets; // We don't want profiles that are extremely hot to be given more weight.
         numberOfSamplesInProfiles += numSamples;
         if (profile->m_bytecodeOffset < 0) {
-            profile->computeUpdatedPrediction(operation);
+            profile->computeUpdatedPrediction(locker, operation);
             continue;
         }
         if (profile->numberOfSamples() || profile->m_prediction != SpecNone)
             numberOfLiveNonArgumentValueProfiles++;
-        profile->computeUpdatedPrediction(operation);
+        profile->computeUpdatedPrediction(locker, operation);
     }
     
 #if ENABLE(DFG_JIT)
-    m_lazyOperandValueProfiles.computeUpdatedPredictions(operation);
+    m_lazyOperandValueProfiles.computeUpdatedPredictions(locker, operation);
 #endif
 }
 
@@ -3175,8 +3181,10 @@ void CodeBlock::updateAllValueProfilePredictions(OperationInProgress operation)
 
 void CodeBlock::updateAllArrayPredictions(OperationInProgress operation)
 {
+    CodeBlockLock locker(m_lock);
+    
     for (unsigned i = m_arrayProfiles.size(); i--;)
-        m_arrayProfiles[i].computeUpdatedPrediction(this, operation);
+        m_arrayProfiles[i].computeUpdatedPrediction(locker, this, operation);
     
     // Don't count these either, for similar reasons.
     for (unsigned i = m_arrayAllocationProfiles.size(); i--;)
index 52b2878..d5afbe0 100644 (file)
@@ -36,6 +36,7 @@
 #include "CallLinkInfo.h"
 #include "CallReturnOffsetToBytecodeOffset.h"
 #include "CodeBlockHash.h"
+#include "CodeBlockLock.h"
 #include "CodeOrigin.h"
 #include "CodeType.h"
 #include "CompactJITCodeMap.h"
@@ -69,7 +70,6 @@
 #include "UnconditionalFinalizer.h"
 #include "ValueProfile.h"
 #include "Watchpoint.h"
-#include <wtf/ByteSpinLock.h>
 #include <wtf/RefCountedArray.h>
 #include <wtf/FastAllocBase.h>
 #include <wtf/PassOwnPtr.h>
@@ -485,9 +485,9 @@ namespace JSC {
                                                                                                               bytecodeOffset].u.opcode)) - 1].u.profile == result);
             return result;
         }
-        SpeculatedType valueProfilePredictionForBytecodeOffset(int bytecodeOffset)
+        SpeculatedType valueProfilePredictionForBytecodeOffset(const CodeBlockLocker& locker, int bytecodeOffset)
         {
-            return valueProfileForBytecodeOffset(bytecodeOffset)->computeUpdatedPrediction();
+            return valueProfileForBytecodeOffset(bytecodeOffset)->computeUpdatedPrediction(locker);
         }
 
         unsigned totalNumberOfValueProfiles()
@@ -902,7 +902,7 @@ namespace JSC {
         void updateAllArrayPredictions(OperationInProgress = NoOperation);
         void updateAllPredictions(OperationInProgress = NoOperation);
 #else
-        bool shouldOptimizeNow() { return false; }
+        bool updateAllPredictionsAndCheckIfShouldOptimizeNow() { return false; }
         void updateAllValueProfilePredictions(OperationInProgress = NoOperation) { }
         void updateAllArrayPredictions(OperationInProgress = NoOperation) { }
         void updateAllPredictions(OperationInProgress = NoOperation) { }
@@ -938,9 +938,7 @@ namespace JSC {
         // Another exception to the rules is that the GC can do whatever it wants
         // without holding any locks, because the GC is guaranteed to wait until any
         // concurrent compilation threads finish what they're doing.
-        typedef ByteSpinLock Lock;
-        typedef ByteSpinLocker Locker;
-        Lock m_lock;
+        CodeBlockLock m_lock;
 
     protected:
 #if ENABLE(JIT)
diff --git a/Source/JavaScriptCore/bytecode/CodeBlockLock.h b/Source/JavaScriptCore/bytecode/CodeBlockLock.h
new file mode 100644 (file)
index 0000000..ce7fdc6
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013 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 CodeBlockLock_h
+#define CodeBlockLock_h
+
+#include <wtf/ByteSpinLock.h>
+#include <wtf/NoLock.h>
+
+namespace JSC {
+
+#if ENABLE(CONCURRENT_JIT)
+typedef ByteSpinLock CodeBlockLock;
+typedef ByteSpinLocker CodeBlockLocker;
+#else
+typedef NoLock CodeBlockLock;
+typedef NoLockLocker CodeBlockLocker;
+#endif
+
+} // namespace JSC
+
+#endif // CodeBlockLock_h
+
index 74a8b76..be64c5b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -112,7 +112,7 @@ void GetByIdStatus::computeForChain(GetByIdStatus& result, CodeBlock* profiledBl
 
 GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex, Identifier& ident)
 {
-    CodeBlock::Locker locker(profiledBlock->m_lock);
+    CodeBlockLocker locker(profiledBlock->m_lock);
     
     UNUSED_PARAM(profiledBlock);
     UNUSED_PARAM(bytecodeIndex);
index 97b8f3b..ea9534b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -35,17 +35,17 @@ namespace JSC {
 CompressedLazyOperandValueProfileHolder::CompressedLazyOperandValueProfileHolder() { }
 CompressedLazyOperandValueProfileHolder::~CompressedLazyOperandValueProfileHolder() { }
 
-void CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions(OperationInProgress operation)
+void CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions(const CodeBlockLocker& locker, OperationInProgress operation)
 {
     if (!m_data)
         return;
     
     for (unsigned i = 0; i < m_data->size(); ++i)
-        m_data->at(i).computeUpdatedPrediction(operation);
+        m_data->at(i).computeUpdatedPrediction(locker, operation);
 }
 
 LazyOperandValueProfile* CompressedLazyOperandValueProfileHolder::add(
-    const LazyOperandValueProfileKey& key)
+    const CodeBlockLocker&, const LazyOperandValueProfileKey& key)
 {
     if (!m_data)
         m_data = adoptPtr(new LazyOperandValueProfile::List());
@@ -60,20 +60,22 @@ LazyOperandValueProfile* CompressedLazyOperandValueProfileHolder::add(
     return &m_data->last();
 }
 
-LazyOperandValueProfileParser::LazyOperandValueProfileParser(
-    CompressedLazyOperandValueProfileHolder& holder)
-    : m_holder(holder)
+LazyOperandValueProfileParser::LazyOperandValueProfileParser() { }
+LazyOperandValueProfileParser::~LazyOperandValueProfileParser() { }
+
+void LazyOperandValueProfileParser::initialize(
+    const CodeBlockLocker&, CompressedLazyOperandValueProfileHolder& holder)
 {
-    if (!m_holder.m_data)
+    ASSERT(m_map.isEmpty());
+    
+    if (!holder.m_data)
         return;
     
-    LazyOperandValueProfile::List& data = *m_holder.m_data;
+    LazyOperandValueProfile::List& data = *holder.m_data;
     for (unsigned i = 0; i < data.size(); ++i)
         m_map.add(data[i].key(), &data[i]);
 }
 
-LazyOperandValueProfileParser::~LazyOperandValueProfileParser() { }
-
 LazyOperandValueProfile* LazyOperandValueProfileParser::getIfPresent(
     const LazyOperandValueProfileKey& key) const
 {
@@ -87,13 +89,13 @@ LazyOperandValueProfile* LazyOperandValueProfileParser::getIfPresent(
 }
 
 SpeculatedType LazyOperandValueProfileParser::prediction(
-    const LazyOperandValueProfileKey& key) const
+    const CodeBlockLocker& locker, const LazyOperandValueProfileKey& key) const
 {
     LazyOperandValueProfile* profile = getIfPresent(key);
     if (!profile)
         return SpecNone;
     
-    return profile->computeUpdatedPrediction();
+    return profile->computeUpdatedPrediction(locker);
 }
 
 } // namespace JSC
index a117db6..c04b47d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -30,6 +30,7 @@
 
 #if ENABLE(VALUE_PROFILER)
 
+#include "CodeBlockLock.h"
 #include "ValueProfile.h"
 #include <wtf/HashMap.h>
 #include <wtf/Noncopyable.h>
@@ -155,9 +156,10 @@ public:
     CompressedLazyOperandValueProfileHolder();
     ~CompressedLazyOperandValueProfileHolder();
     
-    void computeUpdatedPredictions(OperationInProgress);
+    void computeUpdatedPredictions(const CodeBlockLocker&, OperationInProgress);
     
-    LazyOperandValueProfile* add(const LazyOperandValueProfileKey& key);
+    LazyOperandValueProfile* add(
+        const CodeBlockLocker&, const LazyOperandValueProfileKey& key);
     
 private:
     friend class LazyOperandValueProfileParser;
@@ -167,16 +169,18 @@ private:
 class LazyOperandValueProfileParser {
     WTF_MAKE_NONCOPYABLE(LazyOperandValueProfileParser);
 public:
-    explicit LazyOperandValueProfileParser(
-        CompressedLazyOperandValueProfileHolder& holder);
+    explicit LazyOperandValueProfileParser();
     ~LazyOperandValueProfileParser();
     
+    void initialize(
+        const CodeBlockLocker&, CompressedLazyOperandValueProfileHolder& holder);
+    
     LazyOperandValueProfile* getIfPresent(
         const LazyOperandValueProfileKey& key) const;
     
-    SpeculatedType prediction(const LazyOperandValueProfileKey& key) const;
+    SpeculatedType prediction(
+        const CodeBlockLocker&, const LazyOperandValueProfileKey& key) const;
 private:
-    CompressedLazyOperandValueProfileHolder& m_holder;
     HashMap<LazyOperandValueProfileKey, LazyOperandValueProfile*> m_map;
 };
 
index a0f301a..3ebc525 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -52,10 +52,14 @@ EncodedJSValue* MethodOfGettingAValueProfile::getSpecFailBucket(unsigned index)
     case Ready:
         return u.profile->specFailBucket(index);
         
-    case LazyOperand:
-        return u.lazyOperand.codeBlock->lazyOperandValueProfiles().add(
-            LazyOperandValueProfileKey(
-                u.lazyOperand.bytecodeOffset, u.lazyOperand.operand))->specFailBucket(index);
+    case LazyOperand: {
+        LazyOperandValueProfileKey key(u.lazyOperand.bytecodeOffset, u.lazyOperand.operand);
+        
+        CodeBlockLocker locker(u.lazyOperand.codeBlock->m_lock);
+        LazyOperandValueProfile* profile =
+            u.lazyOperand.codeBlock->lazyOperandValueProfiles().add(locker, key);
+        return profile->specFailBucket(index);
+    }
         
     default:
         RELEASE_ASSERT_NOT_REACHED();
index ce03116..a63ccd2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -80,7 +80,7 @@ PutByIdStatus PutByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned
 
 PutByIdStatus PutByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex, Identifier& ident)
 {
-    CodeBlock::Locker locker(profiledBlock->m_lock);
+    CodeBlockLocker locker(profiledBlock->m_lock);
     
     UNUSED_PARAM(profiledBlock);
     UNUSED_PARAM(bytecodeIndex);
index 16b2f17..7e16f73 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -48,7 +48,7 @@ static ResolveGlobalStatus computeForStructure(CodeBlock* codeBlock, Structure*
 
 ResolveGlobalStatus ResolveGlobalStatus::computeFor(CodeBlock* codeBlock, int, ResolveOperation* operation, Identifier& identifier)
 {
-    CodeBlock::Locker locker(codeBlock->m_lock);
+    CodeBlockLocker locker(codeBlock->m_lock);
     
     ASSERT(operation->m_operation == ResolveOperation::GetAndReturnGlobalProperty);
     if (!operation->m_structure)
index 028c1f6..08a8fbd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,6 +33,7 @@
 
 #if ENABLE(VALUE_PROFILER)
 
+#include "CodeBlockLock.h"
 #include "Heap.h"
 #include "JSArray.h"
 #include "SpeculatedType.h"
@@ -111,9 +112,9 @@ struct ValueProfileBase {
         return false;
     }
     
-    CString briefDescription()
+    CString briefDescription(const CodeBlockLocker& locker)
     {
-        computeUpdatedPrediction();
+        computeUpdatedPrediction(locker);
         
         StringPrintStream out;
         
@@ -147,8 +148,9 @@ struct ValueProfileBase {
         }
     }
     
-    // Updates the prediction and returns the new one.
-    SpeculatedType computeUpdatedPrediction(OperationInProgress operation = NoOperation)
+    // Updates the prediction and returns the new one. Never call this from any thread
+    // that isn't executing the code.
+    SpeculatedType computeUpdatedPrediction(const CodeBlockLocker&, OperationInProgress operation = NoOperation)
     {
         for (unsigned i = 0; i < totalNumberOfBuckets; ++i) {
             JSValue value = JSValue::decode(m_buckets[i]);
index ede2ffc..d297bde 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 namespace JSC { namespace DFG {
 
-ArrayMode ArrayMode::fromObserved(ArrayProfile* profile, Array::Action action, bool makeSafe)
+ArrayMode ArrayMode::fromObserved(const CodeBlockLocker& locker, ArrayProfile* profile, Array::Action action, bool makeSafe)
 {
-    ArrayModes observed = profile->observedArrayModes();
+    ArrayModes observed = profile->observedArrayModes(locker);
     switch (observed) {
     case 0:
         return ArrayMode(Array::Unprofiled);
     case asArrayModes(NonArray):
-        if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
+        if (action == Array::Write && !profile->mayInterceptIndexedAccesses(locker))
             return ArrayMode(Array::Undecided, Array::NonArray, Array::OutOfBounds, Array::Convert);
         return ArrayMode(Array::SelectUsingPredictions);
 
@@ -51,49 +51,49 @@ ArrayMode ArrayMode::fromObserved(ArrayProfile* profile, Array::Action action, b
         return ArrayMode(Array::Generic);
         
     case asArrayModes(NonArray) | asArrayModes(ArrayWithUndecided):
-        if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
+        if (action == Array::Write && !profile->mayInterceptIndexedAccesses(locker))
             return ArrayMode(Array::Undecided, Array::PossiblyArray, Array::OutOfBounds, Array::Convert);
         return ArrayMode(Array::SelectUsingPredictions);
 
     case asArrayModes(NonArrayWithInt32):
-        return ArrayMode(Array::Int32, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
+        return ArrayMode(Array::Int32, Array::NonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
     case asArrayModes(ArrayWithInt32):
-        return ArrayMode(Array::Int32, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
+        return ArrayMode(Array::Int32, Array::Array, Array::AsIs).withProfile(locker, profile, makeSafe);
     case asArrayModes(NonArrayWithInt32) | asArrayModes(ArrayWithInt32):
-        return ArrayMode(Array::Int32, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
+        return ArrayMode(Array::Int32, Array::PossiblyArray, Array::AsIs).withProfile(locker, profile, makeSafe);
 
     case asArrayModes(NonArrayWithDouble):
-        return ArrayMode(Array::Double, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
+        return ArrayMode(Array::Double, Array::NonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
     case asArrayModes(ArrayWithDouble):
-        return ArrayMode(Array::Double, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
+        return ArrayMode(Array::Double, Array::Array, Array::AsIs).withProfile(locker, profile, makeSafe);
     case asArrayModes(NonArrayWithDouble) | asArrayModes(ArrayWithDouble):
-        return ArrayMode(Array::Double, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
+        return ArrayMode(Array::Double, Array::PossiblyArray, Array::AsIs).withProfile(locker, profile, makeSafe);
 
     case asArrayModes(NonArrayWithContiguous):
-        return ArrayMode(Array::Contiguous, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
+        return ArrayMode(Array::Contiguous, Array::NonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
     case asArrayModes(ArrayWithContiguous):
-        return ArrayMode(Array::Contiguous, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
+        return ArrayMode(Array::Contiguous, Array::Array, Array::AsIs).withProfile(locker, profile, makeSafe);
     case asArrayModes(NonArrayWithContiguous) | asArrayModes(ArrayWithContiguous):
-        return ArrayMode(Array::Contiguous, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
+        return ArrayMode(Array::Contiguous, Array::PossiblyArray, Array::AsIs).withProfile(locker, profile, makeSafe);
 
     case asArrayModes(NonArrayWithArrayStorage):
-        return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
+        return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
     case asArrayModes(NonArrayWithSlowPutArrayStorage):
     case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage):
-        return ArrayMode(Array::SlowPutArrayStorage, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
+        return ArrayMode(Array::SlowPutArrayStorage, Array::NonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
     case asArrayModes(ArrayWithArrayStorage):
-        return ArrayMode(Array::ArrayStorage, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
+        return ArrayMode(Array::ArrayStorage, Array::Array, Array::AsIs).withProfile(locker, profile, makeSafe);
     case asArrayModes(ArrayWithSlowPutArrayStorage):
     case asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
-        return ArrayMode(Array::SlowPutArrayStorage, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
+        return ArrayMode(Array::SlowPutArrayStorage, Array::Array, Array::AsIs).withProfile(locker, profile, makeSafe);
     case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage):
-        return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
+        return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::AsIs).withProfile(locker, profile, makeSafe);
     case asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
     case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
-        return ArrayMode(Array::SlowPutArrayStorage, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
+        return ArrayMode(Array::SlowPutArrayStorage, Array::PossiblyArray, Array::AsIs).withProfile(locker, profile, makeSafe);
 
     default:
-        if ((observed & asArrayModes(NonArray)) && profile->mayInterceptIndexedAccesses())
+        if ((observed & asArrayModes(NonArray)) && profile->mayInterceptIndexedAccesses(locker))
             return ArrayMode(Array::SelectUsingPredictions);
         
         Array::Type type;
@@ -121,7 +121,7 @@ ArrayMode ArrayMode::fromObserved(ArrayProfile* profile, Array::Action action, b
         else
             arrayClass = Array::PossiblyArray;
         
-        return ArrayMode(type, arrayClass, Array::Convert).withProfile(profile, makeSafe);
+        return ArrayMode(type, arrayClass, Array::Convert).withProfile(locker, profile, makeSafe);
     }
 }
 
index c6d966d..6781ab6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -150,27 +150,27 @@ public:
         return ArrayMode(word);
     }
     
-    static ArrayMode fromObserved(ArrayProfile*, Array::Action, bool makeSafe);
+    static ArrayMode fromObserved(const CodeBlockLocker&, ArrayProfile*, Array::Action, bool makeSafe);
     
     ArrayMode withSpeculation(Array::Speculation speculation) const
     {
         return ArrayMode(type(), arrayClass(), speculation, conversion());
     }
     
-    ArrayMode withProfile(ArrayProfile* profile, bool makeSafe) const
+    ArrayMode withProfile(const CodeBlockLocker& locker, ArrayProfile* profile, bool makeSafe) const
     {
         Array::Speculation mySpeculation;
         Array::Class myArrayClass;
         
         if (makeSafe)
             mySpeculation = Array::OutOfBounds;
-        else if (profile->mayStoreToHole())
+        else if (profile->mayStoreToHole(locker))
             mySpeculation = Array::ToHole;
         else
             mySpeculation = Array::InBounds;
         
         if (isJSArray()) {
-            if (profile->usesOriginalArrayStructures() && benefitsFromOriginalArray())
+            if (profile->usesOriginalArrayStructures(locker) && benefitsFromOriginalArray())
                 myArrayClass = Array::OriginalArray;
             else
                 myArrayClass = Array::Array;
index 941c0a7..d0c681a 100644 (file)
@@ -264,9 +264,9 @@ private:
     {
         ASSERT(node->op() == GetLocal);
         ASSERT(node->codeOrigin.bytecodeIndex == m_currentIndex);
-        SpeculatedType prediction = 
-            m_inlineStackTop->m_lazyOperands.prediction(
-                LazyOperandValueProfileKey(m_currentIndex, node->local()));
+        CodeBlockLock locker(m_inlineStackTop->m_profiledBlock->m_lock);
+        LazyOperandValueProfileKey key(m_currentIndex, node->local());
+        SpeculatedType prediction = m_inlineStackTop->m_lazyOperands.prediction(locker, key);
 #if DFG_ENABLE(DEBUG_VERBOSE)
         dataLog("Lazy operand [@", node->index(), ", bc#", m_currentIndex, ", r", node->local(), "] prediction: ", SpeculationDump(prediction), "\n");
 #endif
@@ -805,7 +805,8 @@ private:
     
     SpeculatedType getPredictionWithoutOSRExit(unsigned bytecodeIndex)
     {
-        return m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(bytecodeIndex);
+        CodeBlockLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
+        return m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(locker, bytecodeIndex);
     }
 
     SpeculatedType getPrediction(unsigned bytecodeIndex)
@@ -833,8 +834,9 @@ private:
     
     ArrayMode getArrayMode(ArrayProfile* profile, Array::Action action)
     {
-        profile->computeUpdatedPrediction(m_inlineStackTop->m_codeBlock);
-        return ArrayMode::fromObserved(profile, action, false);
+        CodeBlockLock locker(m_inlineStackTop->m_profiledBlock->m_lock);
+        profile->computeUpdatedPrediction(locker, m_inlineStackTop->m_profiledBlock);
+        return ArrayMode::fromObserved(locker, profile, action, false);
     }
     
     ArrayMode getArrayMode(ArrayProfile* profile)
@@ -844,24 +846,26 @@ private:
     
     ArrayMode getArrayModeAndEmitChecks(ArrayProfile* profile, Array::Action action, Node* base)
     {
-        profile->computeUpdatedPrediction(m_inlineStackTop->m_codeBlock);
+        CodeBlockLock locker(m_inlineStackTop->m_profiledBlock->m_lock);
+        
+        profile->computeUpdatedPrediction(locker, m_inlineStackTop->m_profiledBlock);
         
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
         if (m_inlineStackTop->m_profiledBlock->numberOfRareCaseProfiles())
             dataLogF("Slow case profile for bc#%u: %u\n", m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter);
-        dataLogF("Array profile for bc#%u: %p%s%s, %u\n", m_currentIndex, profile->expectedStructure(), profile->structureIsPolymorphic() ? " (polymorphic)" : "", profile->mayInterceptIndexedAccesses() ? " (may intercept)" : "", profile->observedArrayModes());
+        dataLogF("Array profile for bc#%u: %p%s%s, %u\n", m_currentIndex, profile->expectedStructure(), profile->structureIsPolymorphic(locker) ? " (polymorphic)" : "", profile->mayInterceptIndexedAccesses(locker) ? " (may intercept)" : "", profile->observedArrayModes(locker));
 #endif
         
         bool makeSafe =
             m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex)
-            || profile->outOfBounds();
+            || profile->outOfBounds(locker);
         
-        ArrayMode result = ArrayMode::fromObserved(profile, action, makeSafe);
+        ArrayMode result = ArrayMode::fromObserved(locker, profile, action, makeSafe);
         
-        if (profile->hasDefiniteStructure()
+        if (profile->hasDefiniteStructure(locker)
             && result.benefitsFromStructureCheck()
             && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache))
-            addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base);
+            addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure(locker))), base);
         
         return result;
     }
@@ -1787,7 +1791,7 @@ Node* ByteCodeParser::getScope(bool skipTop, unsigned skipCount)
 bool ByteCodeParser::parseResolveOperations(SpeculatedType prediction, unsigned identifier, ResolveOperations* resolveOperations, PutToBaseOperation* putToBaseOperation, Node** base, Node** value)
 {
     {
-        CodeBlock::Locker locker(m_inlineStackTop->m_profiledBlock->m_lock);
+        CodeBlockLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
      
         if (!resolveOperations->m_ready) {
             addToGraph(ForceOSRExit);
@@ -2023,9 +2027,10 @@ bool ByteCodeParser::parseBlock(unsigned limit)
         case op_convert_this: {
             Node* op1 = getThis();
             if (op1->op() != ConvertThis) {
+                CodeBlockLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
                 ValueProfile* profile =
                     m_inlineStackTop->m_profiledBlock->valueProfileForBytecodeOffset(m_currentProfilingIndex);
-                profile->computeUpdatedPrediction();
+                profile->computeUpdatedPrediction(locker);
 #if DFG_ENABLE(DEBUG_VERBOSE)
                 dataLogF("[bc#%u]: profile %p: ", m_currentProfilingIndex, profile);
                 profile->dump(WTF::dataFile());
@@ -2123,8 +2128,9 @@ bool ByteCodeParser::parseBlock(unsigned limit)
         }
             
         case op_get_callee: {
+            CodeBlockLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
             ValueProfile* profile = currentInstruction[2].u.profile;
-            profile->computeUpdatedPrediction();
+            profile->computeUpdatedPrediction(locker);
             if (profile->m_singletonValueIsTop
                 || !profile->m_singletonValue
                 || !profile->m_singletonValue.isCell())
@@ -3159,7 +3165,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             PutToBaseOperation* putToBase = currentInstruction[4].u.putToBaseOperation;
             
             {
-                CodeBlock::Locker locker(m_inlineStackTop->m_profiledBlock->m_lock);
+                CodeBlockLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
                 
                 if (!putToBase->m_ready) {
                     addToGraph(ForceOSRExit);
@@ -3485,11 +3491,15 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry(
     , m_exitProfile(profiledBlock->exitProfile())
     , m_callsiteBlockHead(callsiteBlockHead)
     , m_returnValue(returnValueVR)
-    , m_lazyOperands(profiledBlock->lazyOperandValueProfiles())
     , m_didReturn(false)
     , m_didEarlyReturn(false)
     , m_caller(byteCodeParser->m_inlineStackTop)
 {
+    {
+        CodeBlockLocker locker(m_profiledBlock->m_lock);
+        m_lazyOperands.initialize(locker, m_profiledBlock->lazyOperandValueProfiles());
+    }
+    
     m_argumentPositions.resize(argumentCountIncludingThis);
     for (int i = 0; i < argumentCountIncludingThis; ++i) {
         byteCodeParser->m_graph.m_argumentPositions.append(ArgumentPosition());
index ac28423..27bb1ac 100644 (file)
@@ -688,19 +688,19 @@ private:
                 break;
             if (codeBlock()->identifier(node->identifierNumber()) != vm().propertyNames->length)
                 break;
+            CodeBlock* profiledBlock = m_graph.baselineCodeBlockFor(node->codeOrigin);
             ArrayProfile* arrayProfile = 
-                m_graph.baselineCodeBlockFor(node->codeOrigin)->getArrayProfile(
-                    node->codeOrigin.bytecodeIndex);
+                profiledBlock->getArrayProfile(node->codeOrigin.bytecodeIndex);
             ArrayMode arrayMode = ArrayMode(Array::SelectUsingPredictions);
             if (arrayProfile) {
-                arrayProfile->computeUpdatedPrediction(m_graph.baselineCodeBlockFor(node->codeOrigin));
-                arrayMode = ArrayMode::fromObserved(arrayProfile, Array::Read, false);
-                arrayMode = arrayMode.refine(
-                    node->child1()->prediction(), node->prediction());
-                if (arrayMode.supportsLength() && arrayProfile->hasDefiniteStructure()) {
+                CodeBlockLocker locker(profiledBlock->m_lock);
+                arrayProfile->computeUpdatedPrediction(locker, profiledBlock);
+                arrayMode = ArrayMode::fromObserved(locker, arrayProfile, Array::Read, false);
+                arrayMode = arrayMode.refine(node->child1()->prediction(), node->prediction());
+                if (arrayMode.supportsLength() && arrayProfile->hasDefiniteStructure(locker)) {
                     m_insertionSet.insertNode(
                         m_indexInBlock, SpecNone, CheckStructure, node->codeOrigin,
-                        OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())),
+                        OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure(locker))),
                         node->child1());
                 }
             } else
index 82ac35b..44db0f1 100644 (file)
@@ -37,9 +37,12 @@ namespace JSC { namespace DFG {
 void prepareCodeOriginForOSRExit(ExecState* exec, CodeOrigin codeOrigin)
 {
     for (; codeOrigin.inlineCallFrame; codeOrigin = codeOrigin.inlineCallFrame->caller) {
-        static_cast<FunctionExecutable*>(codeOrigin.inlineCallFrame->executable.get())
-            ->baselineCodeBlockFor(codeOrigin.inlineCallFrame->isCall ? CodeForCall : CodeForConstruct)
-            ->jitCompile(exec);
+        FunctionExecutable* executable =
+            static_cast<FunctionExecutable*>(codeOrigin.inlineCallFrame->executable.get());
+        CodeBlock* codeBlock = executable->baselineCodeBlockFor(
+            codeOrigin.inlineCallFrame->isCall ? CodeForCall : CodeForConstruct);
+        
+        codeBlock->jitCompile(exec);
     }
 }
 
index d5a5920..2236876 100644 (file)
@@ -48,18 +48,24 @@ public:
         ASSERT(m_graph.m_unificationState == GloballyUnified);
         
         ASSERT(codeBlock()->numParameters() >= 1);
-        for (size_t arg = 0; arg < static_cast<size_t>(codeBlock()->numParameters()); ++arg) {
-            ValueProfile* profile = profiledBlock()->valueProfileForArgument(arg);
-            if (!profile)
-                continue;
+        {
+            CodeBlockLocker locker(profiledBlock()->m_lock);
+            
+            for (size_t arg = 0; arg < static_cast<size_t>(codeBlock()->numParameters()); ++arg) {
+                ValueProfile* profile = profiledBlock()->valueProfileForArgument(arg);
+                if (!profile)
+                    continue;
             
-            m_graph.m_arguments[arg]->variableAccessData()->predict(profile->computeUpdatedPrediction());
+                m_graph.m_arguments[arg]->variableAccessData()->predict(
+                    profile->computeUpdatedPrediction(locker));
             
 #if DFG_ENABLE(DEBUG_VERBOSE)
-            dataLog(
-                "Argument [", arg, "] prediction: ",
-                SpeculationDump(m_graph.m_arguments[arg]->variableAccessData()->prediction()), "\n");
+                dataLog(
+                    "Argument [", arg, "] prediction: ",
+                    SpeculationDump(m_graph.m_arguments[arg]->variableAccessData()->prediction()),
+                    "\n");
 #endif
+            }
         }
         
         for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
index 5e5d834..cfc0abb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -436,9 +436,10 @@ static inline bool arrayProfileSaw(ArrayModes arrayModes, IndexingType capabilit
 
 inline JITArrayMode JIT::chooseArrayMode(ArrayProfile* profile)
 {
-#if ENABLE(VALUE_PROFILER)        
-    profile->computeUpdatedPrediction(m_codeBlock);
-    ArrayModes arrayModes = profile->observedArrayModes();
+#if ENABLE(VALUE_PROFILER)
+    CodeBlockLocker locker(m_codeBlock->m_lock);
+    profile->computeUpdatedPrediction(locker, m_codeBlock);
+    ArrayModes arrayModes = profile->observedArrayModes(locker);
     if (arrayProfileSaw(arrayModes, DoubleShape))
         return JITDouble;
     if (arrayProfileSaw(arrayModes, Int32Shape))
index d7a194e..b1c5104 100644 (file)
@@ -914,7 +914,7 @@ void performPlatformSpecificJITAssertions(VM* vm)
 
 NEVER_INLINE static void tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot& slot, StructureStubInfo* stubInfo, bool direct)
 {
-    CodeBlock::Locker locker(codeBlock->m_lock);
+    CodeBlockLocker locker(codeBlock->m_lock);
     
     // The interpreter checks for recursion here; I do not believe this can occur in CTI.
 
@@ -970,7 +970,7 @@ NEVER_INLINE static void tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBl
 
 NEVER_INLINE static void tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo* stubInfo)
 {
-    CodeBlock::Locker locker(codeBlock->m_lock);
+    CodeBlockLocker locker(codeBlock->m_lock);
     
     // FIXME: Write a test that proves we need to check for recursion here just
     // like the interpreter does, then add a check for recursion.
@@ -1712,7 +1712,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail)
 
     CHECK_FOR_EXCEPTION();
 
-    CodeBlock::Locker locker(codeBlock->m_lock);
+    CodeBlockLocker locker(codeBlock->m_lock);
     
     if (baseValue.isCell()
         && slot.isCacheable()
@@ -1834,7 +1834,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list)
         return JSValue::encode(result);
     }
 
-    CodeBlock::Locker locker(codeBlock->m_lock);
+    CodeBlockLocker locker(codeBlock->m_lock);
     
     Structure* structure = baseValue.asCell()->structure();
 
@@ -2299,7 +2299,7 @@ inline void* lazyLinkFor(CallFrame* callFrame, CodeSpecializationKind kind)
             codePtr = functionExecutable->generatedJITCodeFor(kind)->addressForCall();
     }
 
-    CodeBlock::Locker locker(callFrame->callerFrame()->codeBlock()->m_lock);
+    CodeBlockLocker locker(callFrame->callerFrame()->codeBlock()->m_lock);
     if (!callLinkInfo->seenOnce())
         callLinkInfo->setSeen();
     else
@@ -2375,7 +2375,7 @@ DEFINE_STUB_FUNCTION(void*, vm_lazyLinkClosureCall)
     
     if (shouldLink) {
         ASSERT(codePtr);
-        CodeBlock::Locker locker(callerCodeBlock->m_lock);
+        CodeBlockLocker locker(callerCodeBlock->m_lock);
         JIT::compileClosureCall(vm, callLinkInfo, callerCodeBlock, calleeCodeBlock, structure, executable, codePtr);
         callLinkInfo->hasSeenClosure = true;
     } else
@@ -2523,7 +2523,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve)
     JSValue result = JSScope::resolve(callFrame, stackFrame.args[0].identifier(), operations);
     
     if (willReify) {
-        CodeBlock::Locker locker(callFrame->codeBlock()->m_lock);
+        CodeBlockLocker locker(callFrame->codeBlock()->m_lock);
         operations->m_ready = true;
     }
     
@@ -2543,7 +2543,7 @@ DEFINE_STUB_FUNCTION(void, op_put_to_base)
     JSScope::resolvePut(callFrame, base, stackFrame.args[1].identifier(), value, operation);
     
     if (firstTime) {
-        CodeBlock::Locker locker(callFrame->codeBlock()->m_lock);
+        CodeBlockLocker locker(callFrame->codeBlock()->m_lock);
         operation->m_ready = true;
     }
 
@@ -2881,7 +2881,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base)
     JSValue result = JSScope::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), false, operations, stackFrame.args[2].putToBaseOperation());
     
     if (willReify) {
-        CodeBlock::Locker locker(stackFrame.callFrame->codeBlock()->m_lock);
+        CodeBlockLocker locker(stackFrame.callFrame->codeBlock()->m_lock);
         operations->m_ready = true;
     }
     
@@ -2898,7 +2898,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base_strict_put)
     if (JSValue result = JSScope::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), true, operations, stackFrame.args[2].putToBaseOperation())) {
         
         if (willReify) {
-            CodeBlock::Locker locker(stackFrame.callFrame->codeBlock()->m_lock);
+            CodeBlockLocker locker(stackFrame.callFrame->codeBlock()->m_lock);
             operations->m_ready = true;
         }
         
@@ -3175,7 +3175,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_base)
     bool willReify = operations->isEmpty();
     JSValue result = JSScope::resolveWithBase(callFrame, stackFrame.args[0].identifier(), &callFrame->registers()[stackFrame.args[1].int32()], operations, stackFrame.args[3].putToBaseOperation());
     if (willReify) {
-        CodeBlock::Locker locker(stackFrame.callFrame->codeBlock()->m_lock);
+        CodeBlockLocker locker(stackFrame.callFrame->codeBlock()->m_lock);
         operations->m_ready = true;
     }
     CHECK_FOR_EXCEPTION_AT_END();
@@ -3191,7 +3191,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_this)
     bool willReify = operations->isEmpty();
     JSValue result = JSScope::resolveWithThis(callFrame, stackFrame.args[0].identifier(), &callFrame->registers()[stackFrame.args[1].int32()], operations);
     if (willReify) {
-        CodeBlock::Locker locker(stackFrame.callFrame->codeBlock()->m_lock);
+        CodeBlockLocker locker(stackFrame.callFrame->codeBlock()->m_lock);
         operations->m_ready = true;
     }
     CHECK_FOR_EXCEPTION_AT_END();
index 764f5fc..1fa47e5 100644 (file)
@@ -802,7 +802,7 @@ LLINT_SLOW_PATH_DECL(slow_path_resolve)
     }
     
     {
-        CodeBlock::Locker locker(exec->codeBlock()->m_lock);
+        CodeBlockLocker locker(exec->codeBlock()->m_lock);
         operations->m_ready = true;
     }
     
@@ -824,7 +824,7 @@ LLINT_SLOW_PATH_DECL(slow_path_put_to_base)
     }
 
     {
-        CodeBlock::Locker locker(exec->codeBlock()->m_lock);
+        CodeBlockLocker locker(exec->codeBlock()->m_lock);
         operation->m_ready = true;
     }
     
@@ -868,7 +868,7 @@ LLINT_SLOW_PATH_DECL(slow_path_resolve_base)
     }
     
     {
-        CodeBlock::Locker locker(exec->codeBlock()->m_lock);
+        CodeBlockLocker locker(exec->codeBlock()->m_lock);
         operations->m_ready = true;
     }
     
@@ -883,7 +883,7 @@ LLINT_SLOW_PATH_DECL(slow_path_resolve_with_base)
     bool willReify = operations->isEmpty();
     JSValue result = JSScope::resolveWithBase(exec, exec->codeBlock()->identifier(pc[3].u.operand), &LLINT_OP(1), operations, pc[5].u.putToBaseOperation);
     if (willReify) {
-        CodeBlock::Locker locker(exec->codeBlock()->m_lock);
+        CodeBlockLocker locker(exec->codeBlock()->m_lock);
         operations->m_ready = true;
     }
     LLINT_CHECK_EXCEPTION();
@@ -899,7 +899,7 @@ LLINT_SLOW_PATH_DECL(slow_path_resolve_with_this)
     bool willReify = operations->isEmpty();
     JSValue result = JSScope::resolveWithThis(exec, exec->codeBlock()->identifier(pc[3].u.operand), &LLINT_OP(1), operations);
     if (willReify) {
-        CodeBlock::Locker locker(exec->codeBlock()->m_lock);
+        CodeBlockLocker locker(exec->codeBlock()->m_lock);
         operations->m_ready = true;
     }
     LLINT_CHECK_EXCEPTION();
@@ -939,7 +939,7 @@ LLINT_SLOW_PATH_DECL(slow_path_get_by_id)
         
         if (!structure->isUncacheableDictionary()
             && !structure->typeInfo().prohibitsPropertyCaching()) {
-            CodeBlock::Locker locker(codeBlock->m_lock);
+            CodeBlockLocker locker(codeBlock->m_lock);
             
             pc[4].u.structure.set(
                 vm, codeBlock->ownerExecutable(), structure);
@@ -1006,7 +1006,7 @@ LLINT_SLOW_PATH_DECL(slow_path_put_by_id)
             && baseCell == slot.base()) {
             
             if (slot.type() == PutPropertySlot::NewProperty) {
-                CodeBlock::Locker locker(codeBlock->m_lock);
+                CodeBlockLocker locker(codeBlock->m_lock);
             
                 if (!structure->isDictionary() && structure->previousID()->outOfLineCapacity() == structure->outOfLineCapacity()) {
                     ASSERT(structure->previousID()->transitionWatchpointSetHasBeenInvalidated());
@@ -1435,7 +1435,7 @@ inline SlowPathReturnType setUpCall(ExecState* execCallee, Instruction* pc, Code
     if (!LLINT_ALWAYS_ACCESS_SLOW && callLinkInfo) {
         ExecState* execCaller = execCallee->callerFrame();
 
-        CodeBlock::Locker locker(execCaller->codeBlock()->m_lock);
+        CodeBlockLocker locker(execCaller->codeBlock()->m_lock);
         
         if (callLinkInfo->isOnList())
             callLinkInfo->remove();
index a98b8ba..45f0213 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -40,7 +40,8 @@ BytecodeSequence::BytecodeSequence(CodeBlock* codeBlock)
     
 #if ENABLE(VALUE_PROFILER)
     for (unsigned i = 0; i < codeBlock->numberOfArgumentValueProfiles(); ++i) {
-        CString description = codeBlock->valueProfileForArgument(i)->briefDescription();
+        CodeBlockLocker locker(codeBlock->m_lock);
+        CString description = codeBlock->valueProfileForArgument(i)->briefDescription(locker);
         if (!description.length())
             continue;
         out.reset();
index eb008fe..ebdfe74 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -301,7 +301,7 @@ template <JSScope::LookupMode mode, JSScope::ReturnValues returnValues> JSObject
                             operations->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope());
 
                         if (putToBaseOperation) {
-                            CodeBlock::Locker locker(callFrame->codeBlock()->m_lock);
+                            CodeBlockLocker locker(callFrame->codeBlock()->m_lock);
                             
                             putToBaseOperation->m_isDynamic = requiresDynamicChecks;
                             putToBaseOperation->m_kind = PutToBaseOperation::GlobalPropertyPut;
@@ -347,7 +347,7 @@ template <JSScope::LookupMode mode, JSScope::ReturnValues returnValues> JSObject
                         goto fail;
 
                     if (putToBaseOperation) {
-                        CodeBlock::Locker locker(callFrame->codeBlock()->m_lock);
+                        CodeBlockLocker locker(callFrame->codeBlock()->m_lock);
                         
                         putToBaseOperation->m_kind = entry.isReadOnly() ? PutToBaseOperation::Readonly : PutToBaseOperation::VariablePut;
                         putToBaseOperation->m_structure.set(callFrame->vm(), callFrame->codeBlock()->ownerExecutable(), callFrame->lexicalGlobalObject()->activationStructure());
@@ -611,7 +611,7 @@ void JSScope::resolvePut(CallFrame* callFrame, JSValue base, const Identifier& p
     if (slot.base() != baseObject)
         return;
     ASSERT(!baseObject->hasInlineStorage());
-    CodeBlock::Locker locker(callFrame->codeBlock()->m_lock);
+    CodeBlockLocker locker(callFrame->codeBlock()->m_lock);
     
     operation->m_structure.set(callFrame->vm(), callFrame->codeBlock()->ownerExecutable(), baseObject->structure());
     setPutPropertyAccessOffset(operation, slot.cachedOffset());
index 4f69cc7..5c464e8 100644 (file)
@@ -1,3 +1,28 @@
+2013-07-16  Oliver Hunt <oliver@apple.com>
+
+        Merge dfgFourthTier r148804
+
+    2013-04-20  Filip Pizlo  <fpizlo@apple.com>
+
+        fourthTier: value profiles and array profiles should be thread-safe enough to be accessible in a concurrent compilation thread
+        https://bugs.webkit.org/show_bug.cgi?id=114906
+
+        Reviewed by Oliver Hunt.
+        
+        Add ability to abstract whether or not the CodeBlock requires locking at all,
+        since some platforms may not support the byte spin-locking and/or may not want
+        to, if they turn off concurrent JIT.
+
+        * WTF.xcodeproj/project.pbxproj:
+        * wtf/ByteSpinLock.h:
+        * wtf/NoLock.h: Added.
+        (WTF):
+        (NoLock):
+        (WTF::NoLock::lock):
+        (WTF::NoLock::unlock):
+        (WTF::NoLock::isHeld):
+        * wtf/Platform.h:
+
 2013-04-17  Filip Pizlo  <fpizlo@apple.com>
 
         fourthTier: all inline caches should thread-safe enough to allow a concurrent compilation thread to read them safely
index b0d7414..a45ae36 100644 (file)
@@ -21,6 +21,7 @@
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
+               0F0D85B417234CC100338210 /* NoLock.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0D85B317234CB100338210 /* NoLock.h */; };
                0F87105A16643F190090B0AD /* RawPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F87105916643F190090B0AD /* RawPointer.h */; };
                0F9D3360165DBA73005AD387 /* FilePrintStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F9D335B165DBA73005AD387 /* FilePrintStream.cpp */; };
                0F9D3361165DBA73005AD387 /* FilePrintStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F9D335C165DBA73005AD387 /* FilePrintStream.h */; };
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
+               0F0D85B317234CB100338210 /* NoLock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NoLock.h; sourceTree = "<group>"; };
                0F87105916643F190090B0AD /* RawPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RawPointer.h; sourceTree = "<group>"; };
                0F9D335B165DBA73005AD387 /* FilePrintStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FilePrintStream.cpp; sourceTree = "<group>"; };
                0F9D335C165DBA73005AD387 /* FilePrintStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FilePrintStream.h; sourceTree = "<group>"; };
                                A8A472CE151A825B004123FF /* MetaAllocator.h */,
                                A8A472CF151A825B004123FF /* MetaAllocatorHandle.h */,
                                1A3F6BE6174ADA2100B2EEA7 /* NeverDestroyed.h */,
+                               0F0D85B317234CB100338210 /* NoLock.h */,
                                A8A472D0151A825B004123FF /* Noncopyable.h */,
                                A8A472D1151A825B004123FF /* NonCopyingSort.h */,
                                A8A472D2151A825B004123FF /* NotFound.h */,
                                A8A473E8151A825B004123FF /* MathExtras.h in Headers */,
                                A8A473EA151A825B004123FF /* MD5.h in Headers */,
                                CD5497AD15857D0300B5BC30 /* MediaTime.h in Headers */,
+                               0F0D85B417234CC100338210 /* NoLock.h in Headers */,
                                A8A473EB151A825B004123FF /* MessageQueue.h in Headers */,
                                A8A473ED151A825B004123FF /* MetaAllocator.h in Headers */,
                                A8A473EE151A825B004123FF /* MetaAllocatorHandle.h in Headers */,
index 9a397cd..2b588d6 100644 (file)
@@ -29,6 +29,7 @@
 #include <wtf/Assertions.h>
 #include <wtf/Atomics.h>
 #include <wtf/Locker.h>
+#include <wtf/ThreadingPrimitives.h>
 
 namespace WTF {
 
diff --git a/Source/WTF/wtf/NoLock.h b/Source/WTF/wtf/NoLock.h
new file mode 100644 (file)
index 0000000..6432864
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 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 NoLock_h
+#define NoLock_h
+
+#include <wtf/Locker.h>
+
+namespace WTF {
+
+class NoLock {
+public:
+    void lock() { }
+    void unlock() { }
+    bool isHeld() { return false; }
+};
+
+typedef Locker<NoLock> NoLockLocker;
+
+} // namespace WTF
+
+using WTF::NoLock;
+using WTF::NoLockLocker;
+
+#endif // NoLock_h
+
index 08493f0..2a5ae2a 100644 (file)
 #endif
 #endif
 
+/* Concurrent JIT only works on 64-bit platforms because it requires that
+   values get stored to atomically. This is trivially true on 64-bit platforms,
+   but not true at all on 32-bit platforms where values are composed of two
+   separate sub-values. */
+#if PLATFORM(MAC) && ENABLE(DFG_JIT) && USE(JSVALUE64)
+#define ENABLE_CONCURRENT_JIT 1
+#endif
+
 /* If the jit is not available, enable the LLInt C Loop: */
 #if !ENABLE(JIT)
 #undef ENABLE_LLINT        /* Undef so that we can redefine it. */