Title: [206226] trunk
Revision
206226
Author
fpi...@apple.com
Date
2016-09-21 12:09:24 -0700 (Wed, 21 Sep 2016)

Log Message

Add a Fence opcode to B3
https://bugs.webkit.org/show_bug.cgi?id=162343

Reviewed by Geoffrey Garen.
Source/_javascript_Core:

        
This adds the most basic fence support to B3. Currently, this is optimal on x86 and correct
on ARM. It also happens to be sufficient and optimal for what we'll do in the concurrent GC.
        
The idea of Fence is that it can represent any standalone fence instruction by having two
additional params: a read range and a write range. If the write range is empty, this is
taken to be a store-store fence, which turns into zero code on x86 and a cheaper fence on
ARM.
        
It turns out that this is powerful enough to express store-load and store-store fences. For
load-store and load-load fences, you wouldn't have wanted to use any code on x86 and you
wouldn't have wanted a standalone barrier on ARM. For those cases, you'd want either a
fenced load (load acquire) or a dependency. See bug 162349 and bug 162350, respectively.
        
This isn't yet optimized for store-store fences on ARM because we don't have the
MacroAssembler support. Also, the support for "dmb ish" is not really what we want (it seems
to use a heavier fence). I don't think that this is urgent because of how the concurrent GC
will use this facility. I've left that to bug 162342.

* CMakeLists.txt:
* _javascript_Core.xcodeproj/project.pbxproj:
* assembler/MacroAssemblerCodeRef.cpp:
(JSC::MacroAssemblerCodeRef::tryToDisassemble):
(JSC::MacroAssemblerCodeRef::disassembly):
* assembler/MacroAssemblerCodeRef.h:
(JSC::MacroAssemblerCodeRef::size): Deleted.
(JSC::MacroAssemblerCodeRef::tryToDisassemble): Deleted.
* b3/B3Compilation.h:
(JSC::B3::Compilation::codeRef):
(JSC::B3::Compilation::disassembly):
(JSC::B3::Compilation::code): Deleted.
* b3/B3Effects.h:
* b3/B3FenceValue.cpp: Added.
(JSC::B3::FenceValue::~FenceValue):
(JSC::B3::FenceValue::cloneImpl):
(JSC::B3::FenceValue::FenceValue):
* b3/B3FenceValue.h: Added.
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::lower):
* b3/B3Opcode.cpp:
(WTF::printInternal):
* b3/B3Opcode.h:
* b3/B3Validate.cpp:
* b3/B3Value.cpp:
(JSC::B3::Value::effects):
* b3/air/AirOpcode.opcodes:
* b3/testb3.cpp:
(JSC::B3::checkUsesInstruction):
(JSC::B3::checkDoesNotUseInstruction):
(JSC::B3::testX86MFence):
(JSC::B3::testX86CompilerFence):
(JSC::B3::run):

Websites/webkit.org:


* docs/b3/intermediate-representation.html:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (206225 => 206226)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2016-09-21 19:09:24 UTC (rev 206226)
@@ -125,6 +125,7 @@
     b3/B3DuplicateTails.cpp
     b3/B3Effects.cpp
     b3/B3EliminateCommonSubexpressions.cpp
+    b3/B3FenceValue.cpp
     b3/B3FixSSA.cpp
     b3/B3FoldPathConstants.cpp
     b3/B3FrequencyClass.cpp

Modified: trunk/Source/_javascript_Core/ChangeLog (206225 => 206226)


--- trunk/Source/_javascript_Core/ChangeLog	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-09-21 19:09:24 UTC (rev 206226)
@@ -1,3 +1,62 @@
+2016-09-21  Filip Pizlo  <fpi...@apple.com>
+
+        Add a Fence opcode to B3
+        https://bugs.webkit.org/show_bug.cgi?id=162343
+
+        Reviewed by Geoffrey Garen.
+        
+        This adds the most basic fence support to B3. Currently, this is optimal on x86 and correct
+        on ARM. It also happens to be sufficient and optimal for what we'll do in the concurrent GC.
+        
+        The idea of Fence is that it can represent any standalone fence instruction by having two
+        additional params: a read range and a write range. If the write range is empty, this is
+        taken to be a store-store fence, which turns into zero code on x86 and a cheaper fence on
+        ARM.
+        
+        It turns out that this is powerful enough to express store-load and store-store fences. For
+        load-store and load-load fences, you wouldn't have wanted to use any code on x86 and you
+        wouldn't have wanted a standalone barrier on ARM. For those cases, you'd want either a
+        fenced load (load acquire) or a dependency. See bug 162349 and bug 162350, respectively.
+        
+        This isn't yet optimized for store-store fences on ARM because we don't have the
+        MacroAssembler support. Also, the support for "dmb ish" is not really what we want (it seems
+        to use a heavier fence). I don't think that this is urgent because of how the concurrent GC
+        will use this facility. I've left that to bug 162342.
+
+        * CMakeLists.txt:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * assembler/MacroAssemblerCodeRef.cpp:
+        (JSC::MacroAssemblerCodeRef::tryToDisassemble):
+        (JSC::MacroAssemblerCodeRef::disassembly):
+        * assembler/MacroAssemblerCodeRef.h:
+        (JSC::MacroAssemblerCodeRef::size): Deleted.
+        (JSC::MacroAssemblerCodeRef::tryToDisassemble): Deleted.
+        * b3/B3Compilation.h:
+        (JSC::B3::Compilation::codeRef):
+        (JSC::B3::Compilation::disassembly):
+        (JSC::B3::Compilation::code): Deleted.
+        * b3/B3Effects.h:
+        * b3/B3FenceValue.cpp: Added.
+        (JSC::B3::FenceValue::~FenceValue):
+        (JSC::B3::FenceValue::cloneImpl):
+        (JSC::B3::FenceValue::FenceValue):
+        * b3/B3FenceValue.h: Added.
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::lower):
+        * b3/B3Opcode.cpp:
+        (WTF::printInternal):
+        * b3/B3Opcode.h:
+        * b3/B3Validate.cpp:
+        * b3/B3Value.cpp:
+        (JSC::B3::Value::effects):
+        * b3/air/AirOpcode.opcodes:
+        * b3/testb3.cpp:
+        (JSC::B3::checkUsesInstruction):
+        (JSC::B3::checkDoesNotUseInstruction):
+        (JSC::B3::testX86MFence):
+        (JSC::B3::testX86CompilerFence):
+        (JSC::B3::run):
+
 2016-09-21  Keith Miller  <keith_mil...@apple.com>
 
         Fix build for future versions of Clang.

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (206225 => 206226)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-09-21 19:09:24 UTC (rev 206226)
@@ -452,6 +452,8 @@
 		0F66E16C14DF3F1600B7B2E4 /* DFGEdge.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */; };
 		0F682FB219BCB36400FA3BAD /* DFGSSACalculator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F682FB019BCB36400FA3BAD /* DFGSSACalculator.cpp */; };
 		0F682FB319BCB36400FA3BAD /* DFGSSACalculator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F682FB119BCB36400FA3BAD /* DFGSSACalculator.h */; };
+		0F6971EA1D92F42400BA02A5 /* B3FenceValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6971E91D92F42100BA02A5 /* B3FenceValue.h */; };
+		0F6971EB1D92F42D00BA02A5 /* B3FenceValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6971E81D92F42100BA02A5 /* B3FenceValue.cpp */; };
 		0F69CC88193AC60A0045759E /* DFGFrozenValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F69CC86193AC60A0045759E /* DFGFrozenValue.cpp */; };
 		0F69CC89193AC60A0045759E /* DFGFrozenValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F69CC87193AC60A0045759E /* DFGFrozenValue.h */; };
 		0F6B1CB91861244C00845D97 /* ArityCheckMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6B1CB71861244C00845D97 /* ArityCheckMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -2691,6 +2693,8 @@
 		0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGEdge.h; path = dfg/DFGEdge.h; sourceTree = "<group>"; };
 		0F682FB019BCB36400FA3BAD /* DFGSSACalculator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGSSACalculator.cpp; path = dfg/DFGSSACalculator.cpp; sourceTree = "<group>"; };
 		0F682FB119BCB36400FA3BAD /* DFGSSACalculator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGSSACalculator.h; path = dfg/DFGSSACalculator.h; sourceTree = "<group>"; };
+		0F6971E81D92F42100BA02A5 /* B3FenceValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3FenceValue.cpp; path = b3/B3FenceValue.cpp; sourceTree = "<group>"; };
+		0F6971E91D92F42100BA02A5 /* B3FenceValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3FenceValue.h; path = b3/B3FenceValue.h; sourceTree = "<group>"; };
 		0F69CC86193AC60A0045759E /* DFGFrozenValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGFrozenValue.cpp; path = dfg/DFGFrozenValue.cpp; sourceTree = "<group>"; };
 		0F69CC87193AC60A0045759E /* DFGFrozenValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGFrozenValue.h; path = dfg/DFGFrozenValue.h; sourceTree = "<group>"; };
 		0F6B1CB71861244C00845D97 /* ArityCheckMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArityCheckMode.h; sourceTree = "<group>"; };
@@ -4844,6 +4848,8 @@
 				0FEC85BE1BE167A00080FF74 /* B3Effects.h */,
 				0F725CA31C503DED00AD943A /* B3EliminateCommonSubexpressions.cpp */,
 				0F725CA41C503DED00AD943A /* B3EliminateCommonSubexpressions.h */,
+				0F6971E81D92F42100BA02A5 /* B3FenceValue.cpp */,
+				0F6971E91D92F42100BA02A5 /* B3FenceValue.h */,
 				0F6B8AE01C4EFE1700969052 /* B3FixSSA.cpp */,
 				0F6B8AE11C4EFE1700969052 /* B3FixSSA.h */,
 				0F725CAD1C506D3B00AD943A /* B3FoldPathConstants.cpp */,
@@ -4921,9 +4927,9 @@
 				0FEC84EF1BDACDAC0080FF74 /* B3SwitchValue.cpp */,
 				0FEC84F01BDACDAC0080FF74 /* B3SwitchValue.h */,
 				0F45703E1BE584CA0062A629 /* B3TimingScope.cpp */,
-				0FEC84F21BDACDAC0080FF74 /* B3Type.h */,
 				0F45703F1BE584CA0062A629 /* B3TimingScope.h */,
 				0FEC84F11BDACDAC0080FF74 /* B3Type.cpp */,
+				0FEC84F21BDACDAC0080FF74 /* B3Type.h */,
 				DCFDFBD81D1F5D9800FE3D72 /* B3TypeMap.h */,
 				0FEC84F31BDACDAC0080FF74 /* B3UpsilonValue.cpp */,
 				0FEC84F41BDACDAC0080FF74 /* B3UpsilonValue.h */,
@@ -7826,6 +7832,7 @@
 				A1587D721B4DC14100D69849 /* IntlDateTimeFormatPrototype.h in Headers */,
 				A1587D761B4DC1C600D69849 /* IntlDateTimeFormatPrototype.lut.h in Headers */,
 				A55714BE1CD8049F0004D2C6 /* ConsoleObject.h in Headers */,
+				0F6971EA1D92F42400BA02A5 /* B3FenceValue.h in Headers */,
 				A1D792FD1B43864B004516F5 /* IntlNumberFormat.h in Headers */,
 				A1D792FF1B43864B004516F5 /* IntlNumberFormatConstructor.h in Headers */,
 				A125846E1B45A36000CC7F6C /* IntlNumberFormatConstructor.lut.h in Headers */,
@@ -9478,6 +9485,7 @@
 				0F4680CC14BBB17A00BFE272 /* LowLevelInterpreter.cpp in Sources */,
 				A5AB49DC1BEC8082007020FB /* PerGlobalObjectWrapperWorld.cpp in Sources */,
 				14B723B212D7DA46003BD5ED /* MachineStackMarker.cpp in Sources */,
+				0F6971EB1D92F42D00BA02A5 /* B3FenceValue.cpp in Sources */,
 				FE3A06BD1C11040D00390FDD /* JITLeftShiftGenerator.cpp in Sources */,
 				0FEB3ECF16237F6C00AB67AD /* MacroAssembler.cpp in Sources */,
 				86C568E011A213EE0007F7F0 /* MacroAssemblerARM.cpp in Sources */,

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerCodeRef.cpp (206225 => 206226)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerCodeRef.cpp	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerCodeRef.cpp	2016-09-21 19:09:24 UTC (rev 206226)
@@ -59,6 +59,24 @@
     return createSelfManagedCodeRef(MacroAssemblerCodePtr::createFromExecutableAddress(LLInt::getCodePtr(codeId)));
 }
 
+bool MacroAssemblerCodeRef::tryToDisassemble(PrintStream& out, const char* prefix) const
+{
+    return JSC::tryToDisassemble(m_codePtr, size(), prefix, out);
+}
+
+bool MacroAssemblerCodeRef::tryToDisassemble(const char* prefix) const
+{
+    return tryToDisassemble(WTF::dataFile(), prefix);
+}
+
+CString MacroAssemblerCodeRef::disassembly() const
+{
+    StringPrintStream out;
+    if (!tryToDisassemble(out, ""))
+        return CString();
+    return out.toCString();
+}
+
 void MacroAssemblerCodeRef::dump(PrintStream& out) const
 {
     m_codePtr.dumpWithName("CodeRef", out);

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerCodeRef.h (206225 => 206226)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerCodeRef.h	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerCodeRef.h	2016-09-21 19:09:24 UTC (rev 206226)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2012, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,12 +26,12 @@
 #ifndef MacroAssemblerCodeRef_h
 #define MacroAssemblerCodeRef_h
 
-#include "Disassembler.h"
 #include "ExecutableAllocator.h"
 #include <wtf/DataLog.h>
 #include <wtf/PassRefPtr.h>
 #include <wtf/PrintStream.h>
 #include <wtf/RefPtr.h>
+#include <wtf/text/CString.h>
 
 // ASSERT_VALID_CODE_POINTER checks that ptr is a non-null pointer, and that it is a valid
 // instruction address on the platform (for example, check any alignment requirements).
@@ -391,12 +391,13 @@
             return 0;
         return m_executableMemory->sizeInBytes();
     }
+
+    bool tryToDisassemble(PrintStream& out, const char* prefix = "") const;
     
-    bool tryToDisassemble(const char* prefix) const
-    {
-        return JSC::tryToDisassemble(m_codePtr, size(), prefix, WTF::dataFile());
-    }
+    bool tryToDisassemble(const char* prefix = "") const;
     
+    JS_EXPORT_PRIVATE CString disassembly() const;
+    
     explicit operator bool() const { return !!m_codePtr; }
     
     void dump(PrintStream& out) const;

Modified: trunk/Source/_javascript_Core/b3/B3Compilation.h (206225 => 206226)


--- trunk/Source/_javascript_Core/b3/B3Compilation.h	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Source/_javascript_Core/b3/B3Compilation.h	2016-09-21 19:09:24 UTC (rev 206226)
@@ -63,6 +63,9 @@
     JS_EXPORT_PRIVATE ~Compilation();
 
     MacroAssemblerCodePtr code() const { return m_codeRef.code(); }
+    MacroAssemblerCodeRef codeRef() const { return m_codeRef; }
+    
+    CString disassembly() const { return m_codeRef.disassembly(); }
 
 private:
     MacroAssemblerCodeRef m_codeRef;

Modified: trunk/Source/_javascript_Core/b3/B3Effects.h (206225 => 206226)


--- trunk/Source/_javascript_Core/b3/B3Effects.h	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Source/_javascript_Core/b3/B3Effects.h	2016-09-21 19:09:24 UTC (rev 206226)
@@ -53,9 +53,9 @@
     bool controlDependent { false };
 
     // True if this writes to the local state. Operations that write local state don't write to anything
-    // in "memory" but they have a side-effect anyway. This is for modeling Upsilons and Sets. You can ignore
-    // this if you have your own way of modeling Upsilons and Sets or if you intend to just rebuild them
-    // anyway.
+    // in "memory" but they have a side-effect anyway. This is for modeling Upsilons, Sets, and Fences.
+    // This is a way of saying: even though this operation is not a terminal, does not exit sideways,
+    // and does not write to the heap, you still cannot kill this operation.
     bool writesLocalState { false };
 
     // True if this reads from the local state. This is only used for Phi and Get.

Added: trunk/Source/_javascript_Core/b3/B3FenceValue.cpp (0 => 206226)


--- trunk/Source/_javascript_Core/b3/B3FenceValue.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/b3/B3FenceValue.cpp	2016-09-21 19:09:24 UTC (rev 206226)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 "B3FenceValue.h"
+
+#if ENABLE(B3_JIT)
+
+namespace JSC { namespace B3 {
+
+FenceValue::~FenceValue()
+{
+}
+
+Value* FenceValue::cloneImpl() const
+{
+    return new FenceValue(*this);
+}
+
+FenceValue::FenceValue(Origin origin, HeapRange read, HeapRange write)
+    : Value(CheckedOpcode, Fence, Void, origin)
+    , read(read)
+    , write(write)
+{
+}
+
+FenceValue::FenceValue(Origin origin)
+    : FenceValue(origin, HeapRange::top(), HeapRange::top())
+{
+}
+
+} } // namespace JSC::B3
+
+#endif // ENABLE(B3_JIT)
+

Added: trunk/Source/_javascript_Core/b3/B3FenceValue.h (0 => 206226)


--- trunk/Source/_javascript_Core/b3/B3FenceValue.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/b3/B3FenceValue.h	2016-09-21 19:09:24 UTC (rev 206226)
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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.
+ */
+
+#pragma once
+
+#if ENABLE(B3_JIT)
+
+#include "B3HeapRange.h"
+#include "B3Value.h"
+
+namespace JSC { namespace B3 {
+
+class JS_EXPORT_PRIVATE FenceValue : public Value {
+public:
+    static bool accepts(Opcode opcode) { return opcode == Fence; }
+    
+    ~FenceValue();
+    
+    // The read/write heaps are reflected in the effects() of this value. The compiler may change
+    // the lowering of a Fence based on the heaps. For example, if a fence does not write anything
+    // then it is understood to be a store-store fence. On x86, this may lead us to not emit any
+    // code, while on ARM we may emit a cheaper fence (dmb ishst instead of dmb ish).
+    //
+    // This abstraction allows us to cover all of the fences on x86 and all of the standalone fences
+    // on ARM. X86 really just has one fence: mfence. This fence should be used to protect stores
+    // from being sunk below loads. WTF calls it the storeLoadFence. A classic example is the Steele
+    // barrier:
+    //
+    //     o.f = v  =>  o.f = v
+    //                  if (color(o) == black)
+    //                      log(o)
+    //
+    // We are trying to ensure that if the store to o.f occurs after the collector has started
+    // visiting o, then we will log o. Under sequential consistency, this would work. The collector
+    // would set color(o) to black just before it started visiting. But x86's illusion of sequential
+    // consistency is broken in exactly just this store->load ordering case. The store to o.f may
+    // get buffered, and it may occur some time after we have loaded and checked color(o). As well,
+    // the collector's store to set color(o) to black may get buffered and it may occur some time
+    // after the collector has finished visiting o. Therefore, we need mfences. In B3 we model this
+    // as a Fence that reads and writes some heaps. Setting writes to the empty set will cause B3 to
+    // not emit any barrier on x86.
+    //
+    // On ARM there are many more fences. The Fence instruction is meant to model just two of them:
+    // dmb ish and dmb ishst. You can emit a dmb ishst by using a Fence with an empty write heap.
+    // Otherwise, you will get a dmb ish.
+    // FIXME: Make this work right on ARM. https://bugs.webkit.org/show_bug.cgi?id=162342
+    // FIXME: Add fenced memory accesses. https://bugs.webkit.org/show_bug.cgi?id=162349
+    // FIXME: Add a Depend operation. https://bugs.webkit.org/show_bug.cgi?id=162350
+    HeapRange read { HeapRange::top() };
+    HeapRange write { HeapRange::top() };
+
+protected:
+    Value* cloneImpl() const override;
+
+private:
+    friend class Procedure;
+    
+    JS_EXPORT_PRIVATE FenceValue(Origin origin, HeapRange read, HeapRange write);
+    
+    JS_EXPORT_PRIVATE FenceValue(Origin origin);
+};
+
+} } // namespace JSC::B3
+
+#endif // ENABLE(B3_JIT)
+

Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (206225 => 206226)


--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2016-09-21 19:09:24 UTC (rev 206226)
@@ -40,6 +40,7 @@
 #include "B3CheckSpecial.h"
 #include "B3Commutativity.h"
 #include "B3Dominators.h"
+#include "B3FenceValue.h"
 #include "B3MemoryValue.h"
 #include "B3PatchpointSpecial.h"
 #include "B3PatchpointValue.h"
@@ -2045,6 +2046,16 @@
             m_insts.last().append(createStore(Air::Store16, valueToStore, addr(m_value)));
             return;
         }
+            
+        case Fence: {
+            FenceValue* fence = m_value->as<FenceValue>();
+            if (isX86() && !fence->write)
+                return;
+            // FIXME: Optimize this on ARM.
+            // https://bugs.webkit.org/show_bug.cgi?id=162342
+            append(MemoryFence);
+            return;
+        }
 
         case Trunc: {
             ASSERT(tmp(m_value->child(0)) == tmp(m_value));

Modified: trunk/Source/_javascript_Core/b3/B3MemoryValue.h (206225 => 206226)


--- trunk/Source/_javascript_Core/b3/B3MemoryValue.h	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Source/_javascript_Core/b3/B3MemoryValue.h	2016-09-21 19:09:24 UTC (rev 206226)
@@ -33,6 +33,9 @@
 
 namespace JSC { namespace B3 {
 
+// FIXME: We want to allow fenced memory accesses on ARM.
+// https://bugs.webkit.org/show_bug.cgi?id=162349
+
 class JS_EXPORT_PRIVATE MemoryValue : public Value {
 public:
     static bool accepts(Opcode opcode)

Modified: trunk/Source/_javascript_Core/b3/B3Opcode.cpp (206225 => 206226)


--- trunk/Source/_javascript_Core/b3/B3Opcode.cpp	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Source/_javascript_Core/b3/B3Opcode.cpp	2016-09-21 19:09:24 UTC (rev 206226)
@@ -257,6 +257,9 @@
     case Store:
         out.print("Store");
         return;
+    case Fence:
+        out.print("Fence");
+        return;
     case CCall:
         out.print("CCall");
         return;

Modified: trunk/Source/_javascript_Core/b3/B3Opcode.h (206225 => 206226)


--- trunk/Source/_javascript_Core/b3/B3Opcode.h	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Source/_javascript_Core/b3/B3Opcode.h	2016-09-21 19:09:24 UTC (rev 206226)
@@ -157,6 +157,12 @@
     Store16,
     // This is a polymorphic store for Int32, Int64, Float, and Double.
     Store,
+    
+    // This is used to represent standalone fences - i.e. fences that are not part of other
+    // instructions. It's expressive enough to expose mfence on x86 and dmb ish/ishst on ARM. On
+    // x86, it also acts as a compiler store-store fence in those cases where it would have been a
+    // dmb ishst on ARM.
+    Fence,
 
     // This is a regular ordinary C function call, using the system C calling convention. Make sure
     // that the arguments are passed using the right types. The first argument is the callee.

Modified: trunk/Source/_javascript_Core/b3/B3Validate.cpp (206225 => 206226)


--- trunk/Source/_javascript_Core/b3/B3Validate.cpp	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Source/_javascript_Core/b3/B3Validate.cpp	2016-09-21 19:09:24 UTC (rev 206226)
@@ -130,6 +130,7 @@
                 VALIDATE(child->type() != Void, ("At ", *value, "->", *child));
             switch (value->opcode()) {
             case Nop:
+            case Fence:
                 VALIDATE(!value->numChildren(), ("At ", *value));
                 VALIDATE(value->type() == Void, ("At ", *value));
                 break;

Modified: trunk/Source/_javascript_Core/b3/B3Value.cpp (206225 => 206226)


--- trunk/Source/_javascript_Core/b3/B3Value.cpp	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Source/_javascript_Core/b3/B3Value.cpp	2016-09-21 19:09:24 UTC (rev 206226)
@@ -32,6 +32,7 @@
 #include "B3BasicBlockInlines.h"
 #include "B3BottomProvider.h"
 #include "B3CCallValue.h"
+#include "B3FenceValue.h"
 #include "B3MemoryValue.h"
 #include "B3OriginDump.h"
 #include "B3ProcedureInlines.h"
@@ -585,6 +586,24 @@
         result.writes = as<MemoryValue>()->range();
         result.controlDependent = true;
         break;
+    case Fence: {
+        const FenceValue* fence = as<FenceValue>();
+        result.reads = fence->read;
+        result.writes = fence->write;
+        
+        // Prevent killing of fences that claim not to write anything. It's a bit weird that we use
+        // local state as the way to do this, but it happens to work: we must assume that we cannot
+        // kill writesLocalState unless we understands exactly what the instruction is doing (like
+        // the way that fixSSA understands Set/Get and the way that reduceStrength and others
+        // understand Upsilon). This would only become a problem if we had some analysis that was
+        // looking to use the writesLocalState bit to invalidate a CSE over local state operations.
+        // Then a Fence would look block, say, the elimination of a redundant Get. But it like
+        // that's not at all how our optimizations for Set/Get/Upsilon/Phi work - they grok their
+        // operations deeply enough that they have no need to check this bit - so this cheat is
+        // fine.
+        result.writesLocalState = true;
+        break;
+    }
     case CCall:
         result = as<CCallValue>()->effects;
         break;

Modified: trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes (206225 => 206226)


--- trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2016-09-21 19:09:24 UTC (rev 206226)
@@ -843,6 +843,8 @@
 MoveDoubleConditionallyFloat U:G:32, U:F:32, U:F:32, U:F:64, U:F:64, D:F:64
     DoubleCond, Tmp, Tmp, Tmp, Tmp, Tmp
 
+MemoryFence /effects
+
 Jump /branch
 
 RetVoid /return

Modified: trunk/Source/_javascript_Core/b3/testb3.cpp (206225 => 206226)


--- trunk/Source/_javascript_Core/b3/testb3.cpp	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Source/_javascript_Core/b3/testb3.cpp	2016-09-21 19:09:24 UTC (rev 206226)
@@ -37,6 +37,7 @@
 #include "B3Const32Value.h"
 #include "B3ConstPtrValue.h"
 #include "B3Effects.h"
+#include "B3FenceValue.h"
 #include "B3Generate.h"
 #include "B3LowerToAir.h"
 #include "B3MathExtras.h"
@@ -151,6 +152,30 @@
     Air::validate(proc.code());
 }
 
+void checkUsesInstruction(Compilation& compilation, const char* text)
+{
+    CString disassembly = compilation.disassembly();
+    if (strstr(disassembly.data(), text))
+        return;
+
+    crashLock.lock();
+    dataLog("Bad lowering!  Expected to find ", text, " but didn't:\n");
+    dataLog(disassembly);
+    CRASH();
+}
+
+void checkDoesNotUseInstruction(Compilation& compilation, const char* text)
+{
+    CString disassembly = compilation.disassembly();
+    if (!strstr(disassembly.data(), text))
+        return;
+
+    crashLock.lock();
+    dataLog("Bad lowering!  Did not expected to find ", text, " but it's there:\n");
+    dataLog(disassembly);
+    CRASH();
+}
+
 template<typename Type>
 struct Operand {
     const char* name;
@@ -13027,6 +13052,32 @@
     CHECK_EQ(invoke<int>(*code, -1), 666);
 }
 
+void testX86MFence()
+{
+    Procedure proc;
+    
+    BasicBlock* root = proc.addBlock();
+    
+    root->appendNew<FenceValue>(proc, Origin());
+    root->appendNew<Value>(proc, Return, Origin());
+    
+    auto code = compile(proc);
+    checkUsesInstruction(*code, "mfence");
+}
+
+void testX86CompilerFence()
+{
+    Procedure proc;
+    
+    BasicBlock* root = proc.addBlock();
+    
+    root->appendNew<FenceValue>(proc, Origin(), HeapRange::top(), HeapRange());
+    root->appendNew<Value>(proc, Return, Origin());
+    
+    auto code = compile(proc);
+    checkDoesNotUseInstruction(*code, "mfence");
+}
+
 // Make sure the compiler does not try to optimize anything out.
 NEVER_INLINE double zero()
 {
@@ -14456,6 +14507,9 @@
         RUN(testBranchBitAndImmFusion(Load8Z, Int32, 1, Air::BranchTest8, Air::Arg::Addr));
         RUN(testBranchBitAndImmFusion(Load, Int32, 1, Air::BranchTest32, Air::Arg::Addr));
         RUN(testBranchBitAndImmFusion(Load, Int64, 1, Air::BranchTest32, Air::Arg::Addr));
+        
+        RUN(testX86MFence());
+        RUN(testX86CompilerFence());
     }
 
     if (isARM64()) {

Modified: trunk/Websites/webkit.org/ChangeLog (206225 => 206226)


--- trunk/Websites/webkit.org/ChangeLog	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Websites/webkit.org/ChangeLog	2016-09-21 19:09:24 UTC (rev 206226)
@@ -1,3 +1,12 @@
+2016-09-21  Filip Pizlo  <fpi...@apple.com>
+
+        Add a Fence opcode to B3
+        https://bugs.webkit.org/show_bug.cgi?id=162343
+
+        Reviewed by Geoffrey Garen.
+
+        * docs/b3/intermediate-representation.html:
+
 2016-08-16  Benjamin Poulain  <bpoul...@apple.com>
 
         [JSC] Update the documentation of B3's Return opcode

Modified: trunk/Websites/webkit.org/docs/b3/intermediate-representation.html (206225 => 206226)


--- trunk/Websites/webkit.org/docs/b3/intermediate-representation.html	2016-09-21 18:42:21 UTC (rev 206225)
+++ trunk/Websites/webkit.org/docs/b3/intermediate-representation.html	2016-09-21 19:09:24 UTC (rev 206226)
@@ -421,6 +421,18 @@
       <dd>Stores the value in the first child into the address computed by adding the
         compile-time 32-bit signed integer offset to the second child.  Misaligned stores are
         not penalized.  Must use the MemoryValue class.</dd>
+      
+      <dt>Void Fence()</dt>
+      <dd>Abstracts standalone data fences on x86 and ARM. Must use the FenceValue class, which has
+        two additional members that configure the precise meaning of the fence:
+        <code>HeapRange FenceValue::read</code> and <code>HeapRange FenceValue::write</code>. If the
+        <code>write</code> range is empty, this is taken to be a store-store fence, which leads to
+        no code generation on x86 and the weaker <code>dmb ishst</code> fence on ARM. If the write
+        range is non-empty, this produces <code>mfence</code> on x86 and <code>dmb ish</code> on
+        ARM. Within B3 IR, the Fence also reports the read/write in its effects. This allows you to
+        scope the fence for the purpose of B3's load elimination. For example, you may use a Fence
+        to protect a store from being sunk below a specific load. In that case, you can claim to
+        read just that store's range and write that load's range.</dd>
 
       <dt>T1 CCall(IntPtr, [T2, [T3, ...]])</dt>
       <dd>Performs a C function call to the function pointed to by the first child.  The types
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to