source: webkit/trunk/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp

Last change on this file was 293629, checked in by [email protected], 3 years ago

[JSC] Use FixedVector in JumpReplacements and VariableEventStream
https://bugs.webkit.org/show_bug.cgi?id=239892

Reviewed by Mark Lam.

  1. Introduce DFG::VariableEventStreamBuilder. And construct DFG::VariableEventStream from that

builder when finailizing code generation. We also make it FixedVector.

  1. Use FixedVector for JumpReplacements.
  • Source/JavaScriptCore/dfg/DFGCommonData.cpp:

(JSC::DFG::CommonData::shrinkToFit):

  • Source/JavaScriptCore/dfg/DFGCommonData.h:
  • Source/JavaScriptCore/dfg/DFGGenerationInfo.h:

(JSC::DFG::GenerationInfo::noticeOSRBirth):
(JSC::DFG::GenerationInfo::use):
(JSC::DFG::GenerationInfo::spill):
(JSC::DFG::GenerationInfo::setSpilled):
(JSC::DFG::GenerationInfo::fillGPR):
(JSC::DFG::GenerationInfo::fillJSValue):
(JSC::DFG::GenerationInfo::fillCell):
(JSC::DFG::GenerationInfo::fillInt32):
(JSC::DFG::GenerationInfo::fillInt52):
(JSC::DFG::GenerationInfo::fillStrictInt52):
(JSC::DFG::GenerationInfo::fillBoolean):
(JSC::DFG::GenerationInfo::fillDouble):
(JSC::DFG::GenerationInfo::fillStorage):
(JSC::DFG::GenerationInfo::appendBirth):
(JSC::DFG::GenerationInfo::appendFill):
(JSC::DFG::GenerationInfo::appendSpill):

  • Source/JavaScriptCore/dfg/DFGJITCode.cpp:

(JSC::DFG::JITCode::shrinkToFit):
(JSC::DFG::JITCode::reconstruct):

  • Source/JavaScriptCore/dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::link):
(JSC::DFG::JITCompiler::compile):
(JSC::DFG::JITCompiler::compileFunction):
(JSC::DFG::JITCompiler::exceptionCheck):

  • Source/JavaScriptCore/dfg/DFGSlowPathGenerator.h:

(JSC::DFG::SlowPathGenerator::SlowPathGenerator):

  • Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::SpeculativeJIT):
(JSC::DFG::SpeculativeJIT::speculationCheck):
(JSC::DFG::SpeculativeJIT::emitInvalidationPoint):
(JSC::DFG::SpeculativeJIT::addSlowPathGeneratorLambda):
(JSC::DFG::SpeculativeJIT::fillStorage):
(JSC::DFG::SpeculativeJIT::compileDeleteById):
(JSC::DFG::SpeculativeJIT::compileDeleteByVal):
(JSC::DFG::SpeculativeJIT::compileInById):
(JSC::DFG::SpeculativeJIT::compileInByVal):
(JSC::DFG::SpeculativeJIT::compileHasPrivate):
(JSC::DFG::SpeculativeJIT::noticeOSRBirth):
(JSC::DFG::SpeculativeJIT::compileMovHint):
(JSC::DFG::SpeculativeJIT::compileCurrentBlock):
(JSC::DFG::SpeculativeJIT::compilePutByVal):

  • Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::finalizeEventStream):
(JSC::DFG::SpeculativeJIT::use):
(JSC::DFG::SpeculativeJIT::spill):
(JSC::DFG::SpeculativeJIT::recordSetLocal):

  • Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::fillJSValue):
(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedGetByIdWithThis):
(JSC::DFG::SpeculativeJIT::emitCall):
(JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal):
(JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):
(JSC::DFG::SpeculativeJIT::compileGetByVal):

  • Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::fillJSValue):
(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedGetByIdWithThis):
(JSC::DFG::SpeculativeJIT::emitCall):
(JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal):
(JSC::DFG::SpeculativeJIT::fillSpeculateInt52):
(JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):
(JSC::DFG::SpeculativeJIT::fillSpeculateBigInt32):
(JSC::DFG::SpeculativeJIT::compileGetByVal):
(JSC::DFG::SpeculativeJIT::compile):

  • Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp:

(JSC::DFG::VariableEventStreamBuilder::logEvent):
(JSC::DFG::VariableEventStream::reconstruct const):
(JSC::DFG::VariableEventStream::logEvent): Deleted.

  • Source/JavaScriptCore/dfg/DFGVariableEventStream.h:

(JSC::DFG::VariableEventStream::VariableEventStream):
(JSC::DFG::VariableEventStreamBuilder::appendAndLog):
(JSC::DFG::VariableEventStreamBuilder::size const):
(JSC::DFG::VariableEventStreamBuilder::finalize):
(JSC::DFG::VariableEventStream::appendAndLog): Deleted.

  • Source/JavaScriptCore/ftl/FTLLink.cpp:

(JSC::FTL::link):

  • Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):

  • Source/JavaScriptCore/ftl/FTLState.h:

Canonical link: https://commits.webkit.org/250135@main

File size: 11.2 KB
Line 
1/*
2 * Copyright (C) 2012-2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "DFGVariableEventStream.h"
28
29#if ENABLE(DFG_JIT)
30
31#include "CodeBlock.h"
32#include "DFGValueSource.h"
33#include "InlineCallFrame.h"
34#include "JSCJSValueInlines.h"
35#include "OperandsInlines.h"
36#include <wtf/DataLog.h>
37#include <wtf/HashMap.h>
38
39namespace JSC { namespace DFG {
40
41void VariableEventStreamBuilder::logEvent(const VariableEvent& event)
42{
43 dataLogF("seq#%u:", static_cast<unsigned>(m_stream.size()));
44 event.dump(WTF::dataFile());
45 dataLogLn(" ");
46}
47
48namespace {
49
50struct MinifiedGenerationInfo {
51 bool filled; // true -> in gpr/fpr/pair, false -> spilled
52 bool alive;
53 VariableRepresentation u;
54 DataFormat format;
55
56 MinifiedGenerationInfo()
57 : filled(false)
58 , alive(false)
59 , format(DataFormatNone)
60 {
61 }
62
63 void update(const VariableEvent& event)
64 {
65 switch (event.kind()) {
66 case BirthToFill:
67 case Fill:
68 filled = true;
69 alive = true;
70 break;
71 case BirthToSpill:
72 case Spill:
73 filled = false;
74 alive = true;
75 break;
76 case Birth:
77 alive = true;
78 return;
79 case Death:
80 format = DataFormatNone;
81 alive = false;
82 return;
83 default:
84 return;
85 }
86
87 u = event.variableRepresentation();
88 format = event.dataFormat();
89 }
90};
91
92} // namespace
93
94static bool tryToSetConstantRecovery(ValueRecovery& recovery, MinifiedNode* node)
95{
96 if (!node)
97 return false;
98
99 if (node->hasConstant()) {
100 recovery = ValueRecovery::constant(node->constant());
101 return true;
102 }
103
104 if (node->isPhantomDirectArguments()) {
105 recovery = ValueRecovery::directArgumentsThatWereNotCreated(node->id());
106 return true;
107 }
108
109 if (node->isPhantomClonedArguments()) {
110 recovery = ValueRecovery::clonedArgumentsThatWereNotCreated(node->id());
111 return true;
112 }
113
114 return false;
115}
116
117template<VariableEventStream::ReconstructionStyle style>
118unsigned VariableEventStream::reconstruct(
119 CodeBlock* codeBlock, CodeOrigin codeOrigin, MinifiedGraph& graph,
120 unsigned index, Operands<ValueRecovery>& valueRecoveries, Vector<UndefinedOperandSpan>* undefinedOperandSpans) const
121{
122 constexpr bool verbose = false;
123 ASSERT(codeBlock->jitType() == JITType::DFGJIT);
124 CodeBlock* baselineCodeBlock = codeBlock->baselineVersion();
125
126 unsigned numVariables;
127 unsigned numTmps;
128 static constexpr unsigned invalidIndex = std::numeric_limits<unsigned>::max();
129 unsigned firstUndefined = invalidIndex;
130 bool firstUndefinedIsArgument = false;
131
132 auto flushUndefinedOperandSpan = [&] (unsigned i) {
133 if (firstUndefined == invalidIndex)
134 return;
135 int firstOffset = valueRecoveries.operandForIndex(firstUndefined).virtualRegister().offset();
136 int lastOffset = valueRecoveries.operandForIndex(i - 1).virtualRegister().offset();
137 int minOffset = std::min(firstOffset, lastOffset);
138 undefinedOperandSpans->append({ firstUndefined, minOffset, i - firstUndefined });
139 firstUndefined = invalidIndex;
140 };
141 auto recordUndefinedOperand = [&] (unsigned i) {
142 // We want to separate the span of arguments from the span of locals even if they have adjacent operands indexes.
143 if (firstUndefined != invalidIndex && firstUndefinedIsArgument != valueRecoveries.operandForIndex(i).isArgument())
144 flushUndefinedOperandSpan(i);
145
146 if (firstUndefined == invalidIndex) {
147 firstUndefined = i;
148 firstUndefinedIsArgument = valueRecoveries.operandForIndex(i).isArgument();
149 }
150 };
151
152 auto* inlineCallFrame = codeOrigin.inlineCallFrame();
153 if (inlineCallFrame) {
154 CodeBlock* codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame);
155 numVariables = codeBlock->numCalleeLocals() + VirtualRegister(inlineCallFrame->stackOffset).toLocal() + 1;
156 numTmps = codeBlock->numTmps() + inlineCallFrame->tmpOffset;
157 } else {
158 numVariables = baselineCodeBlock->numCalleeLocals();
159 numTmps = baselineCodeBlock->numTmps();
160 }
161
162 // Crazy special case: if we're at index == 0 then this must be an argument check
163 // failure, in which case all variables are already set up. The recoveries should
164 // reflect this.
165 if (!index) {
166 // We don't include tmps here because they can't be used yet.
167 valueRecoveries = Operands<ValueRecovery>(codeBlock->numParameters(), numVariables, 0);
168 for (size_t i = 0; i < valueRecoveries.size(); ++i) {
169 valueRecoveries[i] = ValueRecovery::displacedInJSStack(
170 valueRecoveries.operandForIndex(i).virtualRegister(), DataFormatJS);
171 }
172 return numVariables;
173 }
174
175 // Step 1: Find the last checkpoint, and figure out the number of virtual registers as we go.
176 unsigned startIndex = index - 1;
177 while (m_stream.at(startIndex).kind() != Reset)
178 startIndex--;
179
180 // Step 2: Create a mock-up of the DFG's state and execute the events.
181 Operands<ValueSource> operandSources(codeBlock->numParameters(), numVariables, numTmps);
182 for (unsigned i = operandSources.size(); i--;)
183 operandSources[i] = ValueSource(SourceIsDead);
184 HashMap<MinifiedID, MinifiedGenerationInfo> generationInfos;
185 for (unsigned i = startIndex; i < index; ++i) {
186 const VariableEvent& event = m_stream.at(i);
187 dataLogLnIf(verbose, "Processing event ", event);
188 switch (event.kind()) {
189 case Reset:
190 // nothing to do.
191 break;
192 case BirthToFill:
193 case BirthToSpill:
194 case Birth: {
195 MinifiedGenerationInfo info;
196 info.update(event);
197 generationInfos.add(event.id(), info);
198 break;
199 }
200 case Fill:
201 case Spill:
202 case Death: {
203 HashMap<MinifiedID, MinifiedGenerationInfo>::iterator iter = generationInfos.find(event.id());
204 ASSERT(iter != generationInfos.end());
205 iter->value.update(event);
206 break;
207 }
208 case MovHintEvent:
209 if (operandSources.hasOperand(event.operand()))
210 operandSources.setOperand(event.operand(), ValueSource(event.id()));
211 break;
212 case SetLocalEvent:
213 if (operandSources.hasOperand(event.operand()))
214 operandSources.setOperand(event.operand(), ValueSource::forDataFormat(event.machineRegister(), event.dataFormat()));
215 break;
216 default:
217 RELEASE_ASSERT_NOT_REACHED();
218 break;
219 }
220 }
221
222 dataLogLnIf(verbose, "Operand sources: ", operandSources);
223
224 // Step 3: Compute value recoveries!
225 valueRecoveries = Operands<ValueRecovery>(OperandsLike, operandSources);
226 for (unsigned i = 0; i < operandSources.size(); ++i) {
227 ValueSource& source = operandSources[i];
228 if (source.isTriviallyRecoverable()) {
229 valueRecoveries[i] = source.valueRecovery();
230 if (style == ReconstructionStyle::Separated) {
231 if (valueRecoveries[i].isConstant() && valueRecoveries[i].constant() == jsUndefined())
232 recordUndefinedOperand(i);
233 else
234 flushUndefinedOperandSpan(i);
235 }
236 continue;
237 }
238
239 ASSERT(source.kind() == HaveNode);
240 MinifiedNode* node = graph.at(source.id());
241 MinifiedGenerationInfo info = generationInfos.get(source.id());
242 if (!info.alive) {
243 dataLogLnIf(verbose, "Operand ", valueRecoveries.operandForIndex(i), " is dead.");
244 valueRecoveries[i] = ValueRecovery::constant(jsUndefined());
245 if (style == ReconstructionStyle::Separated)
246 recordUndefinedOperand(i);
247 continue;
248 }
249
250 if (tryToSetConstantRecovery(valueRecoveries[i], node)) {
251 dataLogLnIf(verbose, "Operand ", valueRecoveries.operandForIndex(i), " is constant.");
252 if (style == ReconstructionStyle::Separated) {
253 if (node->hasConstant() && node->constant() == jsUndefined())
254 recordUndefinedOperand(i);
255 else
256 flushUndefinedOperandSpan(i);
257 }
258 continue;
259 }
260
261 ASSERT(info.format != DataFormatNone);
262 if (style == ReconstructionStyle::Separated)
263 flushUndefinedOperandSpan(i);
264
265 if (info.filled) {
266 if (info.format == DataFormatDouble) {
267 valueRecoveries[i] = ValueRecovery::inFPR(info.u.fpr, DataFormatDouble);
268 continue;
269 }
270#if USE(JSVALUE32_64)
271 if (info.format & DataFormatJS) {
272 valueRecoveries[i] = ValueRecovery::inPair(info.u.pair.tagGPR, info.u.pair.payloadGPR);
273 continue;
274 }
275#endif
276 valueRecoveries[i] = ValueRecovery::inGPR(info.u.gpr, info.format);
277 continue;
278 }
279
280 valueRecoveries[i] =
281 ValueRecovery::displacedInJSStack(info.u.operand.virtualRegister(), info.format);
282 }
283 if (style == ReconstructionStyle::Separated)
284 flushUndefinedOperandSpan(operandSources.size());
285
286 return numVariables;
287}
288
289unsigned VariableEventStream::reconstruct(
290 CodeBlock* codeBlock, CodeOrigin codeOrigin, MinifiedGraph& graph,
291 unsigned index, Operands<ValueRecovery>& valueRecoveries) const
292{
293 return reconstruct<ReconstructionStyle::Combined>(codeBlock, codeOrigin, graph, index, valueRecoveries, nullptr);
294}
295
296unsigned VariableEventStream::reconstruct(
297 CodeBlock* codeBlock, CodeOrigin codeOrigin, MinifiedGraph& graph,
298 unsigned index, Operands<ValueRecovery>& valueRecoveries, Vector<UndefinedOperandSpan>* undefinedOperandSpans) const
299{
300 return reconstruct<ReconstructionStyle::Separated>(codeBlock, codeOrigin, graph, index, valueRecoveries, undefinedOperandSpans);
301}
302
303} } // namespace JSC::DFG
304
305#endif // ENABLE(DFG_JIT)
306
Note: See TracBrowser for help on using the repository browser.