Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (202501 => 202502)
--- trunk/Source/_javascript_Core/ChangeLog 2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-06-27 18:35:09 UTC (rev 202502)
@@ -1,3 +1,104 @@
+2016-06-25 Filip Pizlo <[email protected]>
+
+ B3 should not use Nops when deleting unreachable code
+ https://bugs.webkit.org/show_bug.cgi?id=159120
+ rdar://problem/26500743
+
+ Reviewed by Michael Saboff.
+
+ Prior to this change, transformations that obviated the need for some value could choose
+ from these ways to kill it:
+
+ - replaceWithIdentity() if we're replacing with another value.
+ - replaceWithNop() if the type is Void or if we know that we'll fix any users of this
+ value.
+ - deleteValue() if the code is unreachable.
+
+ The bug here is that reduceStrength() was being clever about how to get rid of a value.
+ reduceStrength() may find a Check that must always exit. The goal is to remove any code
+ dominated by the Check. But it would be awkward to eagerly delete all of the blocks
+ dominated by this one. So this code took a much simpler approach: it would
+ replaceWithNop() for all of the values in this block after the Check and it would replace
+ the terminal with Oops.
+
+ But this corrupts the IR in a subtle way: some of those values may have been non-Void but
+ now they are Nops so they are Void. reduceStrength() will not yet realize that the blocks
+ dominated by the one with the Check are unreachable, so it will run all sorts of
+ optimizations on those blocks. This could have probably manifested as many different kinds
+ of badness, but the way I found out about this issue was through a crash in
+ IntRange::top(Type) when inlined into ReduceStrength::rangeFor(). We'd die in a switch
+ statement over a child's type.
+
+ We could fix this by making rangeFor() tolerate Void. But I think that this would be
+ dangerous. There could easily be other places in reduceStrength() that assume that value's
+ children are non-Void. So, this change fixes the Check optimization and adds mechanisms to
+ prevent other optimizations from breaking the children-are-not-Void rule.
+
+ This introduces two high-level changes:
+
+ - It's no longer legal to replaceWithNop() if the value is not Void. This change alone
+ would cause reduceStrength() to instacrash in its Check optimization. Almost all other
+ uses of replaceWithNop() were already following this rule, so they were fine. One other
+ place was using replaceWithNop() on non-Void values after arranging for them to no
+ longer have any parents. That was changed to call replaceWithNopIgnoringType(), which
+ doesn't have any type assertions.
+
+ - For reduceStrength() there is a new Value::replaceWithBottom() method that works with
+ Void or non-Void and behaves like you would want replaceWithNop() to behave: if you know
+ that the code is unreachable then it produces something that is guaranteed to be deleted
+ by later optimizations, and if it's not unreachable, then it's guaranteed to be compiled
+ to something harmless and cheap. This means replacing the value with an identity that
+ points to a bottom constant (the 0 for whatever type we have), or just replacing it with
+ Nop if it's Void.
+
+ This also adds a test case for the reason why we do this: we may have two blocks, where
+ the first block unconditionally exits while dominating the second block. The second block
+ references values in the part of the first block that is unreachable. In trunk, this test
+ would assert in ReduceStrength::rangeFor() because the CheckAdd in the second block would
+ reference a Nop in the first block.
+
+ This fixes a high volume crash in ReduceStrength::rangeFor(). This crash was very
+ confusing. Even though we were crashing at a RELEASE_ASSERT_NOT_REACHED() in a switch
+ statement in IntRange::top(Type), clang was merging that trap with the trap it used for
+ Vector OOB. The top of the stack in crash dumps looked like:
+
+ JSC::B3::(anonymous namespace)::ReduceStrength::rangeFor(JSC::B3::Value*, unsigned int) + 4477 (Vector.h:655)
+
+ Where Vector.h:655 is:
+
+ OverflowHandler::overflowed();
+
+ But this crash was not at Vector.h:655. It was at B3ReduceStrength.cpp:121. The two lines
+ are both traps, so they got merged despite differences in debug info. This bug would have
+ been so much easier to fix if I had the right line number.
+
+ * b3/B3BottomProvider.h: Added. This is a utility for creating bottom values.
+ (JSC::B3::BottomProvider::BottomProvider):
+ (JSC::B3::BottomProvider::operator()):
+ * b3/B3InsertionSet.cpp: Optimized adding bottom values a bit. We will no longer create pointless duplicates.
+ (JSC::B3::InsertionSet::insertBottom):
+ (JSC::B3::InsertionSet::execute):
+ (JSC::B3::InsertionSet::bottomForType):
+ * b3/B3InsertionSet.h:
+ * b3/B3MoveConstants.cpp: Use replaceWithNopIgnoringType() because we *know* that we can replaceWithNop even for non-Void.
+ * b3/B3Procedure.h:
+ * b3/B3ReduceStrength.cpp: Use replaceWithBottom().
+ * b3/B3ReduceStrength.h:
+ * b3/B3TypeMap.h: I figured if I wrote type-casing code like this once then I'd never want to write it again.
+ * b3/B3Value.cpp:
+ (JSC::B3::Value::replaceWithIdentity):
+ (JSC::B3::Value::replaceWithNop):
+ (JSC::B3::Value::replaceWithNopIgnoringType):
+ * b3/B3Value.h:
+ * b3/B3ValueInlines.h:
+ (JSC::B3::Value::replaceWithBottom): This is the new method of killing unreachable code.
+ (JSC::B3::Value::as):
+ * b3/testb3.cpp: Add new tests!
+ (JSC::B3::testLateRegister):
+ (JSC::B3::testReduceStrengthCheckBottomUseInAnotherBlock):
+ (JSC::B3::zero):
+ (JSC::B3::run):
+
2016-06-27 Joseph Pecoraro <[email protected]>
REGRESSION: Web Inspector: Text search broken in resources with <CR>
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (202501 => 202502)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2016-06-27 18:35:09 UTC (rev 202502)
@@ -2004,6 +2004,8 @@
DCF3D56B1CD29472003D5C65 /* LazyClassStructureInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = DCF3D5661CD29468003D5C65 /* LazyClassStructureInlines.h */; };
DCF3D56C1CD29475003D5C65 /* LazyProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = DCF3D5671CD29468003D5C65 /* LazyProperty.h */; settings = {ATTRIBUTES = (Private, ); }; };
DCF3D56D1CD29476003D5C65 /* LazyPropertyInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = DCF3D5681CD29468003D5C65 /* LazyPropertyInlines.h */; };
+ DCFDFBD91D1F5D9B00FE3D72 /* B3BottomProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFDFBD71D1F5D9800FE3D72 /* B3BottomProvider.h */; };
+ DCFDFBDA1D1F5D9E00FE3D72 /* B3TypeMap.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFDFBD81D1F5D9800FE3D72 /* B3TypeMap.h */; };
DE26E9031CB5DD0500D2BE82 /* BuiltinExecutableCreator.h in Headers */ = {isa = PBXBuildFile; fileRef = DE26E9021CB5DD0500D2BE82 /* BuiltinExecutableCreator.h */; };
DE26E9071CB5DEFB00D2BE82 /* BuiltinExecutableCreator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE26E9061CB5DD9600D2BE82 /* BuiltinExecutableCreator.cpp */; };
DE5A0A001BA3AC3E003D4424 /* IntrinsicEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE5A09FF1BA3AC3E003D4424 /* IntrinsicEmitter.cpp */; };
@@ -4223,6 +4225,8 @@
DCF3D5661CD29468003D5C65 /* LazyClassStructureInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LazyClassStructureInlines.h; sourceTree = "<group>"; };
DCF3D5671CD29468003D5C65 /* LazyProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LazyProperty.h; sourceTree = "<group>"; };
DCF3D5681CD29468003D5C65 /* LazyPropertyInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LazyPropertyInlines.h; sourceTree = "<group>"; };
+ DCFDFBD71D1F5D9800FE3D72 /* B3BottomProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3BottomProvider.h; path = b3/B3BottomProvider.h; sourceTree = "<group>"; };
+ DCFDFBD81D1F5D9800FE3D72 /* B3TypeMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3TypeMap.h; path = b3/B3TypeMap.h; sourceTree = "<group>"; };
DE26E9021CB5DD0500D2BE82 /* BuiltinExecutableCreator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BuiltinExecutableCreator.h; sourceTree = "<group>"; };
DE26E9061CB5DD9600D2BE82 /* BuiltinExecutableCreator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BuiltinExecutableCreator.cpp; sourceTree = "<group>"; };
DE5A09FF1BA3AC3E003D4424 /* IntrinsicEmitter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntrinsicEmitter.cpp; sourceTree = "<group>"; };
@@ -4671,6 +4675,7 @@
0F338E171BF286EA0013C88F /* B3BlockInsertionSet.cpp */,
0F338E181BF286EA0013C88F /* B3BlockInsertionSet.h */,
0FEC84BA1BDACDAC0080FF74 /* B3BlockWorklist.h */,
+ DCFDFBD71D1F5D9800FE3D72 /* B3BottomProvider.h */,
0F6B8ADE1C4EFE1700969052 /* B3BreakCriticalEdges.cpp */,
0F6B8ADF1C4EFE1700969052 /* B3BreakCriticalEdges.h */,
0F338DF71BE96AA80013C88F /* B3CCallValue.cpp */,
@@ -4789,6 +4794,7 @@
0F45703F1BE584CA0062A629 /* B3TimingScope.h */,
0FEC84F11BDACDAC0080FF74 /* B3Type.cpp */,
0FEC84F21BDACDAC0080FF74 /* B3Type.h */,
+ DCFDFBD81D1F5D9800FE3D72 /* B3TypeMap.h */,
0FEC84F31BDACDAC0080FF74 /* B3UpsilonValue.cpp */,
0FEC84F41BDACDAC0080FF74 /* B3UpsilonValue.h */,
0FEC84F51BDACDAC0080FF74 /* B3UseCounts.cpp */,
@@ -7104,6 +7110,7 @@
99DA00A51BD5993100F4575C /* builtins_templates.py in Headers */,
41DEA1321B9F3163006D65DD /* BuiltinUtils.h in Headers */,
9E72940B190F0514001A91B5 /* BundlePath.h in Headers */,
+ DCFDFBD91D1F5D9B00FE3D72 /* B3BottomProvider.h in Headers */,
0FB7F39715ED8E4600F167B2 /* Butterfly.h in Headers */,
0FB7F39815ED8E4600F167B2 /* ButterflyInlines.h in Headers */,
C2FCAE1117A9C24E0034C735 /* BytecodeBasicBlock.h in Headers */,
@@ -7390,6 +7397,7 @@
0F63943F15C75F19006A597C /* DFGTypeCheckHoistingPhase.h in Headers */,
0FBE0F7716C1DB120082C5E8 /* DFGUnificationPhase.h in Headers */,
0F34B14A16D42013001CDA5A /* DFGUseKind.h in Headers */,
+ DCFDFBDA1D1F5D9E00FE3D72 /* B3TypeMap.h in Headers */,
0F3B3A2C15475002003ED0FF /* DFGValidate.h in Headers */,
0F2BDC481522802900CD8910 /* DFGValueSource.h in Headers */,
0F0123331944EA1B00843A0C /* DFGValueStrength.h in Headers */,
Added: trunk/Source/_javascript_Core/b3/B3BottomProvider.h (0 => 202502)
--- trunk/Source/_javascript_Core/b3/B3BottomProvider.h (rev 0)
+++ trunk/Source/_javascript_Core/b3/B3BottomProvider.h 2016-06-27 18:35:09 UTC (rev 202502)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef B3BottomProvider_h
+#define B3BottomProvider_h
+
+#if ENABLE(B3_JIT)
+
+#include "B3InsertionSet.h"
+
+namespace JSC { namespace B3 {
+
+// This exists because we cannot convert values to constants in-place.
+// FIXME: https://bugs.webkit.org/show_bug.cgi?id=159119
+
+class BottomProvider {
+public:
+ BottomProvider(InsertionSet& insertionSet, size_t index)
+ : m_insertionSet(&insertionSet)
+ , m_index(index)
+ {
+ }
+
+ Value* operator()(Origin origin, Type type) const
+ {
+ return m_insertionSet->insertBottom(m_index, origin, type);
+ }
+
+private:
+ InsertionSet* m_insertionSet;
+ size_t m_index;
+};
+
+} } // namespace JSC::B3
+
+#endif // ENABLE(B3_JIT)
+
+#endif // B3BottomProvider_h
+
Modified: trunk/Source/_javascript_Core/b3/B3InsertionSet.cpp (202501 => 202502)
--- trunk/Source/_javascript_Core/b3/B3InsertionSet.cpp 2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/_javascript_Core/b3/B3InsertionSet.cpp 2016-06-27 18:35:09 UTC (rev 202502)
@@ -47,7 +47,10 @@
Value* InsertionSet::insertBottom(size_t index, Origin origin, Type type)
{
- return insertValue(index, m_procedure.addBottom(origin, type));
+ Value*& bottom = m_bottomForType[type];
+ if (!bottom)
+ bottom = insertValue(index, m_procedure.addBottom(origin, type));
+ return bottom;
}
Value* InsertionSet::insertBottom(size_t index, Value* likeValue)
@@ -59,6 +62,7 @@
{
bubbleSort(m_insertions.begin(), m_insertions.end());
executeInsertions(block->m_values, m_insertions);
+ m_bottomForType = TypeMap<Value*>();
}
} } // namespace JSC::B3
Modified: trunk/Source/_javascript_Core/b3/B3InsertionSet.h (202501 => 202502)
--- trunk/Source/_javascript_Core/b3/B3InsertionSet.h 2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/_javascript_Core/b3/B3InsertionSet.h 2016-06-27 18:35:09 UTC (rev 202502)
@@ -30,6 +30,7 @@
#include "B3Origin.h"
#include "B3Type.h"
+#include "B3TypeMap.h"
#include <wtf/Insertion.h>
#include <wtf/Vector.h>
@@ -77,6 +78,8 @@
private:
Procedure& m_procedure;
Vector<Insertion, 8> m_insertions;
+
+ TypeMap<Value*> m_bottomForType;
};
} } // namespace JSC::B3
Modified: trunk/Source/_javascript_Core/b3/B3MoveConstants.cpp (202501 => 202502)
--- trunk/Source/_javascript_Core/b3/B3MoveConstants.cpp 2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/_javascript_Core/b3/B3MoveConstants.cpp 2016-06-27 18:35:09 UTC (rev 202502)
@@ -125,7 +125,7 @@
if (valueForConstant.get(key) == value)
value = m_proc.add<Value>(Nop, value->origin());
else
- value->replaceWithNop();
+ value->replaceWithNopIgnoringType();
}
}
Modified: trunk/Source/_javascript_Core/b3/B3Procedure.h (202501 => 202502)
--- trunk/Source/_javascript_Core/b3/B3Procedure.h 2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/_javascript_Core/b3/B3Procedure.h 2016-06-27 18:35:09 UTC (rev 202502)
@@ -113,7 +113,7 @@
Value* addBoolConstant(Origin, TriState);
void resetValueOwners();
- void resetReachability();
+ JS_EXPORT_PRIVATE void resetReachability();
// This destroys CFG analyses. If we ask for them again, we will recompute them. Usually you
// should call this anytime you call resetReachability().
Modified: trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp (202501 => 202502)
--- trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp 2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp 2016-06-27 18:35:09 UTC (rev 202502)
@@ -1716,7 +1716,7 @@
// Replace the rest of the block with an Oops.
for (unsigned i = m_index + 1; i < m_block->size() - 1; ++i)
- m_block->at(i)->replaceWithNop();
+ m_block->at(i)->replaceWithBottom(m_insertionSet, m_index);
m_block->last()->as<ControlValue>()->convertToOops();
m_block->last()->setOrigin(checkValue->origin());
Modified: trunk/Source/_javascript_Core/b3/B3ReduceStrength.h (202501 => 202502)
--- trunk/Source/_javascript_Core/b3/B3ReduceStrength.h 2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/_javascript_Core/b3/B3ReduceStrength.h 2016-06-27 18:35:09 UTC (rev 202502)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-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
@@ -40,7 +40,7 @@
// add sophisticated optimizations to it. For that reason we have full CSE in a different phase, for
// example.
-bool reduceStrength(Procedure&);
+JS_EXPORT_PRIVATE bool reduceStrength(Procedure&);
} } // namespace JSC::B3
Added: trunk/Source/_javascript_Core/b3/B3TypeMap.h (0 => 202502)
--- trunk/Source/_javascript_Core/b3/B3TypeMap.h (rev 0)
+++ trunk/Source/_javascript_Core/b3/B3TypeMap.h 2016-06-27 18:35:09 UTC (rev 202502)
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef B3TypeMap_h
+#define B3TypeMap_h
+
+#if ENABLE(B3_JIT)
+
+#include "B3Type.h"
+#include <wtf/PrintStream.h>
+
+namespace JSC { namespace B3 {
+
+template<typename T>
+class TypeMap {
+public:
+ TypeMap()
+ : m_void()
+ , m_int32()
+ , m_int64()
+ , m_float()
+ , m_double()
+ {
+ }
+
+ T& at(Type type)
+ {
+ switch (type) {
+ case Void:
+ return m_void;
+ case Int32:
+ return m_int32;
+ case Int64:
+ return m_int64;
+ case Float:
+ return m_float;
+ case Double:
+ return m_double;
+ }
+ }
+
+ const T& at(Type type) const
+ {
+ return bitwise_cast<TypeMap*>(this)->at(type);
+ }
+
+ T& operator[](Type type)
+ {
+ return at(type);
+ }
+
+ const T& operator[](Type type) const
+ {
+ return at(type);
+ }
+
+ void dump(PrintStream& out) const
+ {
+ out.print(
+ "{void = ", m_void,
+ ", int32 = ", m_int32,
+ ", int64 = ", m_int64,
+ ", float = ", m_float,
+ ", double = ", m_double, "}");
+ }
+
+private:
+ T m_void;
+ T m_int32;
+ T m_int64;
+ T m_float;
+ T m_double;
+};
+
+} } // namespace JSC::B3
+
+#endif // ENABLE(B3_JIT)
+
+#endif // B3TypeMap_h
+
Modified: trunk/Source/_javascript_Core/b3/B3Value.cpp (202501 => 202502)
--- trunk/Source/_javascript_Core/b3/B3Value.cpp 2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/_javascript_Core/b3/B3Value.cpp 2016-06-27 18:35:09 UTC (rev 202502)
@@ -29,6 +29,7 @@
#if ENABLE(B3_JIT)
#include "B3ArgumentRegValue.h"
+#include "B3BottomProvider.h"
#include "B3CCallValue.h"
#include "B3ControlValue.h"
#include "B3MemoryValue.h"
@@ -60,7 +61,7 @@
ASSERT(m_type == value->m_type);
if (m_type == Void) {
- replaceWithNop();
+ replaceWithNopIgnoringType();
return;
}
@@ -79,8 +80,19 @@
this->m_index = index;
}
+void Value::replaceWithBottom(InsertionSet& insertionSet, size_t index)
+{
+ replaceWithBottom(BottomProvider(insertionSet, index));
+}
+
void Value::replaceWithNop()
{
+ RELEASE_ASSERT(m_type == Void);
+ replaceWithNopIgnoringType();
+}
+
+void Value::replaceWithNopIgnoringType()
+{
unsigned index = m_index;
Origin origin = m_origin;
BasicBlock* owner = this->owner;
Modified: trunk/Source/_javascript_Core/b3/B3Value.h (202501 => 202502)
--- trunk/Source/_javascript_Core/b3/B3Value.h 2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/_javascript_Core/b3/B3Value.h 2016-06-27 18:35:09 UTC (rev 202502)
@@ -43,6 +43,7 @@
class BasicBlock;
class CheckValue;
+class InsertionSet;
class PhiChildren;
class Procedure;
@@ -83,8 +84,30 @@
AdjacencyList& children() { return m_children; }
const AdjacencyList& children() const { return m_children; }
+ // If you want to replace all uses of this value with a different value, then replace this
+ // value with Identity. Then do a pass of performSubstitution() on all of the values that use
+ // this one. Usually we do all of this in one pass in pre-order, which ensures that the
+ // X->replaceWithIdentity() calls happen before the performSubstitution() calls on X's users.
void replaceWithIdentity(Value*);
+
+ // It's often necessary to kill a value. It's tempting to replace the value with Nop or to
+ // just remove it. But unless you are sure that the value is Void, you will probably still
+ // have other values that use this one. Sure, you may kill those later, or you might not. This
+ // method lets you kill a value safely. It will replace Void values with Nop and non-Void
+ // values with Identities on bottom constants. For this reason, this takes a callback that is
+ // responsible for creating bottoms. There's a utility for this, see B3BottomProvider.h. You
+ // can also access that utility using replaceWithBottom(InsertionSet&, size_t).
+ template<typename BottomProvider>
+ void replaceWithBottom(const BottomProvider&);
+
+ void replaceWithBottom(InsertionSet&, size_t index);
+
+ // Use this if you want to kill a value and you are sure that the value is Void.
void replaceWithNop();
+
+ // Use this if you want to kill a value and you are sure that nobody is using it anymore.
+ void replaceWithNopIgnoringType();
+
void replaceWithPhi();
void dump(PrintStream&) const;
Modified: trunk/Source/_javascript_Core/b3/B3ValueInlines.h (202501 => 202502)
--- trunk/Source/_javascript_Core/b3/B3ValueInlines.h 2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/_javascript_Core/b3/B3ValueInlines.h 2016-06-27 18:35:09 UTC (rev 202502)
@@ -41,6 +41,20 @@
namespace JSC { namespace B3 {
+template<typename BottomProvider>
+void Value::replaceWithBottom(const BottomProvider& bottomProvider)
+{
+ if (m_type == Void) {
+ replaceWithNop();
+ return;
+ }
+
+ if (isConstant())
+ return;
+
+ replaceWithIdentity(bottomProvider(m_origin, m_type));
+}
+
template<typename T>
T* Value::as()
{
Modified: trunk/Source/_javascript_Core/b3/testb3.cpp (202501 => 202502)
--- trunk/Source/_javascript_Core/b3/testb3.cpp 2016-06-27 18:30:00 UTC (rev 202501)
+++ trunk/Source/_javascript_Core/b3/testb3.cpp 2016-06-27 18:35:09 UTC (rev 202502)
@@ -38,6 +38,7 @@
#include "B3MathExtras.h"
#include "B3MemoryValue.h"
#include "B3Procedure.h"
+#include "B3ReduceStrength.h"
#include "B3SlotBaseValue.h"
#include "B3StackSlot.h"
#include "B3StackmapGenerationParams.h"
@@ -12050,6 +12051,39 @@
CHECK(invoke<uint64_t>(*code) == result);
}
+void testReduceStrengthCheckBottomUseInAnotherBlock()
+{
+ Procedure proc;
+
+ BasicBlock* _one_ = proc.addBlock();
+ BasicBlock* two = proc.addBlock();
+
+ CheckValue* check = one->appendNew<CheckValue>(
+ proc, Check, Origin(), one->appendNew<Const32Value>(proc, Origin(), 1));
+ check->setGenerator(
+ [&] (CCallHelpers& jit, const StackmapGenerationParams&) {
+ AllowMacroScratchRegisterUsage allowScratch(jit);
+
+ jit.move(CCallHelpers::TrustedImm32(666), GPRInfo::returnValueGPR);
+ jit.emitFunctionEpilogue();
+ jit.ret();
+ });
+ Value* arg = one->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+ one->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(two));
+
+ check = two->appendNew<CheckValue>(
+ proc, CheckAdd, Origin(), arg,
+ two->appendNew<ConstPtrValue>(proc, Origin(), 1));
+ check->setGenerator(
+ [&] (CCallHelpers&, const StackmapGenerationParams&) {
+ CHECK(!"Should not execute");
+ });
+ two->appendNew<ControlValue>(proc, Return, Origin(), check);
+
+ proc.resetReachability();
+ reduceStrength(proc);
+}
+
// Make sure the compiler does not try to optimize anything out.
NEVER_INLINE double zero()
{
@@ -13449,11 +13483,10 @@
RUN(testLShiftSelf64());
RUN(testPatchpointDoubleRegs());
-
RUN(testSpillDefSmallerThanUse());
RUN(testSpillUseLargerThanDef());
-
RUN(testLateRegister());
+ RUN(testReduceStrengthCheckBottomUseInAnotherBlock());
if (tasks.isEmpty())
usage();