1/*
2 * Copyright (C) 2013-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#pragma once
27
28#if ENABLE(DFG_JIT)
29
30#include "ArrayConstructor.h"
31#include "ArrayPrototype.h"
32#include "DFGAbstractInterpreter.h"
33#include "DFGAbstractInterpreterClobberState.h"
34#include "DOMJITGetterSetter.h"
35#include "DOMJITSignature.h"
36#include "GetByStatus.h"
37#include "GetterSetter.h"
38#include "HashMapImpl.h"
39#include "JITOperations.h"
40#include "JSAsyncGenerator.h"
41#include "JSGenerator.h"
42#include "JSImmutableButterfly.h"
43#include "JSInternalPromise.h"
44#include "JSInternalPromiseConstructor.h"
45#include "JSPromiseConstructor.h"
46#include "MathCommon.h"
47#include "NumberConstructor.h"
48#include "Operations.h"
49#include "PutByIdStatus.h"
50#include "StringObject.h"
51#include "StructureCache.h"
52#include "StructureRareDataInlines.h"
53#include <wtf/BooleanLattice.h>
54#include <wtf/CheckedArithmetic.h>
55
56namespace JSC { namespace DFG {
57
58template<typename AbstractStateType>
59AbstractInterpreter<AbstractStateType>::AbstractInterpreter(Graph& graph, AbstractStateType& state)
60 : m_codeBlock(graph.m_codeBlock)
61 , m_graph(graph)
62 , m_vm(m_graph.m_vm)
63 , m_state(state)
64{
65 if (m_graph.m_form == SSA)
66 m_phiChildren = makeUnique<PhiChildren>(m_graph);
67}
68
69template<typename AbstractStateType>
70AbstractInterpreter<AbstractStateType>::~AbstractInterpreter()
71{
72}
73
74template<typename AbstractStateType>
75typename AbstractInterpreter<AbstractStateType>::BooleanResult
76AbstractInterpreter<AbstractStateType>::booleanResult(
77 Node* node, AbstractValue& value)
78{
79 JSValue childConst = value.value();
80 if (childConst) {
81 if (childConst.toBoolean(m_codeBlock->globalObjectFor(node->origin.semantic)))
82 return DefinitelyTrue;
83 return DefinitelyFalse;
84 }
85
86 // Next check if we can fold because we know that the source is an object or string and does not equal undefined.
87 if (isCellSpeculation(value.m_type) && !value.m_structure.isTop()) {
88 bool allTrue = true;
89 for (unsigned i = value.m_structure.size(); i--;) {
90 RegisteredStructure structure = value.m_structure[i];
91 if (structure->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))
92 || structure->typeInfo().type() == StringType) {
93 allTrue = false;
94 break;
95 }
96 }
97 if (allTrue)
98 return DefinitelyTrue;
99 }
100
101 return UnknownBooleanResult;
102}
103
104template<typename AbstractStateType>
105void AbstractInterpreter<AbstractStateType>::startExecuting()
106{
107 ASSERT(m_state.block());
108 ASSERT(m_state.isValid());
109
110 m_state.setClobberState(AbstractInterpreterClobberState::NotClobbered);
111}
112
113template<typename AbstractStateType>
114class AbstractInterpreterExecuteEdgesFunc {
115public:
116 AbstractInterpreterExecuteEdgesFunc(AbstractInterpreter<AbstractStateType>& interpreter)
117 : m_interpreter(interpreter)
118 {
119 }
120
121 // This func is manually written out so that we can put ALWAYS_INLINE on it.
122 ALWAYS_INLINE void operator()(Edge& edge) const
123 {
124 m_interpreter.filterEdgeByUse(edge);
125 }
126
127private:
128 AbstractInterpreter<AbstractStateType>& m_interpreter;
129};
130
131template<typename AbstractStateType>
132void AbstractInterpreter<AbstractStateType>::executeEdges(Node* node)
133{
134 m_graph.doToChildren(node, AbstractInterpreterExecuteEdgesFunc<AbstractStateType>(*this));
135}
136
137template<typename AbstractStateType>
138void AbstractInterpreter<AbstractStateType>::executeKnownEdgeTypes(Node* node)
139{
140 // Some use kinds are required to not have checks, because we know somehow that the incoming
141 // value will already have the type we want. In those cases, AI may not be smart enough to
142 // prove that this is indeed the case. But the existance of the edge is enough to prove that
143 // it is indeed the case. Taking advantage of this is not optional, since otherwise the DFG
144 // and FTL backends may emit checks in a node that lacks a valid exit origin.
145 m_graph.doToChildren(
146 node,
147 [&] (Edge& edge) {
148 if (mayHaveTypeCheck(edge.useKind()))
149 return;
150
151 filterEdgeByUse(edge);
152 });
153}
154
155template<typename AbstractStateType>
156ALWAYS_INLINE void AbstractInterpreter<AbstractStateType>::filterByType(Edge& edge, SpeculatedType type)
157{
158 AbstractValue& value = m_state.forNodeWithoutFastForward(edge);
159 if (value.isType(type)) {
160 m_state.setProofStatus(edge, IsProved);
161 return;
162 }
163 m_state.setProofStatus(edge, NeedsCheck);
164 m_state.fastForwardAndFilterUnproven(value, type);
165}
166
167template<typename AbstractStateType>
168void AbstractInterpreter<AbstractStateType>::verifyEdge(Node* node, Edge edge)
169{
170 if (!(m_state.forNodeWithoutFastForward(edge).m_type & ~typeFilterFor(edge.useKind())))
171 return;
172
173 DFG_CRASH(m_graph, node, toCString("Edge verification error: ", node, "->", edge, " was expected to have type ", SpeculationDump(typeFilterFor(edge.useKind())), " but has type ", SpeculationDump(forNode(edge).m_type), " (", forNode(edge).m_type, ")").data(), AbstractInterpreterInvalidType, node->op(), edge->op(), edge.useKind(), forNode(edge).m_type);
174}
175
176template<typename AbstractStateType>
177void AbstractInterpreter<AbstractStateType>::verifyEdges(Node* node)
178{
179 DFG_NODE_DO_TO_CHILDREN(m_graph, node, verifyEdge);
180}
181
182enum class ToThisResult {
183 Identity,
184 Undefined,
185 GlobalThis,
186 Dynamic,
187};
188inline ToThisResult isToThisAnIdentity(VM& vm, bool isStrictMode, AbstractValue& valueForNode)
189{
190 // We look at the type first since that will cover most cases and does not require iterating all the structures.
191 if (isStrictMode) {
192 if (valueForNode.m_type && !(valueForNode.m_type & SpecObjectOther))
193 return ToThisResult::Identity;
194 } else {
195 if (valueForNode.m_type && !(valueForNode.m_type & (~SpecObject | SpecObjectOther)))
196 return ToThisResult::Identity;
197 }
198
199 if (JSValue value = valueForNode.value()) {
200 if (value.isCell()) {
201 auto* toThisMethod = value.asCell()->classInfo(vm)->methodTable.toThis;
202 if (toThisMethod == &JSObject::toThis)
203 return ToThisResult::Identity;
204 if (toThisMethod == &JSScope::toThis) {
205 if (isStrictMode)
206 return ToThisResult::Undefined;
207 return ToThisResult::GlobalThis;
208 }
209 }
210 }
211
212 if ((isStrictMode || (valueForNode.m_type && !(valueForNode.m_type & ~SpecObject))) && valueForNode.m_structure.isFinite()) {
213 bool allStructuresAreJSScope = !valueForNode.m_structure.isClear();
214 bool overridesToThis = false;
215 valueForNode.m_structure.forEach([&](RegisteredStructure structure) {
216 TypeInfo type = structure->typeInfo();
217 ASSERT(type.isObject() || type.type() == StringType || type.type() == SymbolType || type.type() == BigIntType);
218 if (!isStrictMode)
219 ASSERT(type.isObject());
220 // We don't need to worry about strings/symbols here since either:
221 // 1) We are in strict mode and strings/symbols are not wrapped
222 // 2) The AI has proven that the type of this is a subtype of object
223 if (type.isObject() && type.overridesToThis())
224 overridesToThis = true;
225
226 // If all the structures are JSScope's ones, we know the details of JSScope::toThis() operation.
227 allStructuresAreJSScope &= structure->classInfo()->methodTable.toThis == JSScope::info()->methodTable.toThis;
228 });
229 if (!overridesToThis)
230 return ToThisResult::Identity;
231 if (allStructuresAreJSScope) {
232 if (isStrictMode)
233 return ToThisResult::Undefined;
234 return ToThisResult::GlobalThis;
235 }
236 }
237
238 return ToThisResult::Dynamic;
239}
240
241template<typename AbstractStateType>
242bool AbstractInterpreter<AbstractStateType>::handleConstantBinaryBitwiseOp(Node* node)
243{
244 JSValue left = forNode(node->child1()).value();
245 JSValue right = forNode(node->child2()).value();
246 if (left && right && left.isInt32() && right.isInt32()) {
247 int32_t a = left.asInt32();
248 int32_t b = right.asInt32();
249 if (node->isBinaryUseKind(UntypedUse))
250 didFoldClobberWorld();
251 NodeType op = node->op();
252 switch (op) {
253 case ValueBitAnd:
254 case ArithBitAnd:
255 setConstant(node, JSValue(a & b));
256 break;
257 case ValueBitOr:
258 case ArithBitOr:
259 setConstant(node, JSValue(a | b));
260 break;
261 case ValueBitXor:
262 case ArithBitXor:
263 setConstant(node, JSValue(a ^ b));
264 break;
265 case ArithBitRShift:
266 case ValueBitRShift:
267 setConstant(node, JSValue(a >> (static_cast<uint32_t>(b) & 0x1f)));
268 break;
269 case ValueBitLShift:
270 case ArithBitLShift:
271 setConstant(node, JSValue(a << (static_cast<uint32_t>(b) & 0x1f)));
272 break;
273 case BitURShift:
274 setConstant(node, JSValue(static_cast<int32_t>(static_cast<uint32_t>(a) >> (static_cast<uint32_t>(b) & 0x1f))));
275 break;
276 default:
277 RELEASE_ASSERT_NOT_REACHED();
278 break;
279 }
280
281 return true;
282 }
283
284 return false;
285}
286
287template<typename AbstractStateType>
288bool AbstractInterpreter<AbstractStateType>::handleConstantDivOp(Node* node)
289{
290 JSValue left = forNode(node->child1()).value();
291 JSValue right = forNode(node->child2()).value();
292
293 if (left && right) {
294 NodeType op = node->op();
295 bool isDivOperation = op == ValueDiv || op == ArithDiv;
296
297 // Only possible case of ValueOp below is UntypedUse,
298 // so we need to reflect clobberize rules.
299 bool isClobbering = op == ValueDiv || op == ValueMod;
300
301 if (left.isInt32() && right.isInt32()) {
302 double doubleResult;
303 if (isDivOperation)
304 doubleResult = left.asNumber() / right.asNumber();
305 else
306 doubleResult = fmod(left.asNumber(), right.asNumber());
307
308 if (node->hasArithMode()) {
309 if (!shouldCheckOverflow(node->arithMode()))
310 doubleResult = toInt32(doubleResult);
311 else if (!shouldCheckNegativeZero(node->arithMode()))
312 doubleResult += 0; // Sanitizes zero.
313 }
314
315 JSValue valueResult = jsNumber(doubleResult);
316 if (valueResult.isInt32()) {
317 if (isClobbering)
318 didFoldClobberWorld();
319 setConstant(node, valueResult);
320 return true;
321 }
322 } else if (left.isNumber() && right.isNumber()) {
323 if (isClobbering)
324 didFoldClobberWorld();
325
326 if (isDivOperation)
327 setConstant(node, jsDoubleNumber(left.asNumber() / right.asNumber()));
328 else
329 setConstant(node, jsDoubleNumber(fmod(left.asNumber(), right.asNumber())));
330
331 return true;
332 }
333 }
334
335 return false;
336}
337
338template<typename AbstractStateType>
339bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimit, Node* node)
340{
341 verifyEdges(node);
342
343 m_state.createValueForNode(node);
344
345 switch (node->op()) {
346 case JSConstant:
347 case DoubleConstant:
348 case Int52Constant: {
349 setBuiltInConstant(node, *node->constant());
350 break;
351 }
352
353 case LazyJSConstant: {
354 LazyJSValue value = node->lazyJSValue();
355 switch (value.kind()) {
356 case LazyJSValue::KnownValue:
357 setConstant(node, value.value()->value());
358 break;
359 case LazyJSValue::SingleCharacterString:
360 case LazyJSValue::KnownStringImpl:
361 case LazyJSValue::NewStringImpl:
362 setTypeForNode(node, SpecString);
363 break;
364 }
365 break;
366 }
367
368 case IdentityWithProfile:
369 case Identity: {
370 setForNode(node, forNode(node->child1()));
371 if (forNode(node).value())
372 m_state.setShouldTryConstantFolding(true);
373 break;
374 }
375
376 case ExtractCatchLocal:
377 case ExtractOSREntryLocal: {
378 makeBytecodeTopForNode(node);
379 break;
380 }
381
382 case GetLocal: {
383 VariableAccessData* variableAccessData = node->variableAccessData();
384 AbstractValue value = m_state.operand(variableAccessData->local().offset());
385 // The value in the local should already be checked.
386 DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(variableAccessData->flushFormat())));
387 if (value.value())
388 m_state.setShouldTryConstantFolding(true);
389 setForNode(node, value);
390 break;
391 }
392
393 case GetStack: {
394 StackAccessData* data = node->stackAccessData();
395 AbstractValue value = m_state.operand(data->local);
396 // The value in the local should already be checked.
397 DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(data->format)));
398 if (value.value())
399 m_state.setShouldTryConstantFolding(true);
400 setForNode(node, value);
401 break;
402 }
403
404 case SetLocal: {
405 m_state.operand(node->local()) = forNode(node->child1());
406 break;
407 }
408
409 case PutStack: {
410 m_state.operand(node->stackAccessData()->local) = forNode(node->child1());
411 break;
412 }
413
414 case MovHint: {
415 // Don't need to do anything. A MovHint only informs us about what would have happened
416 // in bytecode, but this code is just concerned with what is actually happening during
417 // DFG execution.
418 break;
419 }
420
421 case KillStack: {
422 // This is just a hint telling us that the OSR state of the local is no longer inside the
423 // flushed data.
424 break;
425 }
426
427 case SetArgumentDefinitely:
428 case SetArgumentMaybe:
429 // Assert that the state of arguments has been set. SetArgumentDefinitely/SetArgumentMaybe means
430 // that someone set the argument values out-of-band, and currently this always means setting to a
431 // non-clear value.
432 ASSERT(!m_state.operand(node->local()).isClear());
433 break;
434
435 case InitializeEntrypointArguments: {
436 unsigned entrypointIndex = node->entrypointIndex();
437 const Vector<FlushFormat>& argumentFormats = m_graph.m_argumentFormats[entrypointIndex];
438 for (unsigned argument = 0; argument < argumentFormats.size(); ++argument) {
439 AbstractValue& value = m_state.argument(argument);
440 switch (argumentFormats[argument]) {
441 case FlushedInt32:
442 value.setNonCellType(SpecInt32Only);
443 break;
444 case FlushedBoolean:
445 value.setNonCellType(SpecBoolean);
446 break;
447 case FlushedCell:
448 value.setType(m_graph, SpecCellCheck);
449 break;
450 case FlushedJSValue:
451 value.makeBytecodeTop();
452 break;
453 default:
454 DFG_CRASH(m_graph, node, "Bad flush format for argument");
455 break;
456 }
457 }
458 break;
459 }
460
461 case LoadVarargs:
462 case ForwardVarargs: {
463 // FIXME: ForwardVarargs should check if the count becomes known, and if it does, it should turn
464 // itself into a straight-line sequence of GetStack/PutStack.
465 // https://bugs.webkit.org/show_bug.cgi?id=143071
466 switch (node->op()) {
467 case LoadVarargs:
468 clobberWorld();
469 break;
470 case ForwardVarargs:
471 break;
472 default:
473 DFG_CRASH(m_graph, node, "Bad opcode");
474 break;
475 }
476 LoadVarargsData* data = node->loadVarargsData();
477 m_state.operand(data->count).setNonCellType(SpecInt32Only);
478 for (unsigned i = data->limit - 1; i--;)
479 m_state.operand(data->start.offset() + i).makeHeapTop();
480 break;
481 }
482
483 case ValueBitNot: {
484 JSValue operand = forNode(node->child1()).value();
485 if (operand && operand.isInt32()) {
486 didFoldClobberWorld();
487 int32_t a = operand.asInt32();
488 setConstant(node, JSValue(~a));
489 break;
490 }
491
492 if (node->child1().useKind() == BigIntUse)
493 setTypeForNode(node, SpecBigInt);
494 else {
495 clobberWorld();
496 setTypeForNode(node, SpecInt32Only | SpecBigInt);
497 }
498
499 break;
500 }
501
502 case ArithBitNot: {
503 JSValue operand = forNode(node->child1()).value();
504 if (operand && operand.isInt32()) {
505 int32_t a = operand.asInt32();
506 setConstant(node, JSValue(~a));
507 break;
508 }
509
510 setNonCellTypeForNode(node, SpecInt32Only);
511 break;
512 }
513
514 case ValueBitXor:
515 case ValueBitAnd:
516 case ValueBitOr:
517 case ValueBitRShift:
518 case ValueBitLShift: {
519 if (handleConstantBinaryBitwiseOp(node))
520 break;
521
522 if (node->binaryUseKind() == BigIntUse)
523 setTypeForNode(node, SpecBigInt);
524 else {
525 clobberWorld();
526 setTypeForNode(node, SpecInt32Only | SpecBigInt);
527 }
528 break;
529 }
530
531 case ArithBitAnd:
532 case ArithBitOr:
533 case ArithBitXor:
534 case ArithBitRShift:
535 case ArithBitLShift:
536 case BitURShift: {
537 if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
538 clobberWorld();
539 setNonCellTypeForNode(node, SpecInt32Only);
540 break;
541 }
542
543 if (handleConstantBinaryBitwiseOp(node))
544 break;
545
546 if (node->op() == ArithBitAnd
547 && (isBoolInt32Speculation(forNode(node->child1()).m_type) ||
548 isBoolInt32Speculation(forNode(node->child2()).m_type))) {
549 setNonCellTypeForNode(node, SpecBoolInt32);
550 break;
551 }
552
553 setNonCellTypeForNode(node, SpecInt32Only);
554 break;
555 }
556
557 case UInt32ToNumber: {
558 JSValue child = forNode(node->child1()).value();
559 if (doesOverflow(node->arithMode())) {
560 if (enableInt52()) {
561 if (child && child.isAnyInt()) {
562 int64_t machineInt = child.asAnyInt();
563 setConstant(node, jsNumber(static_cast<uint32_t>(machineInt)));
564 break;
565 }
566 setNonCellTypeForNode(node, SpecInt52Any);
567 break;
568 }
569 if (child && child.isInt32()) {
570 uint32_t value = child.asInt32();
571 setConstant(node, jsNumber(value));
572 break;
573 }
574 setNonCellTypeForNode(node, SpecAnyIntAsDouble);
575 break;
576 }
577 if (child && child.isInt32()) {
578 int32_t value = child.asInt32();
579 if (value >= 0) {
580 setConstant(node, jsNumber(value));
581 break;
582 }
583 }
584 setNonCellTypeForNode(node, SpecInt32Only);
585 break;
586 }
587
588 case BooleanToNumber: {
589 JSValue concreteValue = forNode(node->child1()).value();
590 if (concreteValue) {
591 if (concreteValue.isBoolean())
592 setConstant(node, jsNumber(concreteValue.asBoolean()));
593 else
594 setConstant(node, *m_graph.freeze(concreteValue));
595 break;
596 }
597 AbstractValue& value = forNode(node);
598 value = forNode(node->child1());
599 if (node->child1().useKind() == UntypedUse && !(value.m_type & ~SpecBoolean))
600 m_state.setShouldTryConstantFolding(true);
601 if (value.m_type & SpecBoolean) {
602 value.merge(SpecBoolInt32);
603 value.filter(~SpecBoolean);
604 }
605 break;
606 }
607
608 case DoubleAsInt32: {
609 JSValue child = forNode(node->child1()).value();
610 if (child && child.isNumber()) {
611 double asDouble = child.asNumber();
612 int32_t asInt = JSC::toInt32(asDouble);
613 if (bitwise_cast<int64_t>(static_cast<double>(asInt)) == bitwise_cast<int64_t>(asDouble)) {
614 setConstant(node, JSValue(asInt));
615 break;
616 }
617 }
618 setNonCellTypeForNode(node, SpecInt32Only);
619 break;
620 }
621
622 case ValueToInt32: {
623 JSValue child = forNode(node->child1()).value();
624 if (child) {
625 if (child.isNumber()) {
626 if (child.isInt32())
627 setConstant(node, child);
628 else
629 setConstant(node, JSValue(JSC::toInt32(child.asDouble())));
630 break;
631 }
632 if (child.isBoolean()) {
633 setConstant(node, jsNumber(child.asBoolean()));
634 break;
635 }
636 if (child.isUndefinedOrNull()) {
637 setConstant(node, jsNumber(0));
638 break;
639 }
640 }
641
642 if (isBooleanSpeculation(forNode(node->child1()).m_type)) {
643 setNonCellTypeForNode(node, SpecBoolInt32);
644 break;
645 }
646
647 setNonCellTypeForNode(node, SpecInt32Only);
648 break;
649 }
650
651 case DoubleRep: {
652 JSValue child = forNode(node->child1()).value();
653 if (Optional<double> number = child.toNumberFromPrimitive()) {
654 setConstant(node, jsDoubleNumber(*number));
655 break;
656 }
657
658 SpeculatedType type = forNode(node->child1()).m_type;
659 switch (node->child1().useKind()) {
660 case NotCellUse: {
661 if (type & SpecOther) {
662 type &= ~SpecOther;
663 type |= SpecDoublePureNaN | SpecBoolInt32; // Null becomes zero, undefined becomes NaN.
664 }
665 if (type & SpecBoolean) {
666 type &= ~SpecBoolean;
667 type |= SpecBoolInt32; // True becomes 1, false becomes 0.
668 }
669 type &= SpecBytecodeNumber;
670 break;
671 }
672
673 case Int52RepUse:
674 case NumberUse:
675 case RealNumberUse:
676 break;
677
678 default:
679 RELEASE_ASSERT_NOT_REACHED();
680 }
681 setNonCellTypeForNode(node, type);
682 forNode(node).fixTypeForRepresentation(m_graph, node);
683 break;
684 }
685
686 case Int52Rep: {
687 JSValue child = forNode(node->child1()).value();
688 if (child && child.isAnyInt()) {
689 setConstant(node, child);
690 break;
691 }
692
693 setTypeForNode(node, forNode(node->child1()).m_type);
694 forNode(node).fixTypeForRepresentation(m_graph, node);
695 break;
696 }
697
698 case ValueRep: {
699 JSValue value = forNode(node->child1()).value();
700 if (value) {
701 setConstant(node, value);
702 break;
703 }
704
705 setTypeForNode(node, forNode(node->child1()).m_type & ~SpecDoubleImpureNaN);
706 forNode(node).fixTypeForRepresentation(m_graph, node);
707 break;
708 }
709
710 case ValueSub:
711 case ValueAdd: {
712 DFG_ASSERT(m_graph, node, node->binaryUseKind() == UntypedUse || node->binaryUseKind() == BigIntUse);
713 if (node->binaryUseKind() == BigIntUse)
714 setTypeForNode(node, SpecBigInt);
715 else {
716 clobberWorld();
717 setTypeForNode(node, SpecString | SpecBytecodeNumber | SpecBigInt);
718 }
719 break;
720 }
721
722 case StrCat: {
723 setTypeForNode(node, SpecString);
724 break;
725 }
726
727 case ArithAdd: {
728 JSValue left = forNode(node->child1()).value();
729 JSValue right = forNode(node->child2()).value();
730 switch (node->binaryUseKind()) {
731 case Int32Use:
732 if (left && right && left.isInt32() && right.isInt32()) {
733 if (!shouldCheckOverflow(node->arithMode())) {
734 setConstant(node, jsNumber(left.asInt32() + right.asInt32()));
735 break;
736 }
737 JSValue result = jsNumber(left.asNumber() + right.asNumber());
738 if (result.isInt32()) {
739 setConstant(node, result);
740 break;
741 }
742 }
743 setNonCellTypeForNode(node, SpecInt32Only);
744 break;
745 case Int52RepUse:
746 if (left && right && left.isAnyInt() && right.isAnyInt()) {
747 JSValue result = jsNumber(left.asAnyInt() + right.asAnyInt());
748 if (result.isAnyInt()) {
749 setConstant(node, result);
750 break;
751 }
752 }
753 setNonCellTypeForNode(node, SpecInt52Any);
754 break;
755 case DoubleRepUse:
756 if (left && right && left.isNumber() && right.isNumber()) {
757 setConstant(node, jsDoubleNumber(left.asNumber() + right.asNumber()));
758 break;
759 }
760 setNonCellTypeForNode(node,
761 typeOfDoubleSum(
762 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
763 break;
764 default:
765 RELEASE_ASSERT_NOT_REACHED();
766 break;
767 }
768 break;
769 }
770
771 case AtomicsIsLockFree: {
772 if (node->child1().useKind() != Int32Use)
773 clobberWorld();
774 setNonCellTypeForNode(node, SpecBoolInt32);
775 break;
776 }
777
778 case ArithClz32: {
779 JSValue operand = forNode(node->child1()).value();
780 if (Optional<double> number = operand.toNumberFromPrimitive()) {
781 switch (node->child1().useKind()) {
782 case Int32Use:
783 case KnownInt32Use:
784 break;
785 default:
786 didFoldClobberWorld();
787 break;
788 }
789 uint32_t value = toUInt32(*number);
790 setConstant(node, jsNumber(clz(value)));
791 break;
792 }
793 switch (node->child1().useKind()) {
794 case Int32Use:
795 case KnownInt32Use:
796 break;
797 default:
798 clobberWorld();
799 break;
800 }
801 setNonCellTypeForNode(node, SpecInt32Only);
802 break;
803 }
804
805 case MakeRope: {
806 unsigned numberOfRemovedChildren = 0;
807 for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
808 Edge& edge = node->children.child(i);
809 if (!edge)
810 break;
811 JSValue childConstant = m_state.forNode(edge).value();
812 if (!childConstant)
813 continue;
814 if (!childConstant.isString())
815 continue;
816 if (asString(childConstant)->length())
817 continue;
818 ++numberOfRemovedChildren;
819 }
820
821 if (numberOfRemovedChildren)
822 m_state.setShouldTryConstantFolding(true);
823 setForNode(node, m_vm.stringStructure.get());
824 break;
825 }
826
827 case ArithSub: {
828 JSValue left = forNode(node->child1()).value();
829 JSValue right = forNode(node->child2()).value();
830 switch (node->binaryUseKind()) {
831 case Int32Use:
832 if (left && right && left.isInt32() && right.isInt32()) {
833 if (!shouldCheckOverflow(node->arithMode())) {
834 setConstant(node, jsNumber(left.asInt32() - right.asInt32()));
835 break;
836 }
837 JSValue result = jsNumber(left.asNumber() - right.asNumber());
838 if (result.isInt32()) {
839 setConstant(node, result);
840 break;
841 }
842 }
843 setNonCellTypeForNode(node, SpecInt32Only);
844 break;
845 case Int52RepUse:
846 if (left && right && left.isAnyInt() && right.isAnyInt()) {
847 JSValue result = jsNumber(left.asAnyInt() - right.asAnyInt());
848 if (result.isAnyInt()) {
849 setConstant(node, result);
850 break;
851 }
852 }
853 setNonCellTypeForNode(node, SpecInt52Any);
854 break;
855 case DoubleRepUse:
856 if (left && right && left.isNumber() && right.isNumber()) {
857 setConstant(node, jsDoubleNumber(left.asNumber() - right.asNumber()));
858 break;
859 }
860 setNonCellTypeForNode(node,
861 typeOfDoubleDifference(
862 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
863 break;
864 case UntypedUse:
865 clobberWorld();
866 setNonCellTypeForNode(node, SpecBytecodeNumber);
867 break;
868 default:
869 RELEASE_ASSERT_NOT_REACHED();
870 break;
871 }
872 break;
873 }
874
875 case ValueNegate: {
876 clobberWorld();
877 setTypeForNode(node, SpecBytecodeNumber | SpecBigInt);
878 break;
879 }
880
881 case ArithNegate: {
882 JSValue child = forNode(node->child1()).value();
883 switch (node->child1().useKind()) {
884 case Int32Use:
885 if (child && child.isInt32()) {
886 if (!shouldCheckOverflow(node->arithMode())) {
887 setConstant(node, jsNumber(-child.asInt32()));
888 break;
889 }
890 double doubleResult;
891 if (shouldCheckNegativeZero(node->arithMode()))
892 doubleResult = -child.asNumber();
893 else
894 doubleResult = 0 - child.asNumber();
895 JSValue valueResult = jsNumber(doubleResult);
896 if (valueResult.isInt32()) {
897 setConstant(node, valueResult);
898 break;
899 }
900 }
901 setNonCellTypeForNode(node, SpecInt32Only);
902 break;
903 case Int52RepUse:
904 if (child && child.isAnyInt()) {
905 double doubleResult;
906 if (shouldCheckNegativeZero(node->arithMode()))
907 doubleResult = -child.asNumber();
908 else
909 doubleResult = 0 - child.asNumber();
910 JSValue valueResult = jsNumber(doubleResult);
911 if (valueResult.isAnyInt()) {
912 setConstant(node, valueResult);
913 break;
914 }
915 }
916 setNonCellTypeForNode(node, SpecInt52Any);
917 break;
918 case DoubleRepUse:
919 if (child && child.isNumber()) {
920 setConstant(node, jsDoubleNumber(-child.asNumber()));
921 break;
922 }
923 setNonCellTypeForNode(node,
924 typeOfDoubleNegation(
925 forNode(node->child1()).m_type));
926 break;
927 default:
928 RELEASE_ASSERT_NOT_REACHED();
929 break;
930 }
931 break;
932 }
933
934 case Inc:
935 case Dec: {
936 // FIXME: support some form of constant folding here.
937 // https://bugs.webkit.org/show_bug.cgi?id=204258
938 switch (node->child1().useKind()) {
939 case Int32Use:
940 setNonCellTypeForNode(node, SpecInt32Only);
941 break;
942 case Int52RepUse:
943 setNonCellTypeForNode(node, SpecInt52Any);
944 break;
945 case DoubleRepUse:
946 setNonCellTypeForNode(node, typeOfDoubleIncOrDec(forNode(node->child1()).m_type));
947 break;
948 case BigIntUse:
949 setTypeForNode(node, SpecBigInt);
950 break;
951 default:
952 setTypeForNode(node, SpecBytecodeNumber | SpecBigInt);
953 clobberWorld(); // Because of the call to ToNumeric()
954 break;
955 }
956 break;
957 }
958
959 case ValuePow: {
960 JSValue childX = forNode(node->child1()).value();
961 JSValue childY = forNode(node->child2()).value();
962 if (childX && childY && childX.isNumber() && childY.isNumber()) {
963 // We need to call `didFoldClobberWorld` here because this path is only possible
964 // when node->useKind is UntypedUse. In the case of BigIntUse, children will be
965 // cleared by `AbstractInterpreter::executeEffects`.
966 didFoldClobberWorld();
967 // Our boxing scheme here matches what we do in operationValuePow.
968 setConstant(node, jsNumber(operationMathPow(childX.asNumber(), childY.asNumber())));
969 break;
970 }
971
972 if (node->binaryUseKind() == BigIntUse)
973 setTypeForNode(node, SpecBigInt);
974 else {
975 clobberWorld();
976 setTypeForNode(node, SpecBytecodeNumber | SpecBigInt);
977 }
978 break;
979 }
980
981 case ValueMul: {
982 if (node->binaryUseKind() == BigIntUse)
983 setTypeForNode(node, SpecBigInt);
984 else {
985 clobberWorld();
986 setTypeForNode(node, SpecBytecodeNumber | SpecBigInt);
987 }
988 break;
989 }
990
991 case ArithMul: {
992 JSValue left = forNode(node->child1()).value();
993 JSValue right = forNode(node->child2()).value();
994 switch (node->binaryUseKind()) {
995 case Int32Use:
996 if (left && right && left.isInt32() && right.isInt32()) {
997 if (!shouldCheckOverflow(node->arithMode())) {
998 setConstant(node, jsNumber(left.asInt32() * right.asInt32()));
999 break;
1000 }
1001 double doubleResult = left.asNumber() * right.asNumber();
1002 if (!shouldCheckNegativeZero(node->arithMode()))
1003 doubleResult += 0; // Sanitizes zero.
1004 JSValue valueResult = jsNumber(doubleResult);
1005 if (valueResult.isInt32()) {
1006 setConstant(node, valueResult);
1007 break;
1008 }
1009 }
1010 setNonCellTypeForNode(node, SpecInt32Only);
1011 break;
1012 case Int52RepUse:
1013 if (left && right && left.isAnyInt() && right.isAnyInt()) {
1014 double doubleResult = left.asNumber() * right.asNumber();
1015 if (!shouldCheckNegativeZero(node->arithMode()))
1016 doubleResult += 0;
1017 JSValue valueResult = jsNumber(doubleResult);
1018 if (valueResult.isAnyInt()) {
1019 setConstant(node, valueResult);
1020 break;
1021 }
1022 }
1023 setNonCellTypeForNode(node, SpecInt52Any);
1024 break;
1025 case DoubleRepUse:
1026 if (left && right && left.isNumber() && right.isNumber()) {
1027 setConstant(node, jsDoubleNumber(left.asNumber() * right.asNumber()));
1028 break;
1029 }
1030 setNonCellTypeForNode(node,
1031 typeOfDoubleProduct(
1032 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
1033 break;
1034 default:
1035 RELEASE_ASSERT_NOT_REACHED();
1036 break;
1037 }
1038 break;
1039 }
1040
1041 case ValueMod:
1042 case ValueDiv: {
1043 if (handleConstantDivOp(node))
1044 break;
1045
1046 if (node->binaryUseKind() == BigIntUse)
1047 setTypeForNode(node, SpecBigInt);
1048 else {
1049 clobberWorld();
1050 setTypeForNode(node, SpecBytecodeNumber | SpecBigInt);
1051 }
1052 break;
1053 }
1054
1055 case ArithMod:
1056 case ArithDiv: {
1057 if (handleConstantDivOp(node))
1058 break;
1059
1060 switch (node->binaryUseKind()) {
1061 case Int32Use:
1062 setNonCellTypeForNode(node, SpecInt32Only);
1063 break;
1064 case DoubleRepUse:
1065 if (node->op() == ArithDiv) {
1066 setNonCellTypeForNode(node,
1067 typeOfDoubleQuotient(
1068 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
1069 } else {
1070 setNonCellTypeForNode(node,
1071 typeOfDoubleBinaryOp(
1072 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
1073 }
1074
1075 break;
1076 default:
1077 RELEASE_ASSERT_NOT_REACHED();
1078 break;
1079 }
1080 break;
1081 }
1082
1083 case ArithMin: {
1084 JSValue left = forNode(node->child1()).value();
1085 JSValue right = forNode(node->child2()).value();
1086 switch (node->binaryUseKind()) {
1087 case Int32Use:
1088 if (left && right && left.isInt32() && right.isInt32()) {
1089 setConstant(node, jsNumber(std::min(left.asInt32(), right.asInt32())));
1090 break;
1091 }
1092 setNonCellTypeForNode(node, SpecInt32Only);
1093 break;
1094 case DoubleRepUse:
1095 if (left && right && left.isNumber() && right.isNumber()) {
1096 double a = left.asNumber();
1097 double b = right.asNumber();
1098 setConstant(node, jsDoubleNumber(a < b ? a : (b <= a ? b : a + b)));
1099 break;
1100 }
1101 setNonCellTypeForNode(node,
1102 typeOfDoubleMinMax(
1103 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
1104 break;
1105 default:
1106 RELEASE_ASSERT_NOT_REACHED();
1107 break;
1108 }
1109 break;
1110 }
1111
1112 case ArithMax: {
1113 JSValue left = forNode(node->child1()).value();
1114 JSValue right = forNode(node->child2()).value();
1115 switch (node->binaryUseKind()) {
1116 case Int32Use:
1117 if (left && right && left.isInt32() && right.isInt32()) {
1118 setConstant(node, jsNumber(std::max(left.asInt32(), right.asInt32())));
1119 break;
1120 }
1121 setNonCellTypeForNode(node, SpecInt32Only);
1122 break;
1123 case DoubleRepUse:
1124 if (left && right && left.isNumber() && right.isNumber()) {
1125 double a = left.asNumber();
1126 double b = right.asNumber();
1127 setConstant(node, jsDoubleNumber(a > b ? a : (b >= a ? b : a + b)));
1128 break;
1129 }
1130 setNonCellTypeForNode(node,
1131 typeOfDoubleMinMax(
1132 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
1133 break;
1134 default:
1135 RELEASE_ASSERT_NOT_REACHED();
1136 break;
1137 }
1138 break;
1139 }
1140
1141 case ArithAbs: {
1142 JSValue child = forNode(node->child1()).value();
1143 switch (node->child1().useKind()) {
1144 case Int32Use:
1145 if (Optional<double> number = child.toNumberFromPrimitive()) {
1146 JSValue result = jsNumber(fabs(*number));
1147 if (result.isInt32()) {
1148 setConstant(node, result);
1149 break;
1150 }
1151 }
1152 setNonCellTypeForNode(node, SpecInt32Only);
1153 break;
1154 case DoubleRepUse:
1155 if (Optional<double> number = child.toNumberFromPrimitive()) {
1156 setConstant(node, jsDoubleNumber(fabs(*number)));
1157 break;
1158 }
1159 setNonCellTypeForNode(node, typeOfDoubleAbs(forNode(node->child1()).m_type));
1160 break;
1161 default:
1162 DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse, node->child1().useKind());
1163 clobberWorld();
1164 setNonCellTypeForNode(node, SpecBytecodeNumber);
1165 break;
1166 }
1167 break;
1168 }
1169
1170 case ArithPow: {
1171 JSValue childY = forNode(node->child2()).value();
1172 if (childY && childY.isNumber()) {
1173 if (!childY.asNumber()) {
1174 setConstant(node, jsDoubleNumber(1));
1175 break;
1176 }
1177
1178 JSValue childX = forNode(node->child1()).value();
1179 if (childX && childX.isNumber()) {
1180 setConstant(node, jsDoubleNumber(operationMathPow(childX.asNumber(), childY.asNumber())));
1181 break;
1182 }
1183 }
1184 setNonCellTypeForNode(node, typeOfDoublePow(forNode(node->child1()).m_type, forNode(node->child2()).m_type));
1185 break;
1186 }
1187
1188 case ArithRandom: {
1189 setNonCellTypeForNode(node, SpecDoubleReal);
1190 break;
1191 }
1192
1193 case ArithRound:
1194 case ArithFloor:
1195 case ArithCeil:
1196 case ArithTrunc: {
1197 JSValue operand = forNode(node->child1()).value();
1198 if (Optional<double> number = operand.toNumberFromPrimitive()) {
1199 if (node->child1().useKind() != DoubleRepUse)
1200 didFoldClobberWorld();
1201
1202 double roundedValue = 0;
1203 if (node->op() == ArithRound)
1204 roundedValue = jsRound(*number);
1205 else if (node->op() == ArithFloor)
1206 roundedValue = floor(*number);
1207 else if (node->op() == ArithCeil)
1208 roundedValue = ceil(*number);
1209 else {
1210 ASSERT(node->op() == ArithTrunc);
1211 roundedValue = trunc(*number);
1212 }
1213
1214 if (node->child1().useKind() == UntypedUse) {
1215 setConstant(node, jsNumber(roundedValue));
1216 break;
1217 }
1218 if (producesInteger(node->arithRoundingMode())) {
1219 int32_t roundedValueAsInt32 = static_cast<int32_t>(roundedValue);
1220 if (roundedValueAsInt32 == roundedValue) {
1221 if (shouldCheckNegativeZero(node->arithRoundingMode())) {
1222 if (roundedValueAsInt32 || !std::signbit(roundedValue)) {
1223 setConstant(node, jsNumber(roundedValueAsInt32));
1224 break;
1225 }
1226 } else {
1227 setConstant(node, jsNumber(roundedValueAsInt32));
1228 break;
1229 }
1230 }
1231 } else {
1232 setConstant(node, jsDoubleNumber(roundedValue));
1233 break;
1234 }
1235 }
1236 if (node->child1().useKind() == DoubleRepUse) {
1237 if (producesInteger(node->arithRoundingMode()))
1238 setNonCellTypeForNode(node, SpecInt32Only);
1239 else if (node->child1().useKind() == DoubleRepUse)
1240 setNonCellTypeForNode(node, typeOfDoubleRounding(forNode(node->child1()).m_type));
1241 } else {
1242 DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse, node->child1().useKind());
1243 clobberWorld();
1244 setNonCellTypeForNode(node, SpecBytecodeNumber);
1245 }
1246 break;
1247 }
1248
1249 case ArithSqrt:
1250 executeDoubleUnaryOpEffects(node, sqrt);
1251 break;
1252
1253 case ArithFRound:
1254 executeDoubleUnaryOpEffects(node, [](double value) -> double { return static_cast<float>(value); });
1255 break;
1256
1257 case ArithUnary:
1258 executeDoubleUnaryOpEffects(node, arithUnaryFunction(node->arithUnaryType()));
1259 break;
1260
1261 case LogicalNot: {
1262 switch (booleanResult(node, forNode(node->child1()))) {
1263 case DefinitelyTrue:
1264 setConstant(node, jsBoolean(false));
1265 break;
1266 case DefinitelyFalse:
1267 setConstant(node, jsBoolean(true));
1268 break;
1269 default:
1270 setNonCellTypeForNode(node, SpecBoolean);
1271 break;
1272 }
1273 break;
1274 }
1275
1276 case MapHash: {
1277 if (JSValue key = forNode(node->child1()).value()) {
1278 if (Optional<uint32_t> hash = concurrentJSMapHash(key)) {
1279 // Although C++ code uses uint32_t for the hash, the closest type in DFG IR is Int32
1280 // and that's what MapHash returns. So, we have to cast to int32_t to avoid large
1281 // unsigned values becoming doubles. This casting between signed and unsigned
1282 // happens in the assembly code we emit when we don't constant fold this node.
1283 setConstant(node, jsNumber(static_cast<int32_t>(*hash)));
1284 break;
1285 }
1286 }
1287 setNonCellTypeForNode(node, SpecInt32Only);
1288 break;
1289 }
1290
1291 case NormalizeMapKey: {
1292 if (JSValue key = forNode(node->child1()).value()) {
1293 setConstant(node, *m_graph.freeze(normalizeMapKey(key)));
1294 break;
1295 }
1296
1297 SpeculatedType typeMaybeNormalized = (SpecFullNumber & ~SpecInt32Only);
1298 if (!(forNode(node->child1()).m_type & typeMaybeNormalized)) {
1299 m_state.setShouldTryConstantFolding(true);
1300 forNode(node) = forNode(node->child1());
1301 break;
1302 }
1303
1304 makeHeapTopForNode(node);
1305 break;
1306 }
1307
1308 case StringValueOf: {
1309 clobberWorld();
1310 setTypeForNode(node, SpecString);
1311 break;
1312 }
1313
1314 case StringSlice: {
1315 setTypeForNode(node, SpecString);
1316 break;
1317 }
1318
1319 case ToLowerCase: {
1320 setTypeForNode(node, SpecString);
1321 break;
1322 }
1323
1324 case LoadKeyFromMapBucket:
1325 case LoadValueFromMapBucket:
1326 case ExtractValueFromWeakMapGet:
1327 makeHeapTopForNode(node);
1328 break;
1329
1330 case GetMapBucket:
1331 case GetMapBucketHead:
1332 if (node->child1().useKind() == MapObjectUse)
1333 setForNode(node, m_vm.hashMapBucketMapStructure.get());
1334 else {
1335 ASSERT(node->child1().useKind() == SetObjectUse);
1336 setForNode(node, m_vm.hashMapBucketSetStructure.get());
1337 }
1338 break;
1339
1340 case GetMapBucketNext:
1341 if (node->bucketOwnerType() == BucketOwnerType::Map)
1342 setForNode(node, m_vm.hashMapBucketMapStructure.get());
1343 else {
1344 ASSERT(node->bucketOwnerType() == BucketOwnerType::Set);
1345 setForNode(node, m_vm.hashMapBucketSetStructure.get());
1346 }
1347 break;
1348
1349 case SetAdd:
1350 setForNode(node, m_vm.hashMapBucketSetStructure.get());
1351 break;
1352
1353 case MapSet:
1354 setForNode(node, m_vm.hashMapBucketMapStructure.get());
1355 break;
1356
1357 case WeakSetAdd:
1358 case WeakMapSet:
1359 break;
1360
1361 case WeakMapGet:
1362 makeBytecodeTopForNode(node);
1363 break;
1364
1365 case IsEmpty:
1366 case IsUndefined:
1367 case IsUndefinedOrNull:
1368 case IsBoolean:
1369 case IsNumber:
1370 case NumberIsInteger:
1371 case IsObject:
1372 case IsObjectOrNull:
1373 case IsFunction:
1374 case IsCellWithType:
1375 case IsTypedArrayView: {
1376 AbstractValue child = forNode(node->child1());
1377 if (child.value()) {
1378 bool constantWasSet = true;
1379 switch (node->op()) {
1380 case IsCellWithType:
1381 setConstant(node, jsBoolean(child.value().isCell() && child.value().asCell()->type() == node->queriedType()));
1382 break;
1383 case IsUndefined:
1384 setConstant(node, jsBoolean(
1385 child.value().isCell()
1386 ? child.value().asCell()->structure(m_vm)->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))
1387 : child.value().isUndefined()));
1388 break;
1389 case IsUndefinedOrNull:
1390 setConstant(node, jsBoolean(child.value().isUndefinedOrNull()));
1391 break;
1392 case IsBoolean:
1393 setConstant(node, jsBoolean(child.value().isBoolean()));
1394 break;
1395 case IsNumber:
1396 setConstant(node, jsBoolean(child.value().isNumber()));
1397 break;
1398 case NumberIsInteger:
1399 setConstant(node, jsBoolean(NumberConstructor::isIntegerImpl(child.value())));
1400 break;
1401 case IsObject:
1402 setConstant(node, jsBoolean(child.value().isObject()));
1403 break;
1404 case IsObjectOrNull:
1405 if (child.value().isObject()) {
1406 JSObject* object = asObject(child.value());
1407 if (object->type() == JSFunctionType)
1408 setConstant(node, jsBoolean(false));
1409 else if (!(object->inlineTypeFlags() & OverridesGetCallData))
1410 setConstant(node, jsBoolean(!child.value().asCell()->structure(m_vm)->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))));
1411 else {
1412 // FIXME: This could just call getCallData.
1413 // https://bugs.webkit.org/show_bug.cgi?id=144457
1414 constantWasSet = false;
1415 }
1416 } else
1417 setConstant(node, jsBoolean(child.value().isNull()));
1418 break;
1419 case IsFunction:
1420 if (child.value().isObject()) {
1421 JSObject* object = asObject(child.value());
1422 if (object->type() == JSFunctionType)
1423 setConstant(node, jsBoolean(true));
1424 else if (!(object->inlineTypeFlags() & OverridesGetCallData))
1425 setConstant(node, jsBoolean(false));
1426 else {
1427 // FIXME: This could just call getCallData.
1428 // https://bugs.webkit.org/show_bug.cgi?id=144457
1429 constantWasSet = false;
1430 }
1431 } else
1432 setConstant(node, jsBoolean(false));
1433 break;
1434 case IsEmpty:
1435 setConstant(node, jsBoolean(child.value().isEmpty()));
1436 break;
1437 case IsTypedArrayView:
1438 setConstant(node, jsBoolean(child.value().isObject() && isTypedView(child.value().getObject()->classInfo(m_vm)->typedArrayStorageType)));
1439 break;
1440 default:
1441 constantWasSet = false;
1442 break;
1443 }
1444 if (constantWasSet)
1445 break;
1446 }
1447
1448 if (forNode(node->child1()).m_structure.isFinite()) {
1449 bool constantWasSet = false;
1450 switch (node->op()) {
1451 case IsCellWithType: {
1452 bool ok = true;
1453 Optional<bool> result;
1454 forNode(node->child1()).m_structure.forEach(
1455 [&](RegisteredStructure structure) {
1456 bool matched = structure->typeInfo().type() == node->queriedType();
1457 if (!result)
1458 result = matched;
1459 else {
1460 if (result.value() != matched)
1461 ok = false;
1462 }
1463 });
1464 if (ok && result) {
1465 setConstant(node, jsBoolean(result.value()));
1466 constantWasSet = true;
1467 }
1468 break;
1469 }
1470 default:
1471 break;
1472 }
1473 if (constantWasSet)
1474 break;
1475 }
1476
1477 // FIXME: This code should really use AbstractValue::isType() and
1478 // AbstractValue::couldBeType().
1479 // https://bugs.webkit.org/show_bug.cgi?id=146870
1480
1481 bool constantWasSet = false;
1482 switch (node->op()) {
1483 case IsEmpty: {
1484 if (child.m_type && !(child.m_type & SpecEmpty)) {
1485 setConstant(node, jsBoolean(false));
1486 constantWasSet = true;
1487 break;
1488 }
1489
1490 if (child.m_type && !(child.m_type & ~SpecEmpty)) {
1491 setConstant(node, jsBoolean(true));
1492 constantWasSet = true;
1493 break;
1494 }
1495
1496 break;
1497 }
1498 case IsUndefined:
1499 // FIXME: Use the masquerades-as-undefined watchpoint thingy.
1500 // https://bugs.webkit.org/show_bug.cgi?id=144456
1501
1502 if (!(child.m_type & (SpecOther | SpecObjectOther))) {
1503 setConstant(node, jsBoolean(false));
1504 constantWasSet = true;
1505 break;
1506 }
1507
1508 break;
1509 case IsUndefinedOrNull:
1510 if (!(child.m_type & ~SpecOther)) {
1511 setConstant(node, jsBoolean(true));
1512 constantWasSet = true;
1513 break;
1514 }
1515
1516 if (!(child.m_type & SpecOther)) {
1517 setConstant(node, jsBoolean(false));
1518 constantWasSet = true;
1519 break;
1520 }
1521 break;
1522 case IsBoolean:
1523 if (!(child.m_type & ~SpecBoolean)) {
1524 setConstant(node, jsBoolean(true));
1525 constantWasSet = true;
1526 break;
1527 }
1528
1529 if (!(child.m_type & SpecBoolean)) {
1530 setConstant(node, jsBoolean(false));
1531 constantWasSet = true;
1532 break;
1533 }
1534
1535 break;
1536 case IsNumber:
1537 if (!(child.m_type & ~SpecFullNumber)) {
1538 setConstant(node, jsBoolean(true));
1539 constantWasSet = true;
1540 break;
1541 }
1542
1543 if (!(child.m_type & SpecFullNumber)) {
1544 setConstant(node, jsBoolean(false));
1545 constantWasSet = true;
1546 break;
1547 }
1548
1549 break;
1550
1551 case NumberIsInteger:
1552 if (!(child.m_type & ~SpecInt32Only)) {
1553 setConstant(node, jsBoolean(true));
1554 constantWasSet = true;
1555 break;
1556 }
1557
1558 if (!(child.m_type & SpecFullNumber)) {
1559 setConstant(node, jsBoolean(false));
1560 constantWasSet = true;
1561 break;
1562 }
1563
1564 break;
1565
1566 case IsObject:
1567 if (!(child.m_type & ~SpecObject)) {
1568 setConstant(node, jsBoolean(true));
1569 constantWasSet = true;
1570 break;
1571 }
1572
1573 if (!(child.m_type & SpecObject)) {
1574 setConstant(node, jsBoolean(false));
1575 constantWasSet = true;
1576 break;
1577 }
1578
1579 break;
1580 case IsObjectOrNull:
1581 // FIXME: Use the masquerades-as-undefined watchpoint thingy.
1582 // https://bugs.webkit.org/show_bug.cgi?id=144456
1583
1584 // These expressions are complicated to parse. A helpful way to parse this is that
1585 // "!(T & ~S)" means "T is a subset of S". Conversely, "!(T & S)" means "T is a
1586 // disjoint set from S". Things like "T - S" means that, provided that S is a
1587 // subset of T, it's the "set of all things in T but not in S". Things like "T | S"
1588 // mean the "union of T and S".
1589
1590 // Is the child's type an object that isn't an other-object (i.e. object that could
1591 // have masquaredes-as-undefined traps) and isn't a function? Then: we should fold
1592 // this to true.
1593 if (!(child.m_type & ~(SpecObject - SpecObjectOther - SpecFunction))) {
1594 setConstant(node, jsBoolean(true));
1595 constantWasSet = true;
1596 break;
1597 }
1598
1599 // Is the child's type definitely not either of: an object that isn't a function,
1600 // or either undefined or null? Then: we should fold this to false. This means
1601 // for example that if it's any non-function object, including those that have
1602 // masquerades-as-undefined traps, then we don't fold. It also means we won't fold
1603 // if it's undefined-or-null, since the type bits don't distinguish between
1604 // undefined (which should fold to false) and null (which should fold to true).
1605 if (!(child.m_type & ((SpecObject - SpecFunction) | SpecOther))) {
1606 setConstant(node, jsBoolean(false));
1607 constantWasSet = true;
1608 break;
1609 }
1610
1611 break;
1612 case IsFunction:
1613 if (!(child.m_type & ~SpecFunction)) {
1614 setConstant(node, jsBoolean(true));
1615 constantWasSet = true;
1616 break;
1617 }
1618
1619 if (!(child.m_type & (SpecFunction | SpecObjectOther | SpecProxyObject))) {
1620 setConstant(node, jsBoolean(false));
1621 constantWasSet = true;
1622 break;
1623 }
1624 break;
1625
1626 case IsCellWithType: {
1627 Optional<SpeculatedType> filter = node->speculatedTypeForQuery();
1628 if (!filter) {
1629 if (!(child.m_type & SpecCell)) {
1630 setConstant(node, jsBoolean(false));
1631 constantWasSet = true;
1632 }
1633 break;
1634 }
1635 if (!(child.m_type & ~filter.value())) {
1636 setConstant(node, jsBoolean(true));
1637 constantWasSet = true;
1638 break;
1639 }
1640 if (!(child.m_type & filter.value())) {
1641 setConstant(node, jsBoolean(false));
1642 constantWasSet = true;
1643 break;
1644 }
1645 break;
1646 }
1647
1648 case IsTypedArrayView:
1649 if (!(child.m_type & ~SpecTypedArrayView)) {
1650 setConstant(node, jsBoolean(true));
1651 constantWasSet = true;
1652 break;
1653 }
1654 if (!(child.m_type & SpecTypedArrayView)) {
1655 setConstant(node, jsBoolean(false));
1656 constantWasSet = true;
1657 break;
1658 }
1659 break;
1660
1661 default:
1662 break;
1663 }
1664 if (constantWasSet)
1665 break;
1666
1667 setNonCellTypeForNode(node, SpecBoolean);
1668 break;
1669 }
1670
1671 case TypeOf: {
1672 JSValue child = forNode(node->child1()).value();
1673 AbstractValue& abstractChild = forNode(node->child1());
1674 if (child) {
1675 JSValue typeString = jsTypeStringForValue(m_vm, m_codeBlock->globalObjectFor(node->origin.semantic), child);
1676 setConstant(node, *m_graph.freeze(typeString));
1677 break;
1678 }
1679
1680 if (isFullNumberSpeculation(abstractChild.m_type)) {
1681 setConstant(node, *m_graph.freeze(m_vm.smallStrings.numberString()));
1682 break;
1683 }
1684
1685 if (isStringSpeculation(abstractChild.m_type)) {
1686 setConstant(node, *m_graph.freeze(m_vm.smallStrings.stringString()));
1687 break;
1688 }
1689
1690 // FIXME: We could use the masquerades-as-undefined watchpoint here.
1691 // https://bugs.webkit.org/show_bug.cgi?id=144456
1692 if (!(abstractChild.m_type & ~(SpecObject - SpecObjectOther - SpecFunction))) {
1693 setConstant(node, *m_graph.freeze(m_vm.smallStrings.objectString()));
1694 break;
1695 }
1696
1697 if (isFunctionSpeculation(abstractChild.m_type)) {
1698 setConstant(node, *m_graph.freeze(m_vm.smallStrings.functionString()));
1699 break;
1700 }
1701
1702 if (isBooleanSpeculation(abstractChild.m_type)) {
1703 setConstant(node, *m_graph.freeze(m_vm.smallStrings.booleanString()));
1704 break;
1705 }
1706
1707 if (isSymbolSpeculation(abstractChild.m_type)) {
1708 setConstant(node, *m_graph.freeze(m_vm.smallStrings.symbolString()));
1709 break;
1710 }
1711
1712 if (isBigIntSpeculation(abstractChild.m_type)) {
1713 setConstant(node, *m_graph.freeze(m_vm.smallStrings.bigintString()));
1714 break;
1715 }
1716
1717 setTypeForNode(node, SpecStringIdent);
1718 break;
1719 }
1720
1721 case CompareBelow:
1722 case CompareBelowEq: {
1723 JSValue leftConst = forNode(node->child1()).value();
1724 JSValue rightConst = forNode(node->child2()).value();
1725 if (leftConst && rightConst) {
1726 if (leftConst.isInt32() && rightConst.isInt32()) {
1727 uint32_t a = static_cast<uint32_t>(leftConst.asInt32());
1728 uint32_t b = static_cast<uint32_t>(rightConst.asInt32());
1729 switch (node->op()) {
1730 case CompareBelow:
1731 setConstant(node, jsBoolean(a < b));
1732 break;
1733 case CompareBelowEq:
1734 setConstant(node, jsBoolean(a <= b));
1735 break;
1736 default:
1737 RELEASE_ASSERT_NOT_REACHED();
1738 break;
1739 }
1740 break;
1741 }
1742 }
1743
1744 if (node->child1() == node->child2()) {
1745 switch (node->op()) {
1746 case CompareBelow:
1747 setConstant(node, jsBoolean(false));
1748 break;
1749 case CompareBelowEq:
1750 setConstant(node, jsBoolean(true));
1751 break;
1752 default:
1753 DFG_CRASH(m_graph, node, "Unexpected node type");
1754 break;
1755 }
1756 break;
1757 }
1758 setNonCellTypeForNode(node, SpecBoolean);
1759 break;
1760 }
1761
1762 case CompareLess:
1763 case CompareLessEq:
1764 case CompareGreater:
1765 case CompareGreaterEq:
1766 case CompareEq: {
1767 bool isClobbering = node->isBinaryUseKind(UntypedUse);
1768
1769 if (isClobbering)
1770 didFoldClobberWorld();
1771
1772 JSValue leftConst = forNode(node->child1()).value();
1773 JSValue rightConst = forNode(node->child2()).value();
1774 if (leftConst && rightConst) {
1775 if (leftConst.isNumber() && rightConst.isNumber()) {
1776 double a = leftConst.asNumber();
1777 double b = rightConst.asNumber();
1778 switch (node->op()) {
1779 case CompareLess:
1780 setConstant(node, jsBoolean(a < b));
1781 break;
1782 case CompareLessEq:
1783 setConstant(node, jsBoolean(a <= b));
1784 break;
1785 case CompareGreater:
1786 setConstant(node, jsBoolean(a > b));
1787 break;
1788 case CompareGreaterEq:
1789 setConstant(node, jsBoolean(a >= b));
1790 break;
1791 case CompareEq:
1792 setConstant(node, jsBoolean(a == b));
1793 break;
1794 default:
1795 RELEASE_ASSERT_NOT_REACHED();
1796 break;
1797 }
1798 break;
1799 }
1800
1801 if (leftConst.isString() && rightConst.isString()) {
1802 const StringImpl* a = asString(leftConst)->tryGetValueImpl();
1803 const StringImpl* b = asString(rightConst)->tryGetValueImpl();
1804 if (a && b) {
1805 bool result;
1806 if (node->op() == CompareEq)
1807 result = WTF::equal(a, b);
1808 else if (node->op() == CompareLess)
1809 result = codePointCompare(a, b) < 0;
1810 else if (node->op() == CompareLessEq)
1811 result = codePointCompare(a, b) <= 0;
1812 else if (node->op() == CompareGreater)
1813 result = codePointCompare(a, b) > 0;
1814 else if (node->op() == CompareGreaterEq)
1815 result = codePointCompare(a, b) >= 0;
1816 else
1817 RELEASE_ASSERT_NOT_REACHED();
1818 setConstant(node, jsBoolean(result));
1819 break;
1820 }
1821 }
1822
1823 if (node->op() == CompareEq && leftConst.isSymbol() && rightConst.isSymbol()) {
1824 setConstant(node, jsBoolean(asSymbol(leftConst) == asSymbol(rightConst)));
1825 break;
1826 }
1827 }
1828
1829 if (node->op() == CompareEq) {
1830 SpeculatedType leftType = forNode(node->child1()).m_type;
1831 SpeculatedType rightType = forNode(node->child2()).m_type;
1832 if (!valuesCouldBeEqual(leftType, rightType)) {
1833 setConstant(node, jsBoolean(false));
1834 break;
1835 }
1836
1837 if (leftType == SpecOther)
1838 std::swap(leftType, rightType);
1839 if (rightType == SpecOther) {
1840 // Undefined and Null are always equal when compared to eachother.
1841 if (!(leftType & ~SpecOther)) {
1842 setConstant(node, jsBoolean(true));
1843 break;
1844 }
1845
1846 // Any other type compared to Null or Undefined is always false
1847 // as long as the MasqueradesAsUndefined watchpoint is valid.
1848 //
1849 // MasqueradesAsUndefined only matters for SpecObjectOther, other
1850 // cases are always "false".
1851 if (!(leftType & (SpecObjectOther | SpecOther))) {
1852 setConstant(node, jsBoolean(false));
1853 break;
1854 }
1855
1856 if (!(leftType & SpecOther) && m_graph.masqueradesAsUndefinedWatchpointIsStillValid(node->origin.semantic)) {
1857 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
1858 m_graph.watchpoints().addLazily(globalObject->masqueradesAsUndefinedWatchpoint());
1859 setConstant(node, jsBoolean(false));
1860 break;
1861 }
1862 }
1863 }
1864
1865 if (node->child1() == node->child2()) {
1866 if (node->isBinaryUseKind(Int32Use) ||
1867 node->isBinaryUseKind(Int52RepUse) ||
1868 node->isBinaryUseKind(StringUse) ||
1869 node->isBinaryUseKind(BooleanUse) ||
1870 node->isBinaryUseKind(SymbolUse) ||
1871 node->isBinaryUseKind(StringIdentUse) ||
1872 node->isBinaryUseKind(ObjectUse) ||
1873 node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse) ||
1874 node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse)) {
1875 switch (node->op()) {
1876 case CompareLess:
1877 case CompareGreater:
1878 setConstant(node, jsBoolean(false));
1879 break;
1880 case CompareLessEq:
1881 case CompareGreaterEq:
1882 case CompareEq:
1883 setConstant(node, jsBoolean(true));
1884 break;
1885 default:
1886 DFG_CRASH(m_graph, node, "Unexpected node type");
1887 break;
1888 }
1889 break;
1890 }
1891 }
1892
1893 if (isClobbering)
1894 clobberWorld();
1895 setNonCellTypeForNode(node, SpecBoolean);
1896 break;
1897 }
1898
1899 case CompareStrictEq:
1900 case SameValue: {
1901 Node* leftNode = node->child1().node();
1902 Node* rightNode = node->child2().node();
1903 JSValue left = forNode(leftNode).value();
1904 JSValue right = forNode(rightNode).value();
1905 if (left && right) {
1906 if (left.isString() && right.isString()) {
1907 // We need this case because JSValue::strictEqual is otherwise too racy for
1908 // string comparisons.
1909 const StringImpl* a = asString(left)->tryGetValueImpl();
1910 const StringImpl* b = asString(right)->tryGetValueImpl();
1911 if (a && b) {
1912 setConstant(node, jsBoolean(WTF::equal(a, b)));
1913 break;
1914 }
1915 } else {
1916 if (node->op() == CompareStrictEq)
1917 setConstant(node, jsBoolean(JSValue::strictEqual(nullptr, left, right)));
1918 else
1919 setConstant(node, jsBoolean(sameValue(nullptr, left, right)));
1920 break;
1921 }
1922 }
1923
1924 if (node->isBinaryUseKind(UntypedUse)) {
1925 // FIXME: Revisit this condition when introducing BigInt to JSC.
1926 auto isNonStringCellConstant = [] (JSValue value) {
1927 return value && value.isCell() && !value.isString();
1928 };
1929
1930 if (isNonStringCellConstant(left) || isNonStringCellConstant(right)) {
1931 m_state.setShouldTryConstantFolding(true);
1932 setNonCellTypeForNode(node, SpecBoolean);
1933 break;
1934 }
1935 }
1936
1937 SpeculatedType leftLUB = leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(leftNode).m_type);
1938 SpeculatedType rightLUB = leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(rightNode).m_type);
1939 if (!(leftLUB & rightLUB)) {
1940 setConstant(node, jsBoolean(false));
1941 break;
1942 }
1943
1944 if (node->child1() == node->child2()) {
1945 if (node->isBinaryUseKind(BooleanUse) ||
1946 node->isBinaryUseKind(Int32Use) ||
1947 node->isBinaryUseKind(Int52RepUse) ||
1948 node->isBinaryUseKind(StringUse) ||
1949 node->isBinaryUseKind(StringIdentUse) ||
1950 node->isBinaryUseKind(SymbolUse) ||
1951 node->isBinaryUseKind(ObjectUse) ||
1952 node->isBinaryUseKind(MiscUse, UntypedUse) ||
1953 node->isBinaryUseKind(UntypedUse, MiscUse) ||
1954 node->isBinaryUseKind(StringIdentUse, NotStringVarUse) ||
1955 node->isBinaryUseKind(NotStringVarUse, StringIdentUse) ||
1956 node->isBinaryUseKind(StringUse, UntypedUse) ||
1957 node->isBinaryUseKind(UntypedUse, StringUse)) {
1958 setConstant(node, jsBoolean(true));
1959 break;
1960 }
1961 }
1962
1963 setNonCellTypeForNode(node, SpecBoolean);
1964 break;
1965 }
1966
1967 case CompareEqPtr: {
1968 Node* childNode = node->child1().node();
1969 JSValue childValue = forNode(childNode).value();
1970 if (childValue) {
1971 setConstant(node, jsBoolean(childValue.isCell() && childValue.asCell() == node->cellOperand()->cell()));
1972 break;
1973 }
1974
1975 setNonCellTypeForNode(node, SpecBoolean);
1976 break;
1977 }
1978
1979 case StringCharCodeAt:
1980 case StringCodePointAt:
1981 setNonCellTypeForNode(node, SpecInt32Only);
1982 break;
1983
1984 case StringFromCharCode:
1985 switch (node->child1().useKind()) {
1986 case Int32Use:
1987 break;
1988 case UntypedUse:
1989 clobberWorld();
1990 break;
1991 default:
1992 DFG_CRASH(m_graph, node, "Bad use kind");
1993 break;
1994 }
1995 setTypeForNode(node, SpecString);
1996 break;
1997
1998 case StringCharAt:
1999 setForNode(node, m_vm.stringStructure.get());
2000 break;
2001
2002 case GetByVal:
2003 case AtomicsAdd:
2004 case AtomicsAnd:
2005 case AtomicsCompareExchange:
2006 case AtomicsExchange:
2007 case AtomicsLoad:
2008 case AtomicsOr:
2009 case AtomicsStore:
2010 case AtomicsSub:
2011 case AtomicsXor: {
2012 if (node->op() == GetByVal) {
2013 auto foldGetByValOnConstantProperty = [&] (Edge& arrayEdge, Edge& indexEdge) {
2014 // FIXME: We can expand this for non x86 environments.
2015 // https://bugs.webkit.org/show_bug.cgi?id=134641
2016 if (!isX86())
2017 return false;
2018
2019 AbstractValue& arrayValue = forNode(arrayEdge);
2020
2021 // Check the structure set is finite. This means that this constant's structure is watched and guaranteed the one of this set.
2022 // When the structure is changed, this code should be invalidated. This is important since the following code relies on the
2023 // constant object's is not changed.
2024 if (!arrayValue.m_structure.isFinite())
2025 return false;
2026
2027 JSValue arrayConstant = arrayValue.value();
2028 if (!arrayConstant)
2029 return false;
2030
2031 JSObject* array = jsDynamicCast<JSObject*>(m_vm, arrayConstant);
2032 if (!array)
2033 return false;
2034
2035 JSValue indexConstant = forNode(indexEdge).value();
2036 if (!indexConstant || !indexConstant.isInt32() || indexConstant.asInt32() < 0)
2037 return false;
2038 uint32_t index = indexConstant.asUInt32();
2039
2040 // Check that the early StructureID is not nuked, get the butterfly, and check the late StructureID again.
2041 // And we check the indexing mode of the structure. If the indexing mode is CoW, the butterfly is
2042 // definitely JSImmutableButterfly.
2043 StructureID structureIDEarly = array->structureID();
2044 if (isNuked(structureIDEarly))
2045 return false;
2046
2047 if (node->arrayMode().arrayClass() == Array::OriginalCopyOnWriteArray) {
2048
2049 WTF::loadLoadFence();
2050 Butterfly* butterfly = array->butterfly();
2051
2052 WTF::loadLoadFence();
2053 StructureID structureIDLate = array->structureID();
2054
2055 if (structureIDEarly != structureIDLate)
2056 return false;
2057
2058 Structure* structure = m_vm.getStructure(structureIDLate);
2059 switch (node->arrayMode().type()) {
2060 case Array::Int32:
2061 case Array::Contiguous:
2062 case Array::Double:
2063 if (structure->indexingMode() != (toIndexingShape(node->arrayMode().type()) | CopyOnWrite | IsArray))
2064 return false;
2065 break;
2066 default:
2067 return false;
2068 }
2069 ASSERT(isCopyOnWrite(structure->indexingMode()));
2070
2071 JSImmutableButterfly* immutableButterfly = JSImmutableButterfly::fromButterfly(butterfly);
2072 if (index < immutableButterfly->length()) {
2073 JSValue value = immutableButterfly->get(index);
2074 ASSERT(value);
2075 if (value.isCell())
2076 setConstant(node, *m_graph.freeze(value.asCell()));
2077 else
2078 setConstant(node, value);
2079 return true;
2080 }
2081
2082 if (node->arrayMode().isOutOfBounds()) {
2083 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
2084 Structure* arrayPrototypeStructure = globalObject->arrayPrototype()->structure(m_vm);
2085 Structure* objectPrototypeStructure = globalObject->objectPrototype()->structure(m_vm);
2086 if (arrayPrototypeStructure->transitionWatchpointSetIsStillValid()
2087 && objectPrototypeStructure->transitionWatchpointSetIsStillValid()
2088 && globalObject->arrayPrototypeChainIsSane()) {
2089 m_graph.registerAndWatchStructureTransition(arrayPrototypeStructure);
2090 m_graph.registerAndWatchStructureTransition(objectPrototypeStructure);
2091 // Note that Array::Double and Array::Int32 return JSValue if array mode is OutOfBounds.
2092 setConstant(node, jsUndefined());
2093 return true;
2094 }
2095 }
2096 return false;
2097 }
2098
2099 if (node->arrayMode().type() == Array::ArrayStorage || node->arrayMode().type() == Array::SlowPutArrayStorage) {
2100 JSValue value;
2101 {
2102 // ArrayStorage's Butterfly can be half-broken state.
2103 auto locker = holdLock(array->cellLock());
2104
2105 WTF::loadLoadFence();
2106 Butterfly* butterfly = array->butterfly();
2107
2108 WTF::loadLoadFence();
2109 StructureID structureIDLate = array->structureID();
2110
2111 if (structureIDEarly != structureIDLate)
2112 return false;
2113
2114 Structure* structure = m_vm.getStructure(structureIDLate);
2115 if (!hasAnyArrayStorage(structure->indexingMode()))
2116 return false;
2117
2118 if (structure->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero())
2119 return false;
2120
2121 ArrayStorage* storage = butterfly->arrayStorage();
2122 if (index >= storage->length())
2123 return false;
2124
2125 if (index < storage->vectorLength())
2126 return false;
2127
2128 SparseArrayValueMap* map = storage->m_sparseMap.get();
2129 if (!map)
2130 return false;
2131
2132 value = map->getConcurrently(index);
2133 }
2134 if (!value)
2135 return false;
2136
2137 if (value.isCell())
2138 setConstant(node, *m_graph.freeze(value.asCell()));
2139 else
2140 setConstant(node, value);
2141 return true;
2142 }
2143
2144 return false;
2145 };
2146
2147 bool didFold = false;
2148 switch (node->arrayMode().type()) {
2149 case Array::Generic:
2150 case Array::Int32:
2151 case Array::Double:
2152 case Array::Contiguous:
2153 case Array::ArrayStorage:
2154 case Array::SlowPutArrayStorage:
2155 if (foldGetByValOnConstantProperty(m_graph.child(node, 0), m_graph.child(node, 1))) {
2156 if (!node->arrayMode().isInBounds())
2157 didFoldClobberWorld();
2158 didFold = true;
2159 }
2160 break;
2161 default:
2162 break;
2163 }
2164
2165 if (didFold)
2166 break;
2167 }
2168
2169 if (node->op() != GetByVal) {
2170 unsigned numExtraArgs = numExtraAtomicsArgs(node->op());
2171 Edge storageEdge = m_graph.child(node, 2 + numExtraArgs);
2172 if (!storageEdge)
2173 clobberWorld();
2174 }
2175 switch (node->arrayMode().type()) {
2176 case Array::SelectUsingPredictions:
2177 case Array::Unprofiled:
2178 case Array::SelectUsingArguments:
2179 RELEASE_ASSERT_NOT_REACHED();
2180 break;
2181 case Array::ForceExit:
2182 m_state.setIsValid(false);
2183 break;
2184 case Array::Undecided: {
2185 JSValue index = forNode(m_graph.child(node, 1)).value();
2186 if (index && index.isInt32() && index.asInt32() >= 0) {
2187 setConstant(node, jsUndefined());
2188 break;
2189 }
2190 setNonCellTypeForNode(node, SpecOther);
2191 break;
2192 }
2193 case Array::Generic:
2194 clobberWorld();
2195 makeHeapTopForNode(node);
2196 break;
2197 case Array::String:
2198 if (node->arrayMode().isOutOfBounds()) {
2199 // If the watchpoint was still valid we could totally set this to be
2200 // SpecString | SpecOther. Except that we'd have to be careful. If we
2201 // tested the watchpoint state here then it could change by the time
2202 // we got to the backend. So to do this right, we'd have to get the
2203 // fixup phase to check the watchpoint state and then bake into the
2204 // GetByVal operation the fact that we're using a watchpoint, using
2205 // something like Array::SaneChain (except not quite, because that
2206 // implies an in-bounds access). None of this feels like it's worth it,
2207 // so we're going with TOP for now. The same thing applies to
2208 // clobbering the world.
2209 clobberWorld();
2210 makeHeapTopForNode(node);
2211 } else
2212 setForNode(node, m_vm.stringStructure.get());
2213 break;
2214 case Array::DirectArguments:
2215 case Array::ScopedArguments:
2216 if (node->arrayMode().isOutOfBounds())
2217 clobberWorld();
2218 makeHeapTopForNode(node);
2219 break;
2220 case Array::Int32:
2221 if (node->arrayMode().isOutOfBounds()) {
2222 clobberWorld();
2223 makeHeapTopForNode(node);
2224 } else
2225 setNonCellTypeForNode(node, SpecInt32Only);
2226 break;
2227 case Array::Double:
2228 if (node->arrayMode().isOutOfBounds()) {
2229 clobberWorld();
2230 makeHeapTopForNode(node);
2231 } else if (node->arrayMode().isSaneChain())
2232 setNonCellTypeForNode(node, SpecBytecodeDouble);
2233 else
2234 setNonCellTypeForNode(node, SpecDoubleReal);
2235 break;
2236 case Array::Contiguous:
2237 case Array::ArrayStorage:
2238 case Array::SlowPutArrayStorage:
2239 if (node->arrayMode().isOutOfBounds())
2240 clobberWorld();
2241 makeHeapTopForNode(node);
2242 break;
2243 case Array::Int8Array:
2244 setNonCellTypeForNode(node, SpecInt32Only);
2245 break;
2246 case Array::Int16Array:
2247 setNonCellTypeForNode(node, SpecInt32Only);
2248 break;
2249 case Array::Int32Array:
2250 setNonCellTypeForNode(node, SpecInt32Only);
2251 break;
2252 case Array::Uint8Array:
2253 setNonCellTypeForNode(node, SpecInt32Only);
2254 break;
2255 case Array::Uint8ClampedArray:
2256 setNonCellTypeForNode(node, SpecInt32Only);
2257 break;
2258 case Array::Uint16Array:
2259 setNonCellTypeForNode(node, SpecInt32Only);
2260 break;
2261 case Array::Uint32Array:
2262 if (node->shouldSpeculateInt32())
2263 setNonCellTypeForNode(node, SpecInt32Only);
2264 else if (node->shouldSpeculateInt52())
2265 setNonCellTypeForNode(node, SpecInt52Any);
2266 else
2267 setNonCellTypeForNode(node, SpecAnyIntAsDouble);
2268 break;
2269 case Array::Float32Array:
2270 setNonCellTypeForNode(node, SpecFullDouble);
2271 break;
2272 case Array::Float64Array:
2273 setNonCellTypeForNode(node, SpecFullDouble);
2274 break;
2275 default:
2276 RELEASE_ASSERT_NOT_REACHED();
2277 break;
2278 }
2279 break;
2280 }
2281
2282 case PutByValDirect:
2283 case PutByVal:
2284 case PutByValAlias: {
2285 switch (node->arrayMode().modeForPut().type()) {
2286 case Array::ForceExit:
2287 m_state.setIsValid(false);
2288 break;
2289 case Array::Generic:
2290 clobberWorld();
2291 break;
2292 case Array::Int32:
2293 if (node->arrayMode().isOutOfBounds())
2294 clobberWorld();
2295 break;
2296 case Array::Double:
2297 if (node->arrayMode().isOutOfBounds())
2298 clobberWorld();
2299 break;
2300 case Array::Contiguous:
2301 case Array::ArrayStorage:
2302 if (node->arrayMode().isOutOfBounds())
2303 clobberWorld();
2304 break;
2305 case Array::SlowPutArrayStorage:
2306 if (node->arrayMode().mayStoreToHole())
2307 clobberWorld();
2308 break;
2309 default:
2310 break;
2311 }
2312 break;
2313 }
2314
2315 case ArrayPush:
2316 clobberWorld();
2317 setNonCellTypeForNode(node, SpecBytecodeNumber);
2318 break;
2319
2320 case ArraySlice: {
2321 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
2322
2323 // FIXME: We could do better here if we prove that the
2324 // incoming value has only a single structure.
2325 RegisteredStructureSet structureSet;
2326 structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithInt32)));
2327 structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous)));
2328 structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithDouble)));
2329
2330 setForNode(node, structureSet);
2331 break;
2332 }
2333
2334 case ArrayIndexOf: {
2335 setNonCellTypeForNode(node, SpecInt32Only);
2336 break;
2337 }
2338
2339 case ArrayPop:
2340 clobberWorld();
2341 makeHeapTopForNode(node);
2342 break;
2343
2344 case GetMyArgumentByVal:
2345 case GetMyArgumentByValOutOfBounds: {
2346 JSValue index = forNode(node->child2()).m_value;
2347 InlineCallFrame* inlineCallFrame = node->child1()->origin.semantic.inlineCallFrame();
2348
2349 if (index && index.isUInt32()) {
2350 // This pretends to return TOP for accesses that are actually proven out-of-bounds because
2351 // that's the conservative thing to do. Otherwise we'd need to write more code to mark such
2352 // paths as unreachable, or to return undefined. We could implement that eventually.
2353
2354 Checked<unsigned, RecordOverflow> argumentIndexChecked = index.asUInt32();
2355 argumentIndexChecked += node->numberOfArgumentsToSkip();
2356 unsigned argumentIndex;
2357 if (argumentIndexChecked.safeGet(argumentIndex) != CheckedState::DidOverflow) {
2358 if (inlineCallFrame) {
2359 if (argumentIndex < inlineCallFrame->argumentCountIncludingThis - 1) {
2360 setForNode(node, m_state.operand(
2361 virtualRegisterForArgument(argumentIndex + 1) + inlineCallFrame->stackOffset));
2362 m_state.setShouldTryConstantFolding(true);
2363 break;
2364 }
2365 } else {
2366 if (argumentIndex < m_state.numberOfArguments() - 1) {
2367 setForNode(node, m_state.argument(argumentIndex + 1));
2368 m_state.setShouldTryConstantFolding(true);
2369 break;
2370 }
2371 }
2372 }
2373 }
2374
2375 if (inlineCallFrame) {
2376 // We have a bound on the types even though it's random access. Take advantage of this.
2377
2378 AbstractValue result;
2379 for (unsigned i = 1 + node->numberOfArgumentsToSkip(); i < inlineCallFrame->argumentCountIncludingThis; ++i) {
2380 result.merge(
2381 m_state.operand(
2382 virtualRegisterForArgument(i) + inlineCallFrame->stackOffset));
2383 }
2384
2385 if (node->op() == GetMyArgumentByValOutOfBounds)
2386 result.merge(SpecOther);
2387
2388 if (result.value())
2389 m_state.setShouldTryConstantFolding(true);
2390
2391 setForNode(node, result);
2392 break;
2393 }
2394
2395 makeHeapTopForNode(node);
2396 break;
2397 }
2398
2399 case RegExpExec:
2400 case RegExpExecNonGlobalOrSticky:
2401 if (node->op() == RegExpExec) {
2402 // Even if we've proven known input types as RegExpObject and String,
2403 // accessing lastIndex is effectful if it's a global regexp.
2404 clobberWorld();
2405 }
2406
2407 if (JSValue globalObjectValue = forNode(node->child1()).m_value) {
2408 if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(m_vm, globalObjectValue)) {
2409 if (!globalObject->isHavingABadTime()) {
2410 m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
2411 RegisteredStructureSet structureSet;
2412 structureSet.add(m_graph.registerStructure(globalObject->regExpMatchesArrayStructure()));
2413 setForNode(node, structureSet);
2414 forNode(node).merge(SpecOther);
2415 break;
2416 }
2417 }
2418 }
2419 setTypeForNode(node, SpecOther | SpecArray);
2420 break;
2421
2422 case RegExpTest:
2423 // Even if we've proven known input types as RegExpObject and String,
2424 // accessing lastIndex is effectful if it's a global regexp.
2425 clobberWorld();
2426 setNonCellTypeForNode(node, SpecBoolean);
2427 break;
2428
2429 case RegExpMatchFast:
2430 ASSERT(node->child2().useKind() == RegExpObjectUse);
2431 ASSERT(node->child3().useKind() == StringUse || node->child3().useKind() == KnownStringUse);
2432 setTypeForNode(node, SpecOther | SpecArray);
2433 break;
2434
2435 case RegExpMatchFastGlobal:
2436 ASSERT(node->child2().useKind() == StringUse || node->child2().useKind() == KnownStringUse);
2437 setTypeForNode(node, SpecOther | SpecArray);
2438 break;
2439
2440 case StringReplace:
2441 case StringReplaceRegExp:
2442 if (node->child1().useKind() == StringUse
2443 && node->child2().useKind() == RegExpObjectUse
2444 && node->child3().useKind() == StringUse) {
2445 // This doesn't clobber the world. It just reads and writes regexp state.
2446 } else
2447 clobberWorld();
2448 setForNode(node, m_vm.stringStructure.get());
2449 break;
2450
2451 case Jump:
2452 break;
2453
2454 case Branch: {
2455 Node* child = node->child1().node();
2456 BooleanResult result = booleanResult(node, forNode(child));
2457 if (result == DefinitelyTrue) {
2458 m_state.setBranchDirection(TakeTrue);
2459 break;
2460 }
2461 if (result == DefinitelyFalse) {
2462 m_state.setBranchDirection(TakeFalse);
2463 break;
2464 }
2465 // FIXME: The above handles the trivial cases of sparse conditional
2466 // constant propagation, but we can do better:
2467 // We can specialize the source variable's value on each direction of
2468 // the branch.
2469 m_state.setBranchDirection(TakeBoth);
2470 break;
2471 }
2472
2473 case Switch: {
2474 // Nothing to do for now.
2475 // FIXME: Do sparse conditional things.
2476 break;
2477 }
2478
2479 case EntrySwitch:
2480 break;
2481
2482 case Return:
2483 m_state.setIsValid(false);
2484 break;
2485
2486 case Throw:
2487 case ThrowStaticError:
2488 case TailCall:
2489 case DirectTailCall:
2490 case TailCallVarargs:
2491 case TailCallForwardVarargs:
2492 clobberWorld();
2493 m_state.setIsValid(false);
2494 break;
2495
2496 case ToPrimitive: {
2497 JSValue childConst = forNode(node->child1()).value();
2498 if (childConst && childConst.isNumber()) {
2499 didFoldClobberWorld();
2500 setConstant(node, childConst);
2501 break;
2502 }
2503
2504 ASSERT(node->child1().useKind() == UntypedUse);
2505
2506 if (!(forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString | SpecSymbol | SpecBigInt))) {
2507 m_state.setShouldTryConstantFolding(true);
2508 didFoldClobberWorld();
2509 setForNode(node, forNode(node->child1()));
2510 break;
2511 }
2512
2513 clobberWorld();
2514
2515 setTypeForNode(node, SpecHeapTop & ~SpecObject);
2516 break;
2517 }
2518
2519 case ToNumber: {
2520 JSValue childConst = forNode(node->child1()).value();
2521 if (childConst && childConst.isNumber()) {
2522 didFoldClobberWorld();
2523 setConstant(node, childConst);
2524 break;
2525 }
2526
2527 ASSERT(node->child1().useKind() == UntypedUse);
2528
2529 if (!(forNode(node->child1()).m_type & ~SpecBytecodeNumber)) {
2530 m_state.setShouldTryConstantFolding(true);
2531 didFoldClobberWorld();
2532 setForNode(node, forNode(node->child1()));
2533 break;
2534 }
2535
2536 clobberWorld();
2537 setNonCellTypeForNode(node, SpecBytecodeNumber);
2538 break;
2539 }
2540
2541 case ToNumeric: {
2542 JSValue childConst = forNode(node->child1()).value();
2543 if (childConst && (childConst.isNumber() || childConst.isBigInt())) {
2544 didFoldClobberWorld();
2545 setConstant(node, childConst);
2546 break;
2547 }
2548
2549 ASSERT(node->child1().useKind() == UntypedUse);
2550
2551 if (!(forNode(node->child1()).m_type & ~(SpecBytecodeNumber | SpecBigInt))) {
2552 m_state.setShouldTryConstantFolding(true);
2553 didFoldClobberWorld();
2554 setForNode(node, forNode(node->child1()));
2555 break;
2556 }
2557
2558 clobberWorld();
2559 setTypeForNode(node, SpecBytecodeNumber | SpecBigInt);
2560 break;
2561 }
2562
2563 case ToString:
2564 case CallStringConstructor: {
2565 switch (node->child1().useKind()) {
2566 case StringObjectUse:
2567 case StringOrStringObjectUse:
2568 case Int32Use:
2569 case Int52RepUse:
2570 case DoubleRepUse:
2571 case NotCellUse:
2572 break;
2573 case CellUse:
2574 case UntypedUse:
2575 clobberWorld();
2576 break;
2577 default:
2578 RELEASE_ASSERT_NOT_REACHED();
2579 break;
2580 }
2581 setForNode(node, m_vm.stringStructure.get());
2582 break;
2583 }
2584
2585 case NumberToStringWithRadix: {
2586 JSValue radixValue = forNode(node->child2()).m_value;
2587 if (radixValue && radixValue.isInt32()) {
2588 int32_t radix = radixValue.asInt32();
2589 if (2 <= radix && radix <= 36) {
2590 m_state.setShouldTryConstantFolding(true);
2591 didFoldClobberWorld();
2592 setForNode(node, m_graph.m_vm.stringStructure.get());
2593 break;
2594 }
2595 }
2596 clobberWorld();
2597 setForNode(node, m_graph.m_vm.stringStructure.get());
2598 break;
2599 }
2600
2601 case NumberToStringWithValidRadixConstant: {
2602 setForNode(node, m_graph.m_vm.stringStructure.get());
2603 break;
2604 }
2605
2606 case NewStringObject: {
2607 ASSERT(node->structure()->classInfo() == StringObject::info());
2608 setForNode(node, node->structure());
2609 break;
2610 }
2611
2612 case NewSymbol: {
2613 setForNode(node, m_vm.symbolStructure.get());
2614 break;
2615 }
2616
2617 case NewArray:
2618 ASSERT(node->indexingMode() == node->indexingType()); // Copy on write arrays should only be created by NewArrayBuffer.
2619 setForNode(node,
2620 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
2621 break;
2622
2623 case NewArrayWithSpread:
2624 if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
2625 // We've compiled assuming we're not having a bad time, so to be consistent
2626 // with StructureRegisterationPhase we must say we produce an original array
2627 // allocation structure.
2628 setForNode(node,
2629 m_graph.globalObjectFor(node->origin.semantic)->originalArrayStructureForIndexingType(ArrayWithContiguous));
2630 } else {
2631 setForNode(node,
2632 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous));
2633 }
2634
2635 break;
2636
2637 case Spread:
2638 switch (node->child1()->op()) {
2639 case PhantomNewArrayBuffer:
2640 case PhantomCreateRest:
2641 break;
2642 default:
2643 if (!m_graph.canDoFastSpread(node, forNode(node->child1())))
2644 clobberWorld();
2645 else
2646 didFoldClobberWorld();
2647 break;
2648 }
2649
2650 setForNode(node,
2651 m_vm.fixedArrayStructure.get());
2652 break;
2653
2654 case NewArrayBuffer:
2655 setForNode(node,
2656 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingMode()));
2657 break;
2658
2659 case NewArrayWithSize:
2660 setTypeForNode(node, SpecArray);
2661 break;
2662
2663 case NewTypedArray:
2664 switch (node->child1().useKind()) {
2665 case Int32Use:
2666 break;
2667 case UntypedUse:
2668 clobberWorld();
2669 break;
2670 default:
2671 RELEASE_ASSERT_NOT_REACHED();
2672 break;
2673 }
2674 setForNode(node,
2675 m_graph.globalObjectFor(node->origin.semantic)->typedArrayStructureConcurrently(
2676 node->typedArrayType()));
2677 break;
2678
2679 case NewRegexp:
2680 setForNode(node, m_graph.globalObjectFor(node->origin.semantic)->regExpStructure());
2681 break;
2682
2683 case ToThis: {
2684 AbstractValue& source = forNode(node->child1());
2685 AbstractValue& destination = forNode(node);
2686 bool strictMode = m_graph.isStrictModeFor(node->origin.semantic);
2687
2688 ToThisResult result = isToThisAnIdentity(m_vm, strictMode, source);
2689 switch (result) {
2690 case ToThisResult::Identity:
2691 m_state.setShouldTryConstantFolding(true);
2692 destination = source;
2693 break;
2694 case ToThisResult::Undefined:
2695 setConstant(node, jsUndefined());
2696 break;
2697 case ToThisResult::GlobalThis:
2698 m_state.setShouldTryConstantFolding(true);
2699 destination.setType(m_graph, SpecObject);
2700 break;
2701 case ToThisResult::Dynamic:
2702 if (strictMode)
2703 destination.makeHeapTop();
2704 else {
2705 destination = source;
2706 destination.merge(SpecObject);
2707 }
2708 break;
2709 }
2710 break;
2711 }
2712
2713 case CreateThis: {
2714 if (JSValue base = forNode(node->child1()).m_value) {
2715 if (auto* function = jsDynamicCast<JSFunction*>(m_vm, base)) {
2716 if (FunctionRareData* rareData = function->rareData()) {
2717 if (rareData->allocationProfileWatchpointSet().isStillValid()) {
2718 if (Structure* structure = rareData->objectAllocationStructure()) {
2719 m_graph.freeze(rareData);
2720 m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet());
2721 m_state.setShouldTryConstantFolding(true);
2722 didFoldClobberWorld();
2723 setForNode(node, structure);
2724 break;
2725 }
2726 }
2727 }
2728 }
2729 }
2730 clobberWorld();
2731 setTypeForNode(node, SpecFinalObject);
2732 break;
2733 }
2734
2735 case CreatePromise: {
2736 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
2737 if (JSValue base = forNode(node->child1()).m_value) {
2738 if (base == (node->isInternalPromise() ? globalObject->internalPromiseConstructor() : globalObject->promiseConstructor())) {
2739 m_state.setShouldTryConstantFolding(true);
2740 didFoldClobberWorld();
2741 setForNode(node, node->isInternalPromise() ? globalObject->internalPromiseStructure() : globalObject->promiseStructure());
2742 break;
2743 }
2744 if (auto* function = jsDynamicCast<JSFunction*>(m_graph.m_vm, base)) {
2745 if (FunctionRareData* rareData = function->rareData()) {
2746 if (rareData->allocationProfileWatchpointSet().isStillValid()) {
2747 Structure* structure = rareData->internalFunctionAllocationStructure();
2748 if (structure
2749 && structure->classInfo() == (node->isInternalPromise() ? JSInternalPromise::info() : JSPromise::info())
2750 && structure->globalObject() == globalObject
2751 && rareData->allocationProfileWatchpointSet().isStillValid()) {
2752 m_graph.freeze(rareData);
2753 m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet());
2754 m_state.setShouldTryConstantFolding(true);
2755 didFoldClobberWorld();
2756 setForNode(node, structure);
2757 break;
2758 }
2759 }
2760 }
2761 }
2762 }
2763 clobberWorld();
2764 setTypeForNode(node, SpecPromiseObject);
2765 break;
2766 }
2767
2768 case CreateGenerator:
2769 case CreateAsyncGenerator: {
2770 auto tryToFold = [&] (const ClassInfo* classInfo) -> bool {
2771 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
2772 if (JSValue base = forNode(node->child1()).m_value) {
2773 if (auto* function = jsDynamicCast<JSFunction*>(m_graph.m_vm, base)) {
2774 if (FunctionRareData* rareData = function->rareData()) {
2775 if (rareData->allocationProfileWatchpointSet().isStillValid()) {
2776 Structure* structure = rareData->internalFunctionAllocationStructure();
2777 if (structure
2778 && structure->classInfo() == classInfo
2779 && structure->globalObject() == globalObject
2780 && rareData->allocationProfileWatchpointSet().isStillValid()) {
2781 m_graph.freeze(rareData);
2782 m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet());
2783 m_state.setShouldTryConstantFolding(true);
2784 didFoldClobberWorld();
2785 setForNode(node, structure);
2786 return true;
2787 }
2788 }
2789 }
2790 }
2791 }
2792 return false;
2793 };
2794
2795 bool found = false;
2796 switch (node->op()) {
2797 case CreateGenerator:
2798 found = tryToFold(JSGenerator::info());
2799 break;
2800 case CreateAsyncGenerator:
2801 found = tryToFold(JSAsyncGenerator::info());
2802 break;
2803 default:
2804 RELEASE_ASSERT_NOT_REACHED();
2805 break;
2806 }
2807 if (found)
2808 break;
2809 clobberWorld();
2810 setTypeForNode(node, SpecObjectOther);
2811 break;
2812 }
2813
2814 case NewPromise:
2815 ASSERT(!!node->structure().get());
2816 setForNode(node, node->structure());
2817 break;
2818
2819 case NewGenerator:
2820 case NewAsyncGenerator:
2821 ASSERT(!!node->structure().get());
2822 setForNode(node, node->structure());
2823 break;
2824
2825 case NewObject:
2826 ASSERT(!!node->structure().get());
2827 setForNode(node, node->structure());
2828 break;
2829
2830 case ObjectCreate: {
2831 if (JSValue base = forNode(node->child1()).m_value) {
2832 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
2833 Structure* structure = nullptr;
2834 if (base.isNull())
2835 structure = globalObject->nullPrototypeObjectStructure();
2836 else if (base.isObject())
2837 structure = m_vm.structureCache.emptyObjectStructureConcurrently(globalObject, base.getObject(), JSFinalObject::defaultInlineCapacity());
2838
2839 if (structure) {
2840 m_state.setShouldTryConstantFolding(true);
2841 if (node->child1().useKind() == UntypedUse)
2842 didFoldClobberWorld();
2843 setForNode(node, structure);
2844 break;
2845 }
2846 }
2847 if (node->child1().useKind() == UntypedUse)
2848 clobberWorld();
2849 setTypeForNode(node, SpecFinalObject);
2850 break;
2851 }
2852
2853 case ObjectKeys: {
2854 if (node->child1().useKind() == ObjectUse) {
2855 auto& structureSet = forNode(node->child1()).m_structure;
2856 if (structureSet.isFinite() && structureSet.size() == 1) {
2857 RegisteredStructure structure = structureSet.onlyStructure();
2858 if (auto* rareData = structure->rareDataConcurrently()) {
2859 if (!!rareData->cachedOwnKeysConcurrently()) {
2860 if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
2861 m_state.setShouldTryConstantFolding(true);
2862 didFoldClobberWorld();
2863 setTypeForNode(node, SpecArray);
2864 break;
2865 }
2866 }
2867 }
2868 }
2869 }
2870
2871 clobberWorld();
2872 setTypeForNode(node, SpecArray);
2873 break;
2874 }
2875
2876 case ToObject:
2877 case CallObjectConstructor: {
2878 AbstractValue& source = forNode(node->child1());
2879 AbstractValue& destination = forNode(node);
2880
2881 if (!(source.m_type & ~SpecObject)) {
2882 m_state.setShouldTryConstantFolding(true);
2883 if (node->op() == ToObject)
2884 didFoldClobberWorld();
2885 destination = source;
2886 break;
2887 }
2888
2889 if (node->op() == ToObject)
2890 clobberWorld();
2891 setTypeForNode(node, SpecObject);
2892 break;
2893 }
2894
2895 case PhantomNewObject:
2896 case PhantomNewFunction:
2897 case PhantomNewGeneratorFunction:
2898 case PhantomNewAsyncGeneratorFunction:
2899 case PhantomNewAsyncFunction:
2900 case PhantomCreateActivation:
2901 case PhantomDirectArguments:
2902 case PhantomClonedArguments:
2903 case PhantomCreateRest:
2904 case PhantomSpread:
2905 case PhantomNewArrayWithSpread:
2906 case PhantomNewArrayBuffer:
2907 case PhantomNewRegexp:
2908 case BottomValue: {
2909 clearForNode(node);
2910 break;
2911 }
2912
2913 case PutHint:
2914 break;
2915
2916 case MaterializeNewObject: {
2917 setForNode(node, node->structureSet());
2918 break;
2919 }
2920
2921 case PushWithScope:
2922 // We don't use the more precise withScopeStructure() here because it is a LazyProperty and may not yet be allocated.
2923 setTypeForNode(node, SpecObjectOther);
2924 break;
2925
2926 case CreateActivation:
2927 case MaterializeCreateActivation:
2928 setForNode(node,
2929 m_codeBlock->globalObjectFor(node->origin.semantic)->activationStructure());
2930 break;
2931
2932 case CreateDirectArguments:
2933 setForNode(node, m_codeBlock->globalObjectFor(node->origin.semantic)->directArgumentsStructure());
2934 break;
2935
2936 case CreateScopedArguments:
2937 setForNode(node, m_codeBlock->globalObjectFor(node->origin.semantic)->scopedArgumentsStructure());
2938 break;
2939
2940 case CreateClonedArguments:
2941 if (!m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
2942 setTypeForNode(node, SpecObject);
2943 break;
2944 }
2945 setForNode(node, m_codeBlock->globalObjectFor(node->origin.semantic)->clonedArgumentsStructure());
2946 break;
2947
2948 case NewGeneratorFunction:
2949 setForNode(node,
2950 m_codeBlock->globalObjectFor(node->origin.semantic)->generatorFunctionStructure());
2951 break;
2952
2953 case NewAsyncGeneratorFunction:
2954 setForNode(node,
2955 m_codeBlock->globalObjectFor(node->origin.semantic)->asyncGeneratorFunctionStructure());
2956 break;
2957
2958 case NewAsyncFunction:
2959 setForNode(node,
2960 m_codeBlock->globalObjectFor(node->origin.semantic)->asyncFunctionStructure());
2961 break;
2962
2963 case NewFunction: {
2964 JSGlobalObject* globalObject = m_codeBlock->globalObjectFor(node->origin.semantic);
2965 Structure* structure = JSFunction::selectStructureForNewFuncExp(globalObject, node->castOperand<FunctionExecutable*>());
2966 setForNode(node, structure);
2967 break;
2968 }
2969
2970 case GetCallee:
2971 if (FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>(m_vm, m_codeBlock->ownerExecutable())) {
2972 if (JSFunction* function = executable->singleton().inferredValue()) {
2973 m_graph.watchpoints().addLazily(executable);
2974 setConstant(node, *m_graph.freeze(function));
2975 break;
2976 }
2977 }
2978 setTypeForNode(node, SpecFunction | SpecObjectOther);
2979 break;
2980
2981 case GetArgumentCountIncludingThis:
2982 setTypeForNode(node, SpecInt32Only);
2983 break;
2984
2985 case SetCallee:
2986 case SetArgumentCountIncludingThis:
2987 break;
2988
2989 case GetRestLength:
2990 setNonCellTypeForNode(node, SpecInt32Only);
2991 break;
2992
2993 case GetGetter: {
2994 if (JSValue base = forNode(node->child1()).m_value) {
2995 GetterSetter* getterSetter = jsDynamicCast<GetterSetter*>(m_vm, base);
2996 if (getterSetter && !getterSetter->isGetterNull()) {
2997 setConstant(node, *m_graph.freeze(getterSetter->getterConcurrently()));
2998 break;
2999 }
3000 }
3001
3002 setTypeForNode(node, SpecObject);
3003 break;
3004 }
3005
3006 case GetSetter: {
3007 if (JSValue base = forNode(node->child1()).m_value) {
3008 GetterSetter* getterSetter = jsDynamicCast<GetterSetter*>(m_vm, base);
3009 if (getterSetter && !getterSetter->isSetterNull()) {
3010 setConstant(node, *m_graph.freeze(getterSetter->setterConcurrently()));
3011 break;
3012 }
3013 }
3014
3015 setTypeForNode(node, SpecObject);
3016 break;
3017 }
3018
3019 case GetScope:
3020 if (JSValue base = forNode(node->child1()).m_value) {
3021 if (JSFunction* function = jsDynamicCast<JSFunction*>(m_vm, base)) {
3022 setConstant(node, *m_graph.freeze(function->scope()));
3023 break;
3024 }
3025 }
3026 setTypeForNode(node, SpecObjectOther);
3027 break;
3028
3029 case SkipScope: {
3030 if (JSValue child = forNode(node->child1()).value()) {
3031 if (JSScope* scope = jsDynamicCast<JSScope*>(m_vm, child)) {
3032 if (JSScope* nextScope = scope->next()) {
3033 setConstant(node, *m_graph.freeze(JSValue(nextScope)));
3034 break;
3035 }
3036 }
3037 }
3038 setTypeForNode(node, SpecObjectOther);
3039 break;
3040 }
3041
3042 case GetGlobalObject: {
3043 JSValue child = forNode(node->child1()).value();
3044 if (child) {
3045 setConstant(node, *m_graph.freeze(JSValue(asObject(child)->globalObject(m_vm))));
3046 break;
3047 }
3048
3049 if (forNode(node->child1()).m_structure.isFinite()) {
3050 JSGlobalObject* globalObject = nullptr;
3051 bool ok = true;
3052 forNode(node->child1()).m_structure.forEach(
3053 [&] (RegisteredStructure structure) {
3054 if (!globalObject)
3055 globalObject = structure->globalObject();
3056 else if (globalObject != structure->globalObject())
3057 ok = false;
3058 });
3059 if (globalObject && ok) {
3060 setConstant(node, *m_graph.freeze(JSValue(globalObject)));
3061 break;
3062 }
3063 }
3064
3065 setTypeForNode(node, SpecObjectOther);
3066 break;
3067 }
3068
3069 case GetGlobalThis: {
3070 setTypeForNode(node, SpecObject);
3071 break;
3072 }
3073
3074 case GetClosureVar:
3075 if (JSValue value = m_graph.tryGetConstantClosureVar(forNode(node->child1()), node->scopeOffset())) {
3076 setConstant(node, *m_graph.freeze(value));
3077 break;
3078 }
3079 makeBytecodeTopForNode(node);
3080 break;
3081
3082 case PutClosureVar:
3083 break;
3084
3085 case GetInternalField:
3086 makeBytecodeTopForNode(node);
3087 break;
3088
3089 case PutInternalField:
3090 break;
3091
3092
3093 case GetRegExpObjectLastIndex:
3094 makeHeapTopForNode(node);
3095 break;
3096
3097 case SetRegExpObjectLastIndex:
3098 case RecordRegExpCachedResult:
3099 break;
3100
3101 case GetFromArguments:
3102 makeHeapTopForNode(node);
3103 break;
3104
3105 case PutToArguments:
3106 break;
3107
3108 case GetArgument:
3109 makeHeapTopForNode(node);
3110 break;
3111
3112 case TryGetById:
3113 // FIXME: This should constant fold at least as well as the normal GetById case.
3114 // https://bugs.webkit.org/show_bug.cgi?id=156422
3115 makeHeapTopForNode(node);
3116 break;
3117
3118 case GetByIdDirect:
3119 case GetByIdDirectFlush:
3120 case GetById:
3121 case GetByIdFlush: {
3122 AbstractValue& value = forNode(node->child1());
3123 if (value.m_structure.isFinite()
3124 && (node->child1().useKind() == CellUse || !(value.m_type & ~SpecCell))) {
3125 UniquedStringImpl* uid = m_graph.identifiers()[node->identifierNumber()];
3126 GetByStatus status = GetByStatus::computeFor(value.m_structure.toStructureSet(), uid);
3127 if (status.isSimple()) {
3128 // Figure out what the result is going to be - is it TOP, a constant, or maybe
3129 // something more subtle?
3130 AbstractValue result;
3131 for (unsigned i = status.numVariants(); i--;) {
3132 // This thing won't give us a variant that involves prototypes. If it did, we'd
3133 // have more work to do here.
3134 DFG_ASSERT(m_graph, node, status[i].conditionSet().isEmpty());
3135
3136 result.merge(
3137 m_graph.inferredValueForProperty(
3138 value, status[i].offset(), m_state.structureClobberState()));
3139 }
3140
3141 m_state.setShouldTryConstantFolding(true);
3142 didFoldClobberWorld();
3143 forNode(node) = result;
3144 break;
3145 }
3146 }
3147
3148 clobberWorld();
3149 makeHeapTopForNode(node);
3150 break;
3151 }
3152
3153 case GetByValWithThis:
3154 case GetByIdWithThis:
3155 clobberWorld();
3156 makeHeapTopForNode(node);
3157 break;
3158
3159 case GetArrayLength: {
3160 JSArrayBufferView* view = m_graph.tryGetFoldableView(
3161 forNode(node->child1()).m_value, node->arrayMode());
3162 if (view) {
3163 setConstant(node, jsNumber(view->length()));
3164 break;
3165 }
3166 setNonCellTypeForNode(node, SpecInt32Only);
3167 break;
3168 }
3169
3170 case GetVectorLength: {
3171 setNonCellTypeForNode(node, SpecInt32Only);
3172 break;
3173 }
3174
3175 case DeleteById:
3176 case DeleteByVal: {
3177 // FIXME: This could decide if the delete will be successful based on the set of structures that
3178 // we get from our base value. https://bugs.webkit.org/show_bug.cgi?id=156611
3179 clobberWorld();
3180 setNonCellTypeForNode(node, SpecBoolean);
3181 break;
3182 }
3183
3184 case CheckStructure: {
3185 AbstractValue& value = forNode(node->child1());
3186
3187 const RegisteredStructureSet& set = node->structureSet();
3188
3189 // It's interesting that we could have proven that the object has a larger structure set
3190 // that includes the set we're testing. In that case we could make the structure check
3191 // more efficient. We currently don't.
3192
3193 if (value.m_structure.isSubsetOf(set))
3194 m_state.setShouldTryConstantFolding(true);
3195
3196 SpeculatedType admittedTypes = SpecNone;
3197 switch (node->child1().useKind()) {
3198 case CellUse:
3199 case KnownCellUse:
3200 admittedTypes = SpecNone;
3201 break;
3202 case CellOrOtherUse:
3203 admittedTypes = SpecOther;
3204 break;
3205 default:
3206 DFG_CRASH(m_graph, node, "Bad use kind");
3207 break;
3208 }
3209
3210 filter(value, set, admittedTypes);
3211 break;
3212 }
3213
3214 case CheckStructureOrEmpty: {
3215 AbstractValue& value = forNode(node->child1());
3216
3217 bool mayBeEmpty = value.m_type & SpecEmpty;
3218 if (!mayBeEmpty)
3219 m_state.setShouldTryConstantFolding(true);
3220
3221 SpeculatedType admittedTypes = mayBeEmpty ? SpecEmpty : SpecNone;
3222 filter(value, node->structureSet(), admittedTypes);
3223 break;
3224 }
3225
3226 case CheckStructureImmediate: {
3227 // FIXME: This currently can only reason about one structure at a time.
3228 // https://bugs.webkit.org/show_bug.cgi?id=136988
3229
3230 AbstractValue& value = forNode(node->child1());
3231 const RegisteredStructureSet& set = node->structureSet();
3232
3233 if (value.value()) {
3234 if (Structure* structure = jsDynamicCast<Structure*>(m_vm, value.value())) {
3235 if (set.contains(m_graph.registerStructure(structure))) {
3236 m_state.setShouldTryConstantFolding(true);
3237 break;
3238 }
3239 }
3240 m_state.setIsValid(false);
3241 break;
3242 }
3243
3244 if (m_phiChildren) {
3245 bool allGood = true;
3246 m_phiChildren->forAllTransitiveIncomingValues(
3247 node,
3248 [&] (Node* incoming) {
3249 if (Structure* structure = incoming->dynamicCastConstant<Structure*>(m_vm)) {
3250 if (set.contains(m_graph.registerStructure(structure)))
3251 return;
3252 }
3253 allGood = false;
3254 });
3255 if (allGood) {
3256 m_state.setShouldTryConstantFolding(true);
3257 break;
3258 }
3259 }
3260
3261 if (RegisteredStructure structure = set.onlyStructure()) {
3262 filterByValue(node->child1(), *m_graph.freeze(structure.get()));
3263 break;
3264 }
3265
3266 // Aw shucks, we can't do anything!
3267 break;
3268 }
3269
3270 case PutStructure:
3271 if (!forNode(node->child1()).m_structure.isClear()) {
3272 if (forNode(node->child1()).m_structure.onlyStructure() == node->transition()->next) {
3273 didFoldClobberStructures();
3274 m_state.setShouldTryConstantFolding(true);
3275 } else {
3276 observeTransition(
3277 clobberLimit, node->transition()->previous, node->transition()->next);
3278 forNode(node->child1()).changeStructure(m_graph, node->transition()->next);
3279 }
3280 } else {
3281 // We're going to exit before we get here, but for the sake of validation, we've folded our write to StructureID.
3282 didFoldClobberStructures();
3283 }
3284 break;
3285 case GetButterfly:
3286 case AllocatePropertyStorage:
3287 case ReallocatePropertyStorage:
3288 case NukeStructureAndSetButterfly:
3289 // FIXME: We don't model the fact that the structureID is nuked, simply because currently
3290 // nobody would currently benefit from having that information. But it's a bug nonetheless.
3291 if (node->op() == NukeStructureAndSetButterfly)
3292 didFoldClobberStructures();
3293 clearForNode(node); // The result is not a JS value.
3294 break;
3295 case CheckSubClass: {
3296 JSValue constant = forNode(node->child1()).value();
3297 if (constant) {
3298 if (constant.isCell() && constant.asCell()->inherits(m_vm, node->classInfo())) {
3299 m_state.setShouldTryConstantFolding(true);
3300 ASSERT(constant);
3301 break;
3302 }
3303 }
3304
3305 AbstractValue& value = forNode(node->child1());
3306
3307 if (value.m_structure.isSubClassOf(node->classInfo()))
3308 m_state.setShouldTryConstantFolding(true);
3309
3310 filterClassInfo(value, node->classInfo());
3311 break;
3312 }
3313 case CallDOMGetter: {
3314 CallDOMGetterData* callDOMGetterData = node->callDOMGetterData();
3315 DOMJIT::CallDOMGetterSnippet* snippet = callDOMGetterData->snippet;
3316 if (!snippet || snippet->effect.writes)
3317 clobberWorld();
3318 if (callDOMGetterData->domJIT)
3319 setTypeForNode(node, callDOMGetterData->domJIT->resultType());
3320 else
3321 makeBytecodeTopForNode(node);
3322 break;
3323 }
3324 case CallDOM: {
3325 const DOMJIT::Signature* signature = node->signature();
3326 if (signature->effect.writes)
3327 clobberWorld();
3328 setTypeForNode(node, signature->result);
3329 break;
3330 }
3331 case CheckArray: {
3332 if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
3333 m_state.setShouldTryConstantFolding(true);
3334 break;
3335 }
3336 switch (node->arrayMode().type()) {
3337 case Array::String:
3338 filter(node->child1(), SpecString);
3339 break;
3340 case Array::Int32:
3341 case Array::Double:
3342 case Array::Contiguous:
3343 case Array::Undecided:
3344 case Array::ArrayStorage:
3345 case Array::SlowPutArrayStorage:
3346 break;
3347 case Array::DirectArguments:
3348 filter(node->child1(), SpecDirectArguments);
3349 break;
3350 case Array::ScopedArguments:
3351 filter(node->child1(), SpecScopedArguments);
3352 break;
3353 case Array::Int8Array:
3354 filter(node->child1(), SpecInt8Array);
3355 break;
3356 case Array::Int16Array:
3357 filter(node->child1(), SpecInt16Array);
3358 break;
3359 case Array::Int32Array:
3360 filter(node->child1(), SpecInt32Array);
3361 break;
3362 case Array::Uint8Array:
3363 filter(node->child1(), SpecUint8Array);
3364 break;
3365 case Array::Uint8ClampedArray:
3366 filter(node->child1(), SpecUint8ClampedArray);
3367 break;
3368 case Array::Uint16Array:
3369 filter(node->child1(), SpecUint16Array);
3370 break;
3371 case Array::Uint32Array:
3372 filter(node->child1(), SpecUint32Array);
3373 break;
3374 case Array::Float32Array:
3375 filter(node->child1(), SpecFloat32Array);
3376 break;
3377 case Array::Float64Array:
3378 filter(node->child1(), SpecFloat64Array);
3379 break;
3380 case Array::AnyTypedArray:
3381 filter(node->child1(), SpecTypedArrayView);
3382 break;
3383 default:
3384 RELEASE_ASSERT_NOT_REACHED();
3385 break;
3386 }
3387 filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering());
3388 break;
3389 }
3390 case Arrayify: {
3391 if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
3392 didFoldClobberStructures();
3393 m_state.setShouldTryConstantFolding(true);
3394 break;
3395 }
3396 ASSERT(node->arrayMode().conversion() == Array::Convert);
3397 clobberStructures();
3398 filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering());
3399 break;
3400 }
3401 case ArrayifyToStructure: {
3402 AbstractValue& value = forNode(node->child1());
3403 if (value.m_structure.isSubsetOf(RegisteredStructureSet(node->structure())))
3404 m_state.setShouldTryConstantFolding(true);
3405 clobberStructures();
3406
3407 // We have a bunch of options of how to express the abstract set at this point. Let set S
3408 // be the set of structures that the value had before clobbering and assume that all of
3409 // them are watchable. The new value should be the least expressible upper bound of the
3410 // intersection of "values that currently have structure = node->structure()" and "values
3411 // that have structure in S plus any structure transition-reachable from S". Assume that
3412 // node->structure() is not in S but it is transition-reachable from S. Then we would
3413 // like to say that the result is "values that have structure = node->structure() until
3414 // we invalidate", but there is no way to express this using the AbstractValue syntax. So
3415 // we must choose between:
3416 //
3417 // 1) "values that currently have structure = node->structure()". This is a valid
3418 // superset of the value that we really want, and it's specific enough to satisfy the
3419 // preconditions of the array access that this is guarding. It's also specific enough
3420 // to allow relevant optimizations in the case that we didn't have a contradiction
3421 // like in this example. Notice that in the abscence of any contradiction, this result
3422 // is precise rather than being a conservative LUB.
3423 //
3424 // 2) "values that currently hava structure in S plus any structure transition-reachable
3425 // from S". This is also a valid superset of the value that we really want, but it's
3426 // not specific enough to satisfy the preconditions of the array access that this is
3427 // guarding - so playing such shenanigans would preclude us from having assertions on
3428 // the typing preconditions of any array accesses. This would also not be a desirable
3429 // answer in the absence of a contradiction.
3430 //
3431 // Note that it's tempting to simply say that the resulting value is BOTTOM because of
3432 // the contradiction. That would be wrong, since we haven't hit an invalidation point,
3433 // yet.
3434 forNode(node->child1()).set(m_graph, node->structure());
3435 break;
3436 }
3437 case GetIndexedPropertyStorage: {
3438 JSArrayBufferView* view = m_graph.tryGetFoldableView(
3439 forNode(node->child1()).m_value, node->arrayMode());
3440 if (view)
3441 m_state.setShouldTryConstantFolding(true);
3442 clearForNode(node);
3443 break;
3444 }
3445 case ConstantStoragePointer: {
3446 clearForNode(node);
3447 break;
3448 }
3449
3450 case GetTypedArrayByteOffset: {
3451 JSArrayBufferView* view = m_graph.tryGetFoldableView(forNode(node->child1()).m_value);
3452 if (view) {
3453 Optional<unsigned> byteOffset = view->byteOffsetConcurrently();
3454 if (byteOffset) {
3455 setConstant(node, jsNumber(*byteOffset));
3456 break;
3457 }
3458 }
3459 setNonCellTypeForNode(node, SpecInt32Only);
3460 break;
3461 }
3462
3463 case GetPrototypeOf: {
3464 AbstractValue& value = forNode(node->child1());
3465 if ((value.m_type && !(value.m_type & ~SpecObject)) && value.m_structure.isFinite()) {
3466 bool canFold = !value.m_structure.isClear();
3467 JSValue prototype;
3468 value.m_structure.forEach([&] (RegisteredStructure structure) {
3469 auto getPrototypeMethod = structure->classInfo()->methodTable.getPrototype;
3470 MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
3471 if (getPrototypeMethod != defaultGetPrototype) {
3472 canFold = false;
3473 return;
3474 }
3475
3476 if (structure->hasPolyProto()) {
3477 canFold = false;
3478 return;
3479 }
3480 if (!prototype)
3481 prototype = structure->storedPrototype();
3482 else if (prototype != structure->storedPrototype())
3483 canFold = false;
3484 });
3485
3486 if (prototype && canFold) {
3487 switch (node->child1().useKind()) {
3488 case ArrayUse:
3489 case FunctionUse:
3490 case FinalObjectUse:
3491 break;
3492 default:
3493 didFoldClobberWorld();
3494 break;
3495 }
3496 setConstant(node, *m_graph.freeze(prototype));
3497 break;
3498 }
3499 }
3500
3501 switch (node->child1().useKind()) {
3502 case ArrayUse:
3503 case FunctionUse:
3504 case FinalObjectUse:
3505 break;
3506 default:
3507 clobberWorld();
3508 break;
3509 }
3510 setTypeForNode(node, SpecObject | SpecOther);
3511 break;
3512 }
3513
3514 case GetByOffset: {
3515 StorageAccessData& data = node->storageAccessData();
3516
3517 // FIXME: The part of this that handles inferred property types relies on AI knowing the structure
3518 // right now. That's probably not optimal. In some cases, we may perform an optimization (usually
3519 // by something other than AI, maybe by CSE for example) that obscures AI's view of the structure
3520 // at the point where GetByOffset runs. Currently, when that happens, we'll have to rely entirely
3521 // on the type that ByteCodeParser was able to prove.
3522 AbstractValue value = m_graph.inferredValueForProperty(
3523 forNode(node->child2()), data.offset, m_state.structureClobberState());
3524
3525 // If we decide that there does not exist any value that this can return, then it's probably
3526 // because the compilation was already invalidated.
3527 if (value.isClear())
3528 m_state.setIsValid(false);
3529
3530 setForNode(node, value);
3531 if (value.m_value)
3532 m_state.setShouldTryConstantFolding(true);
3533 break;
3534 }
3535
3536 case GetGetterSetterByOffset: {
3537 StorageAccessData& data = node->storageAccessData();
3538 AbstractValue base = forNode(node->child2());
3539 JSValue result = m_graph.tryGetConstantProperty(base, data.offset);
3540 if (result && jsDynamicCast<GetterSetter*>(m_vm, result)) {
3541 setConstant(node, *m_graph.freeze(result));
3542 break;
3543 }
3544
3545 setForNode(node, m_vm.getterSetterStructure.get());
3546 break;
3547 }
3548
3549 case MultiGetByOffset: {
3550 // This code will filter the base value in a manner that is possibly different (either more
3551 // or less precise) than the way it would be filtered if this was strength-reduced to a
3552 // CheckStructure. This is fine. It's legal for different passes over the code to prove
3553 // different things about the code, so long as all of them are sound. That even includes
3554 // one guy proving that code should never execute (due to a contradiction) and another guy
3555 // not finding that contradiction. If someone ever proved that there would be a
3556 // contradiction then there must always be a contradiction even if subsequent passes don't
3557 // realize it. This is the case here.
3558
3559 // Ordinarily you have to be careful with calling setShouldTryConstantFolding()
3560 // because of the effect on compile times, but this node is FTL-only.
3561 m_state.setShouldTryConstantFolding(true);
3562
3563 AbstractValue base = forNode(node->child1());
3564 RegisteredStructureSet baseSet;
3565 AbstractValue result;
3566 for (const MultiGetByOffsetCase& getCase : node->multiGetByOffsetData().cases) {
3567 RegisteredStructureSet set = getCase.set();
3568 set.filter(base);
3569 if (set.isEmpty())
3570 continue;
3571 baseSet.merge(set);
3572
3573 switch (getCase.method().kind()) {
3574 case GetByOffsetMethod::Constant: {
3575 AbstractValue thisResult;
3576 thisResult.set(
3577 m_graph,
3578 *getCase.method().constant(),
3579 m_state.structureClobberState());
3580 result.merge(thisResult);
3581 break;
3582 }
3583
3584 default: {
3585 result.makeHeapTop();
3586 break;
3587 } }
3588 }
3589
3590 if (forNode(node->child1()).changeStructure(m_graph, baseSet) == Contradiction)
3591 m_state.setIsValid(false);
3592
3593 setForNode(node, result);
3594 break;
3595 }
3596
3597 case PutByOffset: {
3598 break;
3599 }
3600
3601 case MultiPutByOffset: {
3602 RegisteredStructureSet newSet;
3603 TransitionVector transitions;
3604
3605 // Ordinarily you have to be careful with calling setShouldTryConstantFolding()
3606 // because of the effect on compile times, but this node is FTL-only.
3607 m_state.setShouldTryConstantFolding(true);
3608
3609 AbstractValue base = forNode(node->child1());
3610 AbstractValue originalValue = forNode(node->child2());
3611 AbstractValue resultingValue;
3612
3613 if (node->multiPutByOffsetData().writesStructures())
3614 didFoldClobberStructures();
3615
3616 for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
3617 const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
3618 RegisteredStructureSet thisSet = *m_graph.addStructureSet(variant.oldStructure());
3619 thisSet.filter(base);
3620 if (thisSet.isEmpty())
3621 continue;
3622
3623 AbstractValue thisValue = originalValue;
3624 resultingValue.merge(thisValue);
3625
3626 if (variant.kind() == PutByIdVariant::Transition) {
3627 RegisteredStructure newStructure = m_graph.registerStructure(variant.newStructure());
3628 if (thisSet.onlyStructure() != newStructure) {
3629 transitions.append(
3630 Transition(m_graph.registerStructure(variant.oldStructureForTransition()), newStructure));
3631 } // else this is really a replace.
3632 newSet.add(newStructure);
3633 } else {
3634 ASSERT(variant.kind() == PutByIdVariant::Replace);
3635 newSet.merge(thisSet);
3636 }
3637 }
3638
3639 // We need to order AI executing these effects in the same order as they're executed
3640 // at runtime. This is critical when you have JS code like `o.f = o;`. We first
3641 // filter types on o, then transition o. Not the other way around. If we got
3642 // this ordering wrong, we could end up with the wrong type representing o.
3643 setForNode(node->child2(), resultingValue);
3644 if (!!originalValue && !resultingValue)
3645 m_state.setIsValid(false);
3646
3647 observeTransitions(clobberLimit, transitions);
3648 if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction)
3649 m_state.setIsValid(false);
3650 break;
3651 }
3652
3653 case GetExecutable: {
3654 JSValue value = forNode(node->child1()).value();
3655 if (value) {
3656 JSFunction* function = jsDynamicCast<JSFunction*>(m_vm, value);
3657 if (function) {
3658 setConstant(node, *m_graph.freeze(function->executable()));
3659 break;
3660 }
3661 }
3662 setTypeForNode(node, SpecCellOther);
3663 break;
3664 }
3665
3666 case CheckCell: {
3667 JSValue value = forNode(node->child1()).value();
3668 if (value == node->cellOperand()->value()) {
3669 m_state.setShouldTryConstantFolding(true);
3670 ASSERT(value);
3671 break;
3672 }
3673 filterByValue(node->child1(), *node->cellOperand());
3674 break;
3675 }
3676
3677 case AssertNotEmpty:
3678 case CheckNotEmpty: {
3679 AbstractValue& value = forNode(node->child1());
3680 if (!(value.m_type & SpecEmpty)) {
3681 m_state.setShouldTryConstantFolding(true);
3682 break;
3683 }
3684
3685 filter(value, ~SpecEmpty);
3686 break;
3687 }
3688
3689 case CheckIdent: {
3690 AbstractValue& value = forNode(node->child1());
3691 UniquedStringImpl* uid = node->uidOperand();
3692
3693 JSValue childConstant = value.value();
3694 if (childConstant) {
3695 if (childConstant.isString()) {
3696 if (asString(childConstant)->tryGetValueImpl() == uid) {
3697 m_state.setShouldTryConstantFolding(true);
3698 break;
3699 }
3700 } else if (childConstant.isSymbol()) {
3701 if (&jsCast<Symbol*>(childConstant)->privateName().uid() == uid) {
3702 m_state.setShouldTryConstantFolding(true);
3703 break;
3704 }
3705 }
3706 }
3707
3708 if (node->child1().useKind() == StringIdentUse)
3709 filter(value, SpecStringIdent);
3710 else
3711 filter(value, SpecSymbol);
3712 break;
3713 }
3714
3715 case CheckInBounds: {
3716 JSValue left = forNode(node->child1()).value();
3717 JSValue right = forNode(node->child2()).value();
3718 if (left && right && left.isInt32() && right.isInt32() && static_cast<uint32_t>(left.asInt32()) < static_cast<uint32_t>(right.asInt32()))
3719 m_state.setShouldTryConstantFolding(true);
3720
3721 // We claim we result in Int32. It's not really important what our result is (though we
3722 // don't want to claim we may result in the empty value), other nodes with data flow edges
3723 // to us just do that to maintain the invariant that they can't be hoisted higher than us.
3724 // So we just arbitrarily pick Int32. In some ways, StorageResult may be the more correct
3725 // thing to do here. We pick NodeResultJS because it makes converting this to an identity
3726 // easier.
3727 setNonCellTypeForNode(node, SpecInt32Only);
3728 break;
3729 }
3730
3731 case PutById:
3732 case PutByIdFlush:
3733 case PutByIdDirect: {
3734 AbstractValue& value = forNode(node->child1());
3735 if (value.m_structure.isFinite()) {
3736 PutByIdStatus status = PutByIdStatus::computeFor(
3737 m_graph.globalObjectFor(node->origin.semantic),
3738 value.m_structure.toStructureSet(),
3739 m_graph.identifiers()[node->identifierNumber()],
3740 node->op() == PutByIdDirect);
3741
3742 if (status.isSimple()) {
3743 RegisteredStructureSet newSet;
3744 TransitionVector transitions;
3745
3746 for (unsigned i = status.numVariants(); i--;) {
3747 const PutByIdVariant& variant = status[i];
3748 if (variant.kind() == PutByIdVariant::Transition) {
3749 RegisteredStructure newStructure = m_graph.registerStructure(variant.newStructure());
3750 transitions.append(
3751 Transition(
3752 m_graph.registerStructure(variant.oldStructureForTransition()), newStructure));
3753 newSet.add(newStructure);
3754 } else {
3755 ASSERT(variant.kind() == PutByIdVariant::Replace);
3756 newSet.merge(*m_graph.addStructureSet(variant.oldStructure()));
3757 }
3758 }
3759
3760 if (status.numVariants() == 1 || m_graph.m_plan.isFTL())
3761 m_state.setShouldTryConstantFolding(true);
3762
3763 didFoldClobberWorld();
3764 observeTransitions(clobberLimit, transitions);
3765 if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction)
3766 m_state.setIsValid(false);
3767 break;
3768 }
3769 }
3770
3771 clobberWorld();
3772 break;
3773 }
3774
3775 case PutByValWithThis:
3776 case PutByIdWithThis:
3777 clobberWorld();
3778 break;
3779
3780 case PutGetterById:
3781 case PutSetterById:
3782 case PutGetterSetterById:
3783 case PutGetterByVal:
3784 case PutSetterByVal: {
3785 clobberWorld();
3786 break;
3787 }
3788
3789 case DefineDataProperty:
3790 case DefineAccessorProperty:
3791 clobberWorld();
3792 break;
3793
3794 case InById: {
3795 // FIXME: We can determine when the property definitely exists based on abstract
3796 // value information.
3797 clobberWorld();
3798 filter(node->child1(), SpecObject);
3799 setNonCellTypeForNode(node, SpecBoolean);
3800 break;
3801 }
3802
3803 case InByVal: {
3804 AbstractValue& property = forNode(node->child2());
3805 if (JSValue constant = property.value()) {
3806 if (constant.isString()) {
3807 JSString* string = asString(constant);
3808 const StringImpl* impl = string->tryGetValueImpl();
3809 if (impl && impl->isAtom())
3810 m_state.setShouldTryConstantFolding(true);
3811 }
3812 }
3813
3814 // FIXME: We can determine when the property definitely exists based on abstract
3815 // value information.
3816 clobberWorld();
3817 filter(node->child1(), SpecObject);
3818 setNonCellTypeForNode(node, SpecBoolean);
3819 break;
3820 }
3821
3822 case HasOwnProperty: {
3823 clobberWorld();
3824 setNonCellTypeForNode(node, SpecBoolean);
3825 break;
3826 }
3827
3828 case GetEnumerableLength: {
3829 setNonCellTypeForNode(node, SpecInt32Only);
3830 break;
3831 }
3832 case HasGenericProperty: {
3833 setNonCellTypeForNode(node, SpecBoolean);
3834 clobberWorld();
3835 break;
3836 }
3837 case HasStructureProperty: {
3838 setNonCellTypeForNode(node, SpecBoolean);
3839 clobberWorld();
3840 break;
3841 }
3842 case HasIndexedProperty: {
3843 ArrayMode mode = node->arrayMode();
3844 switch (mode.type()) {
3845 case Array::Int32:
3846 case Array::Double:
3847 case Array::Contiguous:
3848 case Array::ArrayStorage: {
3849 break;
3850 }
3851 default: {
3852 clobberWorld();
3853 break;
3854 }
3855 }
3856 setNonCellTypeForNode(node, SpecBoolean);
3857 break;
3858 }
3859 case GetDirectPname: {
3860 clobberWorld();
3861 makeHeapTopForNode(node);
3862 break;
3863 }
3864 case GetPropertyEnumerator: {
3865 setTypeForNode(node, SpecCell);
3866 clobberWorld();
3867 break;
3868 }
3869 case GetEnumeratorStructurePname: {
3870 setTypeForNode(node, SpecString | SpecOther);
3871 break;
3872 }
3873 case GetEnumeratorGenericPname: {
3874 setTypeForNode(node, SpecString | SpecOther);
3875 break;
3876 }
3877 case ToIndexString: {
3878 setTypeForNode(node, SpecString);
3879 break;
3880 }
3881
3882 case GetGlobalVar:
3883 makeHeapTopForNode(node);
3884 break;
3885
3886 case GetGlobalLexicalVariable:
3887 makeBytecodeTopForNode(node);
3888 break;
3889
3890 case GetDynamicVar:
3891 clobberWorld();
3892 makeBytecodeTopForNode(node);
3893 break;
3894
3895 case PutDynamicVar:
3896 clobberWorld();
3897 break;
3898
3899 case ResolveScope:
3900 clobberWorld();
3901 setTypeForNode(node, SpecObject);
3902 break;
3903
3904 case ResolveScopeForHoistingFuncDeclInEval:
3905 clobberWorld();
3906 makeBytecodeTopForNode(node);
3907 break;
3908
3909 case PutGlobalVariable:
3910 case NotifyWrite:
3911 break;
3912
3913 case OverridesHasInstance:
3914 setNonCellTypeForNode(node, SpecBoolean);
3915 break;
3916
3917 case InstanceOf:
3918 clobberWorld();
3919 setNonCellTypeForNode(node, SpecBoolean);
3920 break;
3921
3922 case InstanceOfCustom:
3923 clobberWorld();
3924 setNonCellTypeForNode(node, SpecBoolean);
3925 break;
3926
3927 case MatchStructure: {
3928 AbstractValue base = forNode(node->child1());
3929 RegisteredStructureSet baseSet;
3930
3931 BooleanLattice result = BooleanLattice::Bottom;
3932 for (MatchStructureVariant& variant : node->matchStructureData().variants) {
3933 RegisteredStructure structure = variant.structure;
3934 if (!base.contains(structure)) {
3935 m_state.setShouldTryConstantFolding(true);
3936 continue;
3937 }
3938
3939 baseSet.add(structure);
3940 result = leastUpperBoundOfBooleanLattices(
3941 result, variant.result ? BooleanLattice::True : BooleanLattice::False);
3942 }
3943
3944 if (forNode(node->child1()).changeStructure(m_graph, baseSet) == Contradiction)
3945 m_state.setIsValid(false);
3946
3947 switch (result) {
3948 case BooleanLattice::False:
3949 setConstant(node, jsBoolean(false));
3950 break;
3951 case BooleanLattice::True:
3952 setConstant(node, jsBoolean(true));
3953 break;
3954 default:
3955 setNonCellTypeForNode(node, SpecBoolean);
3956 break;
3957 }
3958 break;
3959 }
3960
3961 case Phi:
3962 RELEASE_ASSERT(m_graph.m_form == SSA);
3963 setForNode(node, forNode(NodeFlowProjection(node, NodeFlowProjection::Shadow)));
3964 // The state of this node would have already been decided, but it may have become a
3965 // constant, in which case we'd like to know.
3966 if (forNode(node).m_value)
3967 m_state.setShouldTryConstantFolding(true);
3968 break;
3969
3970 case Upsilon: {
3971 NodeFlowProjection shadow(node->phi(), NodeFlowProjection::Shadow);
3972 if (shadow.isStillValid()) {
3973 m_state.createValueForNode(shadow);
3974 setForNode(shadow, forNode(node->child1()));
3975 }
3976 break;
3977 }
3978
3979 case Flush:
3980 case PhantomLocal:
3981 break;
3982
3983 case Call:
3984 case TailCallInlinedCaller:
3985 case Construct:
3986 case CallVarargs:
3987 case CallForwardVarargs:
3988 case TailCallVarargsInlinedCaller:
3989 case ConstructVarargs:
3990 case ConstructForwardVarargs:
3991 case TailCallForwardVarargsInlinedCaller:
3992 case CallEval:
3993 case DirectCall:
3994 case DirectConstruct:
3995 case DirectTailCallInlinedCaller:
3996 clobberWorld();
3997 makeHeapTopForNode(node);
3998 break;
3999
4000 case ForceOSRExit:
4001 case CheckBadCell:
4002 m_state.setIsValid(false);
4003 break;
4004
4005 case InvalidationPoint:
4006 m_state.setStructureClobberState(StructuresAreWatched);
4007 m_state.observeInvalidationPoint();
4008 break;
4009
4010 case CPUIntrinsic:
4011 if (node->intrinsic() == CPURdtscIntrinsic)
4012 setNonCellTypeForNode(node, SpecInt32Only);
4013 else
4014 setNonCellTypeForNode(node, SpecOther);
4015 break;
4016
4017 case CheckTraps:
4018 case LogShadowChickenPrologue:
4019 case LogShadowChickenTail:
4020 case ProfileType:
4021 case ProfileControlFlow:
4022 case Phantom:
4023 case CountExecution:
4024 case CheckTierUpInLoop:
4025 case CheckTierUpAtReturn:
4026 case SuperSamplerBegin:
4027 case SuperSamplerEnd:
4028 case CheckTierUpAndOSREnter:
4029 case LoopHint:
4030 case ZombieHint:
4031 case ExitOK:
4032 case FilterCallLinkStatus:
4033 case FilterGetByStatus:
4034 case FilterPutByIdStatus:
4035 case FilterInByIdStatus:
4036 case ClearCatchLocals:
4037 break;
4038
4039 case CheckTypeInfoFlags: {
4040 const AbstractValue& abstractValue = forNode(node->child1());
4041 unsigned bits = node->typeInfoOperand();
4042 ASSERT(bits);
4043 if (bits == ImplementsDefaultHasInstance) {
4044 if (abstractValue.m_type == SpecFunctionWithDefaultHasInstance) {
4045 m_state.setShouldTryConstantFolding(true);
4046 break;
4047 }
4048 }
4049
4050 if (JSValue value = abstractValue.value()) {
4051 if (value.isCell()) {
4052 // This works because if we see a cell here, we know it's fully constructed
4053 // and we can read its inline type info flags. These flags don't change over the
4054 // object's lifetime.
4055 if ((value.asCell()->inlineTypeFlags() & bits) == bits) {
4056 m_state.setShouldTryConstantFolding(true);
4057 break;
4058 }
4059 }
4060 }
4061
4062 if (abstractValue.m_structure.isFinite()) {
4063 bool ok = true;
4064 abstractValue.m_structure.forEach([&] (RegisteredStructure structure) {
4065 ok &= (structure->typeInfo().inlineTypeFlags() & bits) == bits;
4066 });
4067 if (ok) {
4068 m_state.setShouldTryConstantFolding(true);
4069 break;
4070 }
4071 }
4072
4073 break;
4074 }
4075
4076 case ParseInt: {
4077 AbstractValue value = forNode(node->child1());
4078 if (value.m_type && !(value.m_type & ~SpecInt32Only)) {
4079 JSValue radix;
4080 if (!node->child2())
4081 radix = jsNumber(0);
4082 else
4083 radix = forNode(node->child2()).m_value;
4084
4085 if (radix.isNumber()
4086 && (radix.asNumber() == 0 || radix.asNumber() == 10)) {
4087 m_state.setShouldTryConstantFolding(true);
4088 if (node->child1().useKind() == UntypedUse)
4089 didFoldClobberWorld();
4090 setNonCellTypeForNode(node, SpecInt32Only);
4091 break;
4092 }
4093 }
4094
4095 if (node->child1().useKind() == UntypedUse)
4096 clobberWorld();
4097 setNonCellTypeForNode(node, SpecBytecodeNumber);
4098 break;
4099 }
4100
4101 case CreateRest:
4102 if (!m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
4103 // This means we're already having a bad time.
4104 clobberWorld();
4105 setTypeForNode(node, SpecArray);
4106 break;
4107 }
4108 setForNode(node,
4109 m_graph.globalObjectFor(node->origin.semantic)->restParameterStructure());
4110 break;
4111
4112 case CheckVarargs:
4113 case Check: {
4114 // Simplify out checks that don't actually do checking.
4115 m_graph.doToChildren(node, [&] (Edge edge) {
4116 if (!edge)
4117 return;
4118 if (edge.isProved() || edge.willNotHaveCheck())
4119 m_state.setShouldTryConstantFolding(true);
4120 });
4121 break;
4122 }
4123
4124 case SetFunctionName: {
4125 clobberWorld();
4126 break;
4127 }
4128
4129 case StoreBarrier:
4130 case FencedStoreBarrier: {
4131 filter(node->child1(), SpecCell);
4132 break;
4133 }
4134
4135 case DataViewGetInt: {
4136 DataViewData data = node->dataViewData();
4137 if (data.byteSize < 4)
4138 setNonCellTypeForNode(node, SpecInt32Only);
4139 else {
4140 ASSERT(data.byteSize == 4);
4141 if (data.isSigned)
4142 setNonCellTypeForNode(node, SpecInt32Only);
4143 else
4144 setNonCellTypeForNode(node, SpecInt52Any);
4145 }
4146 break;
4147 }
4148
4149 case DataViewGetFloat: {
4150 setNonCellTypeForNode(node, SpecFullDouble);
4151 break;
4152 }
4153
4154 case DateGetInt32OrNaN: {
4155 setNonCellTypeForNode(node, SpecInt32Only | SpecDoublePureNaN);
4156 break;
4157 }
4158
4159 case DateGetTime: {
4160 setNonCellTypeForNode(node, SpecFullDouble);
4161 break;
4162 }
4163
4164 case DataViewSet: {
4165 break;
4166 }
4167
4168 case Unreachable:
4169 // It may be that during a previous run of AI we proved that something was unreachable, but
4170 // during this run of AI we forget that it's unreachable. AI's proofs don't have to get
4171 // monotonically stronger over time. So, we don't assert that AI doesn't reach the
4172 // Unreachable. We have no choice but to take our past proof at face value. Otherwise we'll
4173 // crash whenever AI fails to be as powerful on run K as it was on run K-1.
4174 m_state.setIsValid(false);
4175 break;
4176
4177 case LastNodeType:
4178 case ArithIMul:
4179 case FiatInt52:
4180 DFG_CRASH(m_graph, node, "Unexpected node type");
4181 break;
4182 }
4183
4184 return m_state.isValid();
4185}
4186
4187template<typename AbstractStateType>
4188void AbstractInterpreter<AbstractStateType>::filterICStatus(Node* node)
4189{
4190 switch (node->op()) {
4191 case FilterCallLinkStatus:
4192 if (JSValue value = forNode(node->child1()).m_value)
4193 node->callLinkStatus()->filter(m_vm, value);
4194 break;
4195
4196 case FilterGetByStatus: {
4197 AbstractValue& value = forNode(node->child1());
4198 if (value.m_structure.isFinite())
4199 node->getByStatus()->filter(value.m_structure.toStructureSet());
4200 break;
4201 }
4202
4203 case FilterInByIdStatus: {
4204 AbstractValue& value = forNode(node->child1());
4205 if (value.m_structure.isFinite())
4206 node->inByIdStatus()->filter(value.m_structure.toStructureSet());
4207 break;
4208 }
4209
4210 case FilterPutByIdStatus: {
4211 AbstractValue& value = forNode(node->child1());
4212 if (value.m_structure.isFinite())
4213 node->putByIdStatus()->filter(value.m_structure.toStructureSet());
4214 break;
4215 }
4216
4217 default:
4218 RELEASE_ASSERT_NOT_REACHED();
4219 break;
4220 }
4221}
4222
4223template<typename AbstractStateType>
4224bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned indexInBlock)
4225{
4226 return executeEffects(indexInBlock, m_state.block()->at(indexInBlock));
4227}
4228
4229template<typename AbstractStateType>
4230bool AbstractInterpreter<AbstractStateType>::execute(unsigned indexInBlock)
4231{
4232 Node* node = m_state.block()->at(indexInBlock);
4233
4234 startExecuting();
4235 executeEdges(node);
4236 return executeEffects(indexInBlock, node);
4237}
4238
4239template<typename AbstractStateType>
4240bool AbstractInterpreter<AbstractStateType>::execute(Node* node)
4241{
4242 startExecuting();
4243 executeEdges(node);
4244 return executeEffects(UINT_MAX, node);
4245}
4246
4247template<typename AbstractStateType>
4248void AbstractInterpreter<AbstractStateType>::clobberWorld()
4249{
4250 clobberStructures();
4251}
4252
4253template<typename AbstractStateType>
4254void AbstractInterpreter<AbstractStateType>::didFoldClobberWorld()
4255{
4256 didFoldClobberStructures();
4257}
4258
4259template<typename AbstractStateType>
4260template<typename Functor>
4261void AbstractInterpreter<AbstractStateType>::forAllValues(
4262 unsigned clobberLimit, Functor& functor)
4263{
4264 if (clobberLimit >= m_state.block()->size())
4265 clobberLimit = m_state.block()->size();
4266 else
4267 clobberLimit++;
4268 ASSERT(clobberLimit <= m_state.block()->size());
4269 for (size_t i = clobberLimit; i--;) {
4270 NodeFlowProjection::forEach(
4271 m_state.block()->at(i),
4272 [&] (NodeFlowProjection nodeProjection) {
4273 functor(forNode(nodeProjection));
4274 });
4275 }
4276 if (m_graph.m_form == SSA) {
4277 for (NodeFlowProjection node : m_state.block()->ssa->liveAtHead) {
4278 if (node.isStillValid())
4279 functor(forNode(node));
4280 }
4281 }
4282 for (size_t i = m_state.numberOfArguments(); i--;)
4283 functor(m_state.argument(i));
4284 for (size_t i = m_state.numberOfLocals(); i--;)
4285 functor(m_state.local(i));
4286}
4287
4288template<typename AbstractStateType>
4289void AbstractInterpreter<AbstractStateType>::clobberStructures()
4290{
4291 m_state.clobberStructures();
4292 m_state.mergeClobberState(AbstractInterpreterClobberState::ClobberedStructures);
4293 m_state.setStructureClobberState(StructuresAreClobbered);
4294}
4295
4296template<typename AbstractStateType>
4297void AbstractInterpreter<AbstractStateType>::didFoldClobberStructures()
4298{
4299 m_state.mergeClobberState(AbstractInterpreterClobberState::FoldedClobber);
4300}
4301
4302template<typename AbstractStateType>
4303void AbstractInterpreter<AbstractStateType>::observeTransition(
4304 unsigned clobberLimit, RegisteredStructure from, RegisteredStructure to)
4305{
4306 // Stop performing precise structure transition tracking.
4307 // Precise structure transition tracking shows quadratic complexity for # of nodes in a basic block.
4308 // If it is too large, we conservatively clobber all the structures.
4309 if (m_state.block()->size() > Options::maxDFGNodesInBasicBlockForPreciseAnalysis()) {
4310 clobberStructures();
4311 return;
4312 }
4313
4314 AbstractValue::TransitionObserver transitionObserver(from, to);
4315 forAllValues(clobberLimit, transitionObserver);
4316
4317 ASSERT(!from->dfgShouldWatch()); // We don't need to claim to be in a clobbered state because 'from' was never watchable (during the time we were compiling), hence no constants ever introduced into the DFG IR that ever had a watchable structure would ever have the same structure as from.
4318
4319 m_state.mergeClobberState(AbstractInterpreterClobberState::ObservedTransitions);
4320}
4321
4322template<typename AbstractStateType>
4323void AbstractInterpreter<AbstractStateType>::observeTransitions(
4324 unsigned clobberLimit, const TransitionVector& vector)
4325{
4326 if (vector.isEmpty())
4327 return;
4328
4329 // Stop performing precise structure transition tracking.
4330 // Precise structure transition tracking shows quadratic complexity for # of nodes in a basic block.
4331 // If it is too large, we conservatively clobber all the structures.
4332 if (m_state.block()->size() > Options::maxDFGNodesInBasicBlockForPreciseAnalysis()) {
4333 clobberStructures();
4334 return;
4335 }
4336
4337 AbstractValue::TransitionsObserver transitionsObserver(vector);
4338 forAllValues(clobberLimit, transitionsObserver);
4339
4340 if (!ASSERT_DISABLED) {
4341 // We don't need to claim to be in a clobbered state because none of the Transition::previous structures are watchable.
4342 for (unsigned i = vector.size(); i--;)
4343 ASSERT(!vector[i].previous->dfgShouldWatch());
4344 }
4345
4346 m_state.mergeClobberState(AbstractInterpreterClobberState::ObservedTransitions);
4347}
4348
4349template<typename AbstractStateType>
4350void AbstractInterpreter<AbstractStateType>::dump(PrintStream& out) const
4351{
4352 const_cast<AbstractInterpreter<AbstractStateType>*>(this)->dump(out);
4353}
4354
4355template<typename AbstractStateType>
4356void AbstractInterpreter<AbstractStateType>::dump(PrintStream& out)
4357{
4358 CommaPrinter comma(" ");
4359 HashSet<NodeFlowProjection> seen;
4360 if (m_graph.m_form == SSA) {
4361 for (NodeFlowProjection node : m_state.block()->ssa->liveAtHead) {
4362 seen.add(node);
4363 AbstractValue& value = forNode(node);
4364 if (value.isClear())
4365 continue;
4366 out.print(comma, node, ":", value);
4367 }
4368 }
4369 for (size_t i = 0; i < m_state.block()->size(); ++i) {
4370 NodeFlowProjection::forEach(
4371 m_state.block()->at(i), [&] (NodeFlowProjection nodeProjection) {
4372 seen.add(nodeProjection);
4373 AbstractValue& value = forNode(nodeProjection);
4374 if (value.isClear())
4375 return;
4376 out.print(comma, nodeProjection, ":", value);
4377 });
4378 }
4379 if (m_graph.m_form == SSA) {
4380 for (NodeFlowProjection node : m_state.block()->ssa->liveAtTail) {
4381 if (seen.contains(node))
4382 continue;
4383 AbstractValue& value = forNode(node);
4384 if (value.isClear())
4385 continue;
4386 out.print(comma, node, ":", value);
4387 }
4388 }
4389}
4390
4391template<typename AbstractStateType>
4392FiltrationResult AbstractInterpreter<AbstractStateType>::filter(
4393 AbstractValue& value, const RegisteredStructureSet& set, SpeculatedType admittedTypes)
4394{
4395 if (value.filter(m_graph, set, admittedTypes) == FiltrationOK)
4396 return FiltrationOK;
4397 m_state.setIsValid(false);
4398 return Contradiction;
4399}
4400
4401template<typename AbstractStateType>
4402FiltrationResult AbstractInterpreter<AbstractStateType>::filterArrayModes(
4403 AbstractValue& value, ArrayModes arrayModes)
4404{
4405 if (value.filterArrayModes(arrayModes) == FiltrationOK)
4406 return FiltrationOK;
4407 m_state.setIsValid(false);
4408 return Contradiction;
4409}
4410
4411template<typename AbstractStateType>
4412FiltrationResult AbstractInterpreter<AbstractStateType>::filter(
4413 AbstractValue& value, SpeculatedType type)
4414{
4415 if (value.filter(type) == FiltrationOK)
4416 return FiltrationOK;
4417 m_state.setIsValid(false);
4418 return Contradiction;
4419}
4420
4421template<typename AbstractStateType>
4422FiltrationResult AbstractInterpreter<AbstractStateType>::filterByValue(
4423 AbstractValue& abstractValue, FrozenValue concreteValue)
4424{
4425 if (abstractValue.filterByValue(concreteValue) == FiltrationOK)
4426 return FiltrationOK;
4427 m_state.setIsValid(false);
4428 return Contradiction;
4429}
4430
4431template<typename AbstractStateType>
4432FiltrationResult AbstractInterpreter<AbstractStateType>::filterClassInfo(
4433 AbstractValue& value, const ClassInfo* classInfo)
4434{
4435 if (value.filterClassInfo(m_graph, classInfo) == FiltrationOK)
4436 return FiltrationOK;
4437 m_state.setIsValid(false);
4438 return Contradiction;
4439}
4440
4441template<typename AbstractStateType>
4442void AbstractInterpreter<AbstractStateType>::executeDoubleUnaryOpEffects(Node* node, double(*equivalentFunction)(double))
4443{
4444 JSValue child = forNode(node->child1()).value();
4445 if (Optional<double> number = child.toNumberFromPrimitive()) {
4446 if (node->child1().useKind() != DoubleRepUse)
4447 didFoldClobberWorld();
4448 setConstant(node, jsDoubleNumber(equivalentFunction(*number)));
4449 return;
4450 }
4451 SpeculatedType type;
4452 if (node->child1().useKind() == DoubleRepUse)
4453 type = typeOfDoubleUnaryOp(forNode(node->child1()).m_type);
4454 else {
4455 clobberWorld();
4456 type = SpecBytecodeNumber;
4457 }
4458 setNonCellTypeForNode(node, type);
4459}
4460
4461} } // namespace JSC::DFG
4462
4463#endif // ENABLE(DFG_JIT)
4464