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