]> git.saurik.com Git - apple/javascriptcore.git/blame - dfg/DFGConstantFoldingPhase.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / dfg / DFGConstantFoldingPhase.cpp
CommitLineData
93a37866 1/*
ed1e77d3 2 * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
93a37866
A
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 "DFGConstantFoldingPhase.h"
28
29#if ENABLE(DFG_JIT)
30
81345200 31#include "DFGAbstractInterpreterInlines.h"
ed1e77d3 32#include "DFGArgumentsUtilities.h"
93a37866
A
33#include "DFGBasicBlock.h"
34#include "DFGGraph.h"
81345200 35#include "DFGInPlaceAbstractState.h"
93a37866
A
36#include "DFGInsertionSet.h"
37#include "DFGPhase.h"
38#include "GetByIdStatus.h"
81345200 39#include "JSCInlines.h"
93a37866
A
40#include "PutByIdStatus.h"
41
42namespace JSC { namespace DFG {
43
44class ConstantFoldingPhase : public Phase {
45public:
46 ConstantFoldingPhase(Graph& graph)
47 : Phase(graph, "constant folding")
48 , m_state(graph)
81345200 49 , m_interpreter(graph, m_state)
93a37866
A
50 , m_insertionSet(graph)
51 {
52 }
53
54 bool run()
55 {
56 bool changed = false;
57
81345200
A
58 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
59 BasicBlock* block = m_graph.block(blockIndex);
93a37866
A
60 if (!block)
61 continue;
93a37866 62 if (block->cfaFoundConstants)
81345200 63 changed |= foldConstants(block);
93a37866
A
64 }
65
ed1e77d3
A
66 if (changed && m_graph.m_form == SSA) {
67 // It's now possible that we have Upsilons pointed at JSConstants. Fix that.
68 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
69 BasicBlock* block = m_graph.block(blockIndex);
70 if (!block)
71 continue;
72 fixUpsilons(block);
73 }
74 }
75
93a37866
A
76 return changed;
77 }
78
79private:
81345200 80 bool foldConstants(BasicBlock* block)
93a37866 81 {
93a37866
A
82 bool changed = false;
83 m_state.beginBasicBlock(block);
84 for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
85 if (!m_state.isValid())
86 break;
87
88 Node* node = block->at(indexInBlock);
89
ed1e77d3 90 bool alreadyHandled = false;
93a37866
A
91 bool eliminated = false;
92
93 switch (node->op()) {
81345200
A
94 case BooleanToNumber: {
95 if (node->child1().useKind() == UntypedUse
96 && !m_interpreter.needsTypeCheck(node->child1(), SpecBoolean))
97 node->child1().setUseKind(BooleanUse);
98 break;
99 }
100
93a37866 101 case CheckStructure:
93a37866
A
102 case ArrayifyToStructure: {
103 AbstractValue& value = m_state.forNode(node->child1());
104 StructureSet set;
105 if (node->op() == ArrayifyToStructure)
106 set = node->structure();
107 else
108 set = node->structureSet();
ed1e77d3 109 if (value.m_structure.isSubsetOf(set)) {
81345200 110 m_interpreter.execute(indexInBlock); // Catch the fact that we may filter on cell.
ed1e77d3 111 node->remove();
93a37866
A
112 eliminated = true;
113 break;
114 }
ed1e77d3
A
115 break;
116 }
117
118 case GetIndexedPropertyStorage: {
119 JSArrayBufferView* view = m_graph.tryGetFoldableView(
120 m_state.forNode(node->child1()).m_value, node->arrayMode());
121 if (!view)
122 break;
123
124 if (view->mode() == FastTypedArray) {
125 // FIXME: It would be awesome to be able to fold the property storage for
126 // these GC-allocated typed arrays. For now it doesn't matter because the
127 // most common use-cases for constant typed arrays involve large arrays with
128 // aliased buffer views.
129 // https://bugs.webkit.org/show_bug.cgi?id=125425
93a37866
A
130 break;
131 }
ed1e77d3
A
132
133 m_interpreter.execute(indexInBlock);
134 eliminated = true;
135
136 m_insertionSet.insertCheck(indexInBlock, node->origin, node->children);
137 node->convertToConstantStoragePointer(view->vector());
138 break;
139 }
140
141 case CheckStructureImmediate: {
142 AbstractValue& value = m_state.forNode(node->child1());
143 StructureSet& set = node->structureSet();
144
145 if (value.value()) {
146 if (Structure* structure = jsDynamicCast<Structure*>(value.value())) {
147 if (set.contains(structure)) {
148 m_interpreter.execute(indexInBlock);
149 node->remove();
150 eliminated = true;
151 break;
152 }
153 }
154 }
155
156 if (PhiChildren* phiChildren = m_interpreter.phiChildren()) {
157 bool allGood = true;
158 phiChildren->forAllTransitiveIncomingValues(
159 node,
160 [&] (Node* incoming) {
161 if (Structure* structure = incoming->dynamicCastConstant<Structure*>()) {
162 if (set.contains(structure))
163 return;
164 }
165 allGood = false;
166 });
167 if (allGood) {
168 m_interpreter.execute(indexInBlock);
169 node->remove();
170 eliminated = true;
171 break;
172 }
173 }
93a37866
A
174 break;
175 }
176
177 case CheckArray:
178 case Arrayify: {
179 if (!node->arrayMode().alreadyChecked(m_graph, node, m_state.forNode(node->child1())))
180 break;
ed1e77d3 181 node->remove();
93a37866
A
182 eliminated = true;
183 break;
184 }
185
ed1e77d3
A
186 case PutStructure: {
187 if (m_state.forNode(node->child1()).m_structure.onlyStructure() != node->transition()->next)
93a37866 188 break;
ed1e77d3
A
189
190 node->remove();
93a37866
A
191 eliminated = true;
192 break;
193 }
194
ed1e77d3
A
195 case CheckCell: {
196 if (m_state.forNode(node->child1()).value() != node->cellOperand()->value())
197 break;
198 node->remove();
199 eliminated = true;
200 break;
201 }
202
203 case CheckNotEmpty: {
204 if (m_state.forNode(node->child1()).m_type & SpecEmpty)
205 break;
206 node->remove();
207 eliminated = true;
208 break;
209 }
210
81345200
A
211 case CheckInBounds: {
212 JSValue left = m_state.forNode(node->child1()).value();
213 JSValue right = m_state.forNode(node->child2()).value();
214 if (left && right && left.isInt32() && right.isInt32()
215 && static_cast<uint32_t>(left.asInt32()) < static_cast<uint32_t>(right.asInt32())) {
ed1e77d3 216 node->remove();
81345200
A
217 eliminated = true;
218 break;
219 }
220
221 break;
222 }
223
ed1e77d3
A
224 case GetMyArgumentByVal: {
225 JSValue index = m_state.forNode(node->child2()).value();
226 if (!index || !index.isInt32())
81345200
A
227 break;
228
ed1e77d3
A
229 Node* arguments = node->child1().node();
230 InlineCallFrame* inlineCallFrame = arguments->origin.semantic.inlineCallFrame;
231
232 // Don't try to do anything if the index is known to be outside our static bounds. Note
233 // that our static bounds are usually strictly larger than the dynamic bounds. The
234 // exception is something like this, assuming foo() is not inlined:
235 //
236 // function foo() { return arguments[5]; }
237 //
238 // Here the static bound on number of arguments is 0, and we're accessing index 5. We
239 // will not strength-reduce this to GetStack because GetStack is otherwise assumed by the
240 // compiler to access those variables that are statically accounted for; for example if
241 // we emitted a GetStack on arg6 we would have out-of-bounds access crashes anywhere that
242 // uses an Operands<> map. There is not much cost to continuing to use a
243 // GetMyArgumentByVal in such statically-out-of-bounds accesses; we just lose CFA unless
244 // GCSE removes the access entirely.
245 if (inlineCallFrame) {
246 if (index.asUInt32() >= inlineCallFrame->arguments.size() - 1)
81345200 247 break;
ed1e77d3
A
248 } else {
249 if (index.asUInt32() >= m_state.variables().numberOfArguments() - 1)
250 break;
251 }
252
253 m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
254
255 StackAccessData* data;
256 if (inlineCallFrame) {
257 data = m_graph.m_stackAccessData.add(
258 VirtualRegister(
259 inlineCallFrame->stackOffset +
260 CallFrame::argumentOffset(index.asInt32())),
261 FlushedJSValue);
262 } else {
263 data = m_graph.m_stackAccessData.add(
264 virtualRegisterForArgument(index.asInt32() + 1), FlushedJSValue);
265 }
266
267 if (inlineCallFrame && !inlineCallFrame->isVarargs()
268 && index.asUInt32() < inlineCallFrame->arguments.size() - 1) {
269 node->convertToGetStack(data);
81345200
A
270 eliminated = true;
271 break;
272 }
ed1e77d3
A
273
274 Node* length = emitCodeToGetArgumentsArrayLength(
275 m_insertionSet, arguments, indexInBlock, node->origin);
276 m_insertionSet.insertNode(
277 indexInBlock, SpecNone, CheckInBounds, node->origin,
278 node->child2(), Edge(length, Int32Use));
279 node->convertToGetStack(data);
280 eliminated = true;
281 break;
282 }
283
284 case MultiGetByOffset: {
285 Edge baseEdge = node->child1();
286 Node* base = baseEdge.node();
287 MultiGetByOffsetData& data = node->multiGetByOffsetData();
288
289 // First prune the variants, then check if the MultiGetByOffset can be
290 // strength-reduced to a GetByOffset.
291
292 AbstractValue baseValue = m_state.forNode(base);
293
294 m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
295 alreadyHandled = true; // Don't allow the default constant folder to do things to this.
296
297 for (unsigned i = 0; i < data.variants.size(); ++i) {
298 GetByIdVariant& variant = data.variants[i];
299 variant.structureSet().filter(baseValue);
300 if (variant.structureSet().isEmpty()) {
301 data.variants[i--] = data.variants.last();
302 data.variants.removeLast();
303 changed = true;
304 }
305 }
306
307 if (data.variants.size() != 1)
308 break;
309
310 emitGetByOffset(
311 indexInBlock, node, baseValue, data.variants[0], data.identifierNumber);
312 changed = true;
81345200
A
313 break;
314 }
315
316 case MultiPutByOffset: {
ed1e77d3
A
317 Edge baseEdge = node->child1();
318 Node* base = baseEdge.node();
81345200 319 MultiPutByOffsetData& data = node->multiPutByOffsetData();
ed1e77d3
A
320
321 AbstractValue baseValue = m_state.forNode(base);
81345200 322
ed1e77d3
A
323 m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
324 alreadyHandled = true; // Don't allow the default constant folder to do things to this.
81345200 325
ed1e77d3
A
326
327 for (unsigned i = 0; i < data.variants.size(); ++i) {
328 PutByIdVariant& variant = data.variants[i];
329 variant.oldStructure().filter(baseValue);
330
331 if (variant.oldStructure().isEmpty()) {
332 data.variants[i--] = data.variants.last();
333 data.variants.removeLast();
334 changed = true;
81345200 335 continue;
ed1e77d3 336 }
81345200 337
ed1e77d3
A
338 if (variant.kind() == PutByIdVariant::Transition
339 && variant.oldStructure().onlyStructure() == variant.newStructure()) {
340 variant = PutByIdVariant::replace(
341 variant.oldStructure(),
342 variant.offset());
343 changed = true;
344 }
81345200 345 }
ed1e77d3
A
346
347 if (data.variants.size() != 1)
348 break;
349
350 emitPutByOffset(
351 indexInBlock, node, baseValue, data.variants[0], data.identifierNumber);
352 changed = true;
81345200
A
353 break;
354 }
355
93a37866
A
356 case GetById:
357 case GetByIdFlush: {
93a37866
A
358 Edge childEdge = node->child1();
359 Node* child = childEdge.node();
360 unsigned identifierNumber = node->identifierNumber();
361
ed1e77d3
A
362 AbstractValue baseValue = m_state.forNode(child);
363
364 m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
365 alreadyHandled = true; // Don't allow the default constant folder to do things to this.
366
367 if (baseValue.m_structure.isTop() || baseValue.m_structure.isClobbered()
368 || (node->child1().useKind() == UntypedUse || (baseValue.m_type & ~SpecCell)))
93a37866
A
369 break;
370
93a37866 371 GetByIdStatus status = GetByIdStatus::computeFor(
ed1e77d3
A
372 baseValue.m_structure.set(), m_graph.identifiers()[identifierNumber]);
373 if (!status.isSimple())
374 break;
375
376 for (unsigned i = status.numVariants(); i--;) {
377 if (!status[i].constantChecks().isEmpty()
378 || status[i].alternateBase()) {
379 // FIXME: We could handle prototype cases.
380 // https://bugs.webkit.org/show_bug.cgi?id=110386
381 break;
382 }
383 }
93a37866 384
ed1e77d3
A
385 if (status.numVariants() == 1) {
386 emitGetByOffset(indexInBlock, node, baseValue, status[0], identifierNumber);
387 changed = true;
93a37866
A
388 break;
389 }
390
ed1e77d3
A
391 if (!isFTL(m_graph.m_plan.mode))
392 break;
393
394 MultiGetByOffsetData* data = m_graph.m_multiGetByOffsetData.add();
395 data->variants = status.variants();
396 data->identifierNumber = identifierNumber;
397 node->convertToMultiGetByOffset(data);
398 changed = true;
93a37866
A
399 break;
400 }
401
402 case PutById:
ed1e77d3
A
403 case PutByIdDirect:
404 case PutByIdFlush: {
81345200 405 NodeOrigin origin = node->origin;
93a37866
A
406 Edge childEdge = node->child1();
407 Node* child = childEdge.node();
408 unsigned identifierNumber = node->identifierNumber();
409
410 ASSERT(childEdge.useKind() == CellUse);
411
ed1e77d3
A
412 AbstractValue baseValue = m_state.forNode(child);
413
414 m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
415 alreadyHandled = true; // Don't allow the default constant folder to do things to this.
416
417 if (baseValue.m_structure.isTop() || baseValue.m_structure.isClobbered())
93a37866
A
418 break;
419
93a37866 420 PutByIdStatus status = PutByIdStatus::computeFor(
81345200 421 m_graph.globalObjectFor(origin.semantic),
ed1e77d3 422 baseValue.m_structure.set(),
81345200 423 m_graph.identifiers()[identifierNumber],
93a37866
A
424 node->op() == PutByIdDirect);
425
81345200
A
426 if (!status.isSimple())
427 break;
ed1e77d3
A
428
429 ASSERT(status.numVariants());
430
431 if (status.numVariants() > 1 && !isFTL(m_graph.m_plan.mode))
432 break;
433
434 changed = true;
435
436 for (unsigned i = status.numVariants(); i--;)
437 addChecks(origin, indexInBlock, status[i].constantChecks());
438
439 if (status.numVariants() == 1) {
440 emitPutByOffset(indexInBlock, node, baseValue, status[0], identifierNumber);
93a37866 441 break;
ed1e77d3 442 }
93a37866 443
ed1e77d3
A
444 ASSERT(isFTL(m_graph.m_plan.mode));
445
446 MultiPutByOffsetData* data = m_graph.m_multiPutByOffsetData.add();
447 data->variants = status.variants();
448 data->identifierNumber = identifierNumber;
449 node->convertToMultiPutByOffset(data);
93a37866
A
450 break;
451 }
81345200
A
452
453 case ToPrimitive: {
ed1e77d3 454 if (m_state.forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString | SpecSymbol))
81345200 455 break;
93a37866 456
81345200 457 node->convertToIdentity();
ed1e77d3 458 changed = true;
81345200
A
459 break;
460 }
ed1e77d3
A
461
462 case Check: {
463 alreadyHandled = true;
464 m_interpreter.execute(indexInBlock);
465 for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
466 Edge edge = node->children.child(i);
467 if (!edge)
468 break;
469 if (edge.isProved() || edge.willNotHaveCheck()) {
470 node->children.removeEdge(i--);
471 changed = true;
472 }
473 }
93a37866
A
474 break;
475 }
476
ed1e77d3
A
477 default:
478 break;
479 }
480
93a37866
A
481 if (eliminated) {
482 changed = true;
483 continue;
484 }
485
ed1e77d3
A
486 if (alreadyHandled)
487 continue;
488
81345200
A
489 m_interpreter.execute(indexInBlock);
490 if (!m_state.isValid()) {
491 // If we invalidated then we shouldn't attempt to constant-fold. Here's an
492 // example:
493 //
494 // c: JSConstant(4.2)
495 // x: ValueToInt32(Check:Int32:@const)
496 //
497 // It would be correct for an analysis to assume that execution cannot
498 // proceed past @x. Therefore, constant-folding @x could be rather bad. But,
499 // the CFA may report that it found a constant even though it also reported
500 // that everything has been invalidated. This will only happen in a couple of
501 // the constant folding cases; most of them are also separately defensive
502 // about such things.
503 break;
504 }
93a37866
A
505 if (!node->shouldGenerate() || m_state.didClobber() || node->hasConstant())
506 continue;
81345200 507
ed1e77d3
A
508 // Interesting fact: this freezing that we do right here may turn an fragile value into
509 // a weak value. See DFGValueStrength.h.
510 FrozenValue* value = m_graph.freeze(m_state.forNode(node).value());
511 if (!*value)
81345200 512 continue;
93a37866 513
ed1e77d3
A
514 if (node->op() == GetLocal) {
515 // Need to preserve bytecode liveness in ThreadedCPS form. This wouldn't be necessary
516 // if it wasn't for https://bugs.webkit.org/show_bug.cgi?id=144086.
517 m_insertionSet.insertNode(
518 indexInBlock, SpecNone, PhantomLocal, node->origin,
519 OpInfo(node->variableAccessData()));
81345200 520 m_graph.dethread();
ed1e77d3
A
521 } else
522 m_insertionSet.insertCheck(indexInBlock, node->origin, node->children);
93a37866 523 m_graph.convertToConstant(node, value);
93a37866
A
524
525 changed = true;
526 }
527 m_state.reset();
528 m_insertionSet.execute(block);
529
530 return changed;
531 }
81345200 532
ed1e77d3 533 void emitGetByOffset(unsigned indexInBlock, Node* node, const AbstractValue& baseValue, const GetByIdVariant& variant, unsigned identifierNumber)
93a37866 534 {
81345200
A
535 NodeOrigin origin = node->origin;
536 Edge childEdge = node->child1();
81345200 537
ed1e77d3 538 addBaseCheck(indexInBlock, node, baseValue, variant.structureSet());
81345200 539
ed1e77d3
A
540 JSValue baseForLoad;
541 if (variant.alternateBase())
542 baseForLoad = variant.alternateBase();
543 else
544 baseForLoad = baseValue.m_value;
545 if (JSValue value = m_graph.tryGetConstantProperty(baseForLoad, variant.baseStructure(), variant.offset())) {
546 m_graph.convertToConstant(node, m_graph.freeze(value));
81345200
A
547 return;
548 }
549
ed1e77d3
A
550 if (variant.alternateBase()) {
551 Node* child = m_insertionSet.insertConstant(indexInBlock, origin, variant.alternateBase());
552 childEdge = Edge(child, KnownCellUse);
553 } else
554 childEdge.setUseKind(KnownCellUse);
81345200
A
555
556 Edge propertyStorage;
557
558 if (isInlineOffset(variant.offset()))
559 propertyStorage = childEdge;
560 else {
561 propertyStorage = Edge(m_insertionSet.insertNode(
562 indexInBlock, SpecNone, GetButterfly, origin, childEdge));
93a37866 563 }
81345200 564
ed1e77d3
A
565 StorageAccessData& data = *m_graph.m_storageAccessData.add();
566 data.offset = variant.offset();
567 data.identifierNumber = identifierNumber;
81345200 568
ed1e77d3 569 node->convertToGetByOffset(data, propertyStorage);
93a37866 570 }
81345200 571
ed1e77d3 572 void emitPutByOffset(unsigned indexInBlock, Node* node, const AbstractValue& baseValue, const PutByIdVariant& variant, unsigned identifierNumber)
81345200
A
573 {
574 NodeOrigin origin = node->origin;
575 Edge childEdge = node->child1();
81345200 576
ed1e77d3 577 addBaseCheck(indexInBlock, node, baseValue, variant.oldStructure());
81345200
A
578
579 childEdge.setUseKind(KnownCellUse);
580
ed1e77d3 581 Transition* transition = 0;
81345200 582 if (variant.kind() == PutByIdVariant::Transition) {
ed1e77d3
A
583 transition = m_graph.m_transitions.add(
584 variant.oldStructureForTransition(), variant.newStructure());
81345200
A
585 }
586
587 Edge propertyStorage;
588
589 if (isInlineOffset(variant.offset()))
590 propertyStorage = childEdge;
ed1e77d3 591 else if (!variant.reallocatesStorage()) {
81345200
A
592 propertyStorage = Edge(m_insertionSet.insertNode(
593 indexInBlock, SpecNone, GetButterfly, origin, childEdge));
ed1e77d3 594 } else if (!variant.oldStructureForTransition()->outOfLineCapacity()) {
81345200
A
595 ASSERT(variant.newStructure()->outOfLineCapacity());
596 ASSERT(!isInlineOffset(variant.offset()));
597 Node* allocatePropertyStorage = m_insertionSet.insertNode(
598 indexInBlock, SpecNone, AllocatePropertyStorage,
ed1e77d3 599 origin, OpInfo(transition), childEdge);
81345200
A
600 propertyStorage = Edge(allocatePropertyStorage);
601 } else {
ed1e77d3
A
602 ASSERT(variant.oldStructureForTransition()->outOfLineCapacity());
603 ASSERT(variant.newStructure()->outOfLineCapacity() > variant.oldStructureForTransition()->outOfLineCapacity());
81345200
A
604 ASSERT(!isInlineOffset(variant.offset()));
605
606 Node* reallocatePropertyStorage = m_insertionSet.insertNode(
607 indexInBlock, SpecNone, ReallocatePropertyStorage, origin,
ed1e77d3 608 OpInfo(transition), childEdge,
81345200
A
609 Edge(m_insertionSet.insertNode(
610 indexInBlock, SpecNone, GetButterfly, origin, childEdge)));
81345200
A
611 propertyStorage = Edge(reallocatePropertyStorage);
612 }
613
ed1e77d3
A
614 StorageAccessData& data = *m_graph.m_storageAccessData.add();
615 data.offset = variant.offset();
616 data.identifierNumber = identifierNumber;
617
618 node->convertToPutByOffset(data, propertyStorage);
619
81345200 620 if (variant.kind() == PutByIdVariant::Transition) {
ed1e77d3
A
621 // FIXME: PutStructure goes last until we fix either
622 // https://bugs.webkit.org/show_bug.cgi?id=142921 or
623 // https://bugs.webkit.org/show_bug.cgi?id=142924.
624 m_insertionSet.insertNode(
625 indexInBlock + 1, SpecNone, PutStructure, origin, OpInfo(transition), childEdge);
81345200 626 }
81345200 627 }
ed1e77d3
A
628
629 void addBaseCheck(
630 unsigned indexInBlock, Node* node, const AbstractValue& baseValue, const StructureSet& set)
93a37866 631 {
ed1e77d3
A
632 if (!baseValue.m_structure.isSubsetOf(set)) {
633 // Arises when we prune MultiGetByOffset. We could have a
634 // MultiGetByOffset with a single variant that checks for structure S,
635 // and the input has structures S and T, for example.
93a37866 636 m_insertionSet.insertNode(
ed1e77d3
A
637 indexInBlock, SpecNone, CheckStructure, node->origin,
638 OpInfo(m_graph.addStructureSet(set)), node->child1());
93a37866
A
639 return;
640 }
ed1e77d3
A
641
642 if (baseValue.m_type & ~SpecCell)
643 m_insertionSet.insertCheck(indexInBlock, node->origin, node->child1());
644 }
645
646 void addChecks(
647 NodeOrigin origin, unsigned indexInBlock, const ConstantStructureCheckVector& checks)
648 {
649 for (unsigned i = 0; i < checks.size(); ++i) {
650 addStructureTransitionCheck(
651 origin, indexInBlock, checks[i].constant(), checks[i].structure());
652 }
653 }
93a37866 654
ed1e77d3
A
655 void addStructureTransitionCheck(NodeOrigin origin, unsigned indexInBlock, JSCell* cell, Structure* structure)
656 {
657 if (m_graph.registerStructure(cell->structure()) == StructureRegisteredAndWatched)
658 return;
659
660 m_graph.registerStructure(structure);
661
662 Node* weakConstant = m_insertionSet.insertNode(
663 indexInBlock, speculationFromValue(cell), JSConstant, origin,
664 OpInfo(m_graph.freeze(cell)));
665
93a37866 666 m_insertionSet.insertNode(
81345200 667 indexInBlock, SpecNone, CheckStructure, origin,
ed1e77d3
A
668 OpInfo(m_graph.addStructureSet(structure)), Edge(weakConstant, CellUse));
669 }
670
671 void fixUpsilons(BasicBlock* block)
672 {
673 for (unsigned nodeIndex = block->size(); nodeIndex--;) {
674 Node* node = block->at(nodeIndex);
675 if (node->op() != Upsilon)
676 continue;
677 switch (node->phi()->op()) {
678 case Phi:
679 break;
680 case JSConstant:
681 case DoubleConstant:
682 case Int52Constant:
683 node->remove();
684 break;
685 default:
686 DFG_CRASH(m_graph, node, "Bad Upsilon phi() pointer");
687 break;
688 }
689 }
93a37866
A
690 }
691
81345200
A
692 InPlaceAbstractState m_state;
693 AbstractInterpreter<InPlaceAbstractState> m_interpreter;
93a37866
A
694 InsertionSet m_insertionSet;
695};
696
697bool performConstantFolding(Graph& graph)
698{
699 SamplingRegion samplingRegion("DFG Constant Folding Phase");
700 return runPhase<ConstantFoldingPhase>(graph);
701}
702
703} } // namespace JSC::DFG
704
705#endif // ENABLE(DFG_JIT)
706
707