Changeset 243959 in webkit
- Timestamp:
- Apr 5, 2019, 6:57:16 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 9 edited
-
JSTests/ChangeLog (modified) (1 diff)
-
JSTests/stress/add-overflow-check-with-three-same-registers.js (added)
-
Source/JavaScriptCore/ChangeLog (modified) (1 diff)
-
Source/JavaScriptCore/dfg/DFGOSRExit.cpp (modified) (2 diffs)
-
Source/JavaScriptCore/dfg/DFGOSRExit.h (modified) (2 diffs)
-
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (modified) (1 diff)
-
Source/JavaScriptCore/ftl/FTLExitValue.cpp (modified) (2 diffs)
-
Source/JavaScriptCore/ftl/FTLExitValue.h (modified) (5 diffs)
-
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (modified) (6 diffs)
-
Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r243955 r243959 1 2019-04-05 Yusuke Suzuki <ysuzuki@apple.com> 2 3 [JSC] OSRExit recovery for SpeculativeAdd does not consier "A = A + A" pattern 4 https://bugs.webkit.org/show_bug.cgi?id=196582 5 6 Reviewed by Saam Barati. 7 8 * stress/add-overflow-check-with-three-same-registers.js: Added. 9 (foo): 10 (Number.prototype.valueOf): 11 (runWithNumber): 12 1 13 2019-04-05 Ryan Haddad <ryanhaddad@apple.com> 2 14 -
trunk/Source/JavaScriptCore/ChangeLog
r243955 r243959 1 2019-04-05 Yusuke Suzuki <ysuzuki@apple.com> 2 3 [JSC] OSRExit recovery for SpeculativeAdd does not consier "A = A + A" pattern 4 https://bugs.webkit.org/show_bug.cgi?id=196582 5 6 Reviewed by Saam Barati. 7 8 In DFG, our ArithAdd with overflow is executed speculatively, and we recover the value when overflow flag is set. 9 The recovery is subtracting the operand from the destination to get the original two operands. Our recovery code 10 handles A + B = A, A + B = B cases. But it misses A + A = A case (here, A and B are GPRReg). Our recovery code 11 attempts to produce the original operand by performing A - A, and it always produces zero accidentally. 12 13 This patch adds the recovery code for A + A = A case. Because we know that this ArithAdd overflows, and operands were 14 same values, we can calculate the original operand from the destination value by `((int32_t)value >> 1) ^ 0x80000000`. 15 16 We also found that FTL recovery code is dead. We remove them in this patch. 17 18 * dfg/DFGOSRExit.cpp: 19 (JSC::DFG::OSRExit::executeOSRExit): 20 (JSC::DFG::OSRExit::compileExit): 21 * dfg/DFGOSRExit.h: 22 (JSC::DFG::SpeculationRecovery::SpeculationRecovery): 23 * dfg/DFGSpeculativeJIT.cpp: 24 (JSC::DFG::SpeculativeJIT::compileArithAdd): 25 * ftl/FTLExitValue.cpp: 26 (JSC::FTL::ExitValue::dataFormat const): 27 (JSC::FTL::ExitValue::dumpInContext const): 28 * ftl/FTLExitValue.h: 29 (JSC::FTL::ExitValue::isArgument const): 30 (JSC::FTL::ExitValue::hasIndexInStackmapLocations const): 31 (JSC::FTL::ExitValue::adjustStackmapLocationsIndexByOffset): 32 (JSC::FTL::ExitValue::recovery): Deleted. 33 (JSC::FTL::ExitValue::isRecovery const): Deleted. 34 (JSC::FTL::ExitValue::leftRecoveryArgument const): Deleted. 35 (JSC::FTL::ExitValue::rightRecoveryArgument const): Deleted. 36 (JSC::FTL::ExitValue::recoveryFormat const): Deleted. 37 (JSC::FTL::ExitValue::recoveryOpcode const): Deleted. 38 * ftl/FTLLowerDFGToB3.cpp: 39 (JSC::FTL::DFG::LowerDFGToB3::compileNode): 40 (JSC::FTL::DFG::LowerDFGToB3::preparePatchpointForExceptions): 41 (JSC::FTL::DFG::LowerDFGToB3::appendOSRExit): 42 (JSC::FTL::DFG::LowerDFGToB3::exitValueForNode): 43 (JSC::FTL::DFG::LowerDFGToB3::addAvailableRecovery): Deleted. 44 * ftl/FTLOSRExitCompiler.cpp: 45 (JSC::FTL::compileRecovery): 46 1 47 2019-04-05 Ryan Haddad <ryanhaddad@apple.com> 2 48 -
trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp
r243286 r243959 470 470 case SpeculativeAdd: 471 471 cpu.gpr(recovery->dest()) = cpu.gpr<uint32_t>(recovery->dest()) - cpu.gpr<uint32_t>(recovery->src()); 472 #if USE(JSVALUE64) 473 ASSERT(!(cpu.gpr(recovery->dest()) >> 32)); 474 cpu.gpr(recovery->dest()) |= TagTypeNumber; 475 #endif 476 break; 477 478 case SpeculativeAddSelf: 479 cpu.gpr(recovery->dest()) = static_cast<uint32_t>(cpu.gpr<int32_t>(recovery->dest()) >> 1) ^ 0x80000000U; 472 480 #if USE(JSVALUE64) 473 481 ASSERT(!(cpu.gpr(recovery->dest()) >> 32)); … … 1118 1126 break; 1119 1127 1128 case SpeculativeAddSelf: 1129 // If A + A = A (int32_t) overflows, A can be recovered by ((static_cast<int32_t>(A) >> 1) ^ 0x8000000). 1130 jit.rshift32(AssemblyHelpers::TrustedImm32(1), recovery->dest()); 1131 jit.xor32(AssemblyHelpers::TrustedImm32(0x80000000), recovery->dest()); 1132 #if USE(JSVALUE64) 1133 jit.or64(GPRInfo::tagTypeNumberRegister, recovery->dest()); 1134 #endif 1135 break; 1136 1120 1137 case SpeculativeAddImmediate: 1121 1138 jit.sub32(AssemblyHelpers::Imm32(recovery->immediate()), recovery->dest()); -
trunk/Source/JavaScriptCore/dfg/DFGOSRExit.h
r236585 r243959 60 60 enum SpeculationRecoveryType : uint8_t { 61 61 SpeculativeAdd, 62 SpeculativeAddSelf, 62 63 SpeculativeAddImmediate, 63 64 BooleanSpeculationCheck … … 75 76 , m_type(type) 76 77 { 77 ASSERT(m_type == SpeculativeAdd || m_type == BooleanSpeculationCheck);78 ASSERT(m_type == SpeculativeAdd || m_type == SpeculativeAddSelf || m_type == BooleanSpeculationCheck); 78 79 } 79 80 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r243364 r243959 4307 4307 MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, gpr2, gprResult); 4308 4308 4309 if (gpr1 == gprResult) 4309 if (gpr1 == gprResult && gpr2 == gprResult) 4310 speculationCheck(Overflow, JSValueRegs(), 0, check, SpeculationRecovery(SpeculativeAddSelf, gprResult, gpr2)); 4311 else if (gpr1 == gprResult) 4310 4312 speculationCheck(Overflow, JSValueRegs(), 0, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2)); 4311 4313 else if (gpr2 == gprResult) -
trunk/Source/JavaScriptCore/ftl/FTLExitValue.cpp
r189362 r243959 76 76 case ExitValueInJSStackAsDouble: 77 77 return DataFormatDouble; 78 79 case ExitValueRecovery:80 return recoveryFormat();81 78 } 82 79 … … 111 108 out.print("InJSStackAsDouble:", virtualRegister()); 112 109 return; 113 case ExitValueRecovery:114 out.print("Recovery(", recoveryOpcode(), ", arg", leftRecoveryArgument(), ", arg", rightRecoveryArgument(), ", ", recoveryFormat(), ")");115 return;116 110 case ExitValueMaterializeNewObject: 117 111 out.print("Materialize(", WTF::RawPointer(objectMaterialization()), ")"); -
trunk/Source/JavaScriptCore/ftl/FTLExitValue.h
r206525 r243959 55 55 ExitValueInJSStackAsInt52, 56 56 ExitValueInJSStackAsDouble, 57 ExitValueRecovery,58 57 ExitValueMaterializeNewObject 59 58 }; … … 122 121 result.m_kind = ExitValueArgument; 123 122 result.u.argument = argument.representation(); 124 return result;125 }126 127 static ExitValue recovery(RecoveryOpcode opcode, unsigned leftArgument, unsigned rightArgument, DataFormat format)128 {129 ExitValue result;130 result.m_kind = ExitValueRecovery;131 result.u.recovery.opcode = opcode;132 result.u.recovery.leftArgument = leftArgument;133 result.u.recovery.rightArgument = rightArgument;134 result.u.recovery.format = format;135 123 return result; 136 124 } … … 155 143 bool isConstant() const { return kind() == ExitValueConstant; } 156 144 bool isArgument() const { return kind() == ExitValueArgument; } 157 bool isRecovery() const { return kind() == ExitValueRecovery; }158 145 bool isObjectMaterialization() const { return kind() == ExitValueMaterializeNewObject; } 159 bool hasIndexInStackmapLocations() const { return isArgument() || isRecovery(); }146 bool hasIndexInStackmapLocations() const { return isArgument(); } 160 147 161 148 ExitArgument exitArgument() const … … 165 152 } 166 153 167 unsigned leftRecoveryArgument() const168 {169 ASSERT(isRecovery());170 return u.recovery.leftArgument;171 }172 173 unsigned rightRecoveryArgument() const174 {175 ASSERT(isRecovery());176 return u.recovery.rightArgument;177 }178 179 154 void adjustStackmapLocationsIndexByOffset(unsigned offset) 180 155 { 181 156 ASSERT(hasIndexInStackmapLocations()); 182 if (isArgument()) 183 u.argument.argument += offset; 184 else { 185 ASSERT(isRecovery()); 186 u.recovery.rightArgument += offset; 187 u.recovery.leftArgument += offset; 188 } 189 } 190 191 DataFormat recoveryFormat() const 192 { 193 ASSERT(isRecovery()); 194 return static_cast<DataFormat>(u.recovery.format); 195 } 196 197 RecoveryOpcode recoveryOpcode() const 198 { 199 ASSERT(isRecovery()); 200 return static_cast<RecoveryOpcode>(u.recovery.opcode); 157 ASSERT(isArgument()); 158 u.argument.argument += offset; 201 159 } 202 160 … … 247 205 EncodedJSValue constant; 248 206 int virtualRegister; 249 struct {250 uint16_t leftArgument;251 uint16_t rightArgument;252 uint16_t opcode;253 uint16_t format;254 } recovery;255 207 ExitTimeObjectMaterialization* newObjectMaterializationData; 256 208 } u; -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r243596 r243959 676 676 if (verboseCompilationEnabled()) 677 677 dataLog("Lowering ", m_node, "\n"); 678 679 m_availableRecoveries.shrink(0);680 678 681 679 m_interpreter.startExecuting(); … … 16745 16743 return PatchpointExceptionHandle::defaultHandle(m_ftlState); 16746 16744 16747 if (verboseCompilationEnabled()) { 16748 dataLog(" Patchpoint exception OSR exit #", m_ftlState.jitCode->osrExitDescriptors.size(), " with availability: ", availabilityMap(), "\n"); 16749 if (!m_availableRecoveries.isEmpty()) 16750 dataLog(" Available recoveries: ", listDump(m_availableRecoveries), "\n"); 16751 } 16745 dataLogLnIf(verboseCompilationEnabled(), " Patchpoint exception OSR exit #", m_ftlState.jitCode->osrExitDescriptors.size(), " with availability: ", availabilityMap()); 16752 16746 16753 16747 bool exitOK = true; … … 16803 16797 NodeOrigin origin, bool isExceptionHandler = false) 16804 16798 { 16805 if (verboseCompilationEnabled()) { 16806 dataLog(" OSR exit #", m_ftlState.jitCode->osrExitDescriptors.size(), " with availability: ", availabilityMap(), "\n"); 16807 if (!m_availableRecoveries.isEmpty()) 16808 dataLog(" Available recoveries: ", listDump(m_availableRecoveries), "\n"); 16809 } 16799 dataLogLnIf(verboseCompilationEnabled(), " OSR exit #", m_ftlState.jitCode->osrExitDescriptors.size(), " with availability: ", availabilityMap()); 16810 16800 16811 16801 DFG_ASSERT(m_graph, m_node, origin.exitOK); … … 17001 16991 } 17002 16992 17003 for (unsigned i = 0; i < m_availableRecoveries.size(); ++i) {17004 AvailableRecovery recovery = m_availableRecoveries[i];17005 if (recovery.node() != node)17006 continue;17007 ExitValue result = ExitValue::recovery(17008 recovery.opcode(), arguments.size(), arguments.size() + 1,17009 recovery.format());17010 arguments.append(recovery.left());17011 arguments.append(recovery.right());17012 return result;17013 }17014 17015 16993 LoweredNodeValue value = m_int32Values.get(node); 17016 16994 if (isValid(value)) … … 17079 17057 } 17080 17058 17081 void addAvailableRecovery(17082 Node* node, RecoveryOpcode opcode, LValue left, LValue right, DataFormat format)17083 {17084 m_availableRecoveries.append(AvailableRecovery(node, opcode, left, right, format));17085 }17086 17087 void addAvailableRecovery(17088 Edge edge, RecoveryOpcode opcode, LValue left, LValue right, DataFormat format)17089 {17090 addAvailableRecovery(edge.node(), opcode, left, right, format);17091 }17092 17093 17059 void setInt32(Node* node, LValue value) 17094 17060 { … … 17351 17317 LocalOSRAvailabilityCalculator m_availabilityCalculator; 17352 17318 17353 Vector<AvailableRecovery, 3> m_availableRecoveries;17354 17355 17319 InPlaceAbstractState m_state; 17356 17320 AbstractInterpreter<InPlaceAbstractState> m_interpreter; -
trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp
r243232 r243959 125 125 break; 126 126 127 case ExitValueRecovery:128 Location::forValueRep(valueReps[value.rightRecoveryArgument()]).restoreInto(129 jit, registerScratch, GPRInfo::regT1);130 Location::forValueRep(valueReps[value.leftRecoveryArgument()]).restoreInto(131 jit, registerScratch, GPRInfo::regT0);132 switch (value.recoveryOpcode()) {133 case AddRecovery:134 switch (value.recoveryFormat()) {135 case DataFormatInt32:136 jit.add32(GPRInfo::regT1, GPRInfo::regT0);137 break;138 case DataFormatInt52:139 jit.add64(GPRInfo::regT1, GPRInfo::regT0);140 break;141 default:142 RELEASE_ASSERT_NOT_REACHED();143 break;144 }145 break;146 case SubRecovery:147 switch (value.recoveryFormat()) {148 case DataFormatInt32:149 jit.sub32(GPRInfo::regT1, GPRInfo::regT0);150 break;151 case DataFormatInt52:152 jit.sub64(GPRInfo::regT1, GPRInfo::regT0);153 break;154 default:155 RELEASE_ASSERT_NOT_REACHED();156 break;157 }158 break;159 default:160 RELEASE_ASSERT_NOT_REACHED();161 break;162 }163 break;164 165 127 case ExitValueMaterializeNewObject: 166 128 jit.loadPtr(materializationToPointer.get(value.objectMaterialization()), GPRInfo::regT0);
Note:
See TracChangeset
for help on using the changeset viewer.