2 * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "DFGFixupPhase.h"
32 #include "DFGInsertionSet.h"
34 #include "DFGPredictionPropagationPhase.h"
35 #include "DFGVariableAccessDataDump.h"
36 #include "Operations.h"
38 namespace JSC { namespace DFG {
40 class FixupPhase : public Phase {
42 FixupPhase(Graph& graph)
43 : Phase(graph, "fixup")
44 , m_insertionSet(graph)
50 ASSERT(m_graph.m_fixpointState == BeforeFixpoint);
51 ASSERT(m_graph.m_form == ThreadedCPS);
53 m_profitabilityChanged = false;
54 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex)
55 fixupBlock(m_graph.block(blockIndex));
57 while (m_profitabilityChanged) {
58 m_profitabilityChanged = false;
60 for (unsigned i = m_graph.m_argumentPositions.size(); i--;)
61 m_graph.m_argumentPositions[i].mergeArgumentUnboxingAwareness();
63 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex)
64 fixupSetLocalsInBlock(m_graph.block(blockIndex));
71 void fixupBlock(BasicBlock* block)
75 ASSERT(block->isReachable);
77 for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
78 m_currentNode = block->at(m_indexInBlock);
79 fixupNode(m_currentNode);
81 m_insertionSet.execute(block);
84 void fixupNode(Node* node)
86 NodeType op = node->op();
88 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
89 dataLogF(" %s @%u: ", Graph::opName(op), node->index());
94 // This gets handled by fixupSetLocalsInBlock().
105 fixIntEdge(node->child1());
106 fixIntEdge(node->child2());
110 case UInt32ToNumber: {
111 fixEdge<KnownInt32Use>(node->child1());
115 case DoubleAsInt32: {
116 RELEASE_ASSERT_NOT_REACHED();
121 if (node->child1()->shouldSpeculateInt32()) {
122 fixEdge<Int32Use>(node->child1());
123 node->setOpAndDefaultFlags(Identity);
127 if (node->child1()->shouldSpeculateNumber()) {
128 fixEdge<NumberUse>(node->child1());
132 if (node->child1()->shouldSpeculateBoolean()) {
133 fixEdge<BooleanUse>(node->child1());
137 fixEdge<NotCellUse>(node->child1());
141 case Int32ToDouble: {
142 RELEASE_ASSERT_NOT_REACHED();
147 if (attemptToMakeIntegerAdd(node))
149 if (Node::shouldSpeculateNumberExpectingDefined(node->child1().node(), node->child2().node())) {
150 fixEdge<NumberUse>(node->child1());
151 fixEdge<NumberUse>(node->child2());
155 // FIXME: Optimize for the case where one of the operands is the
156 // empty string. Also consider optimizing for the case where we don't
157 // believe either side is the emtpy string. Both of these things should
160 if (node->child1()->shouldSpeculateString()
161 && attemptToMakeFastStringAdd<StringUse>(node, node->child1(), node->child2()))
163 if (node->child2()->shouldSpeculateString()
164 && attemptToMakeFastStringAdd<StringUse>(node, node->child2(), node->child1()))
166 if (node->child1()->shouldSpeculateStringObject()
167 && attemptToMakeFastStringAdd<StringObjectUse>(node, node->child1(), node->child2()))
169 if (node->child2()->shouldSpeculateStringObject()
170 && attemptToMakeFastStringAdd<StringObjectUse>(node, node->child2(), node->child1()))
172 if (node->child1()->shouldSpeculateStringOrStringObject()
173 && attemptToMakeFastStringAdd<StringOrStringObjectUse>(node, node->child1(), node->child2()))
175 if (node->child2()->shouldSpeculateStringOrStringObject()
176 && attemptToMakeFastStringAdd<StringOrStringObjectUse>(node, node->child2(), node->child1()))
188 if (attemptToMakeIntegerAdd(node))
190 fixEdge<NumberUse>(node->child1());
191 fixEdge<NumberUse>(node->child2());
196 if (m_graph.negateShouldSpeculateInt32(node)) {
197 fixEdge<Int32Use>(node->child1());
200 fixEdge<NumberUse>(node->child1());
205 if (m_graph.mulShouldSpeculateInt32(node)) {
206 fixEdge<Int32Use>(node->child1());
207 fixEdge<Int32Use>(node->child2());
210 fixEdge<NumberUse>(node->child1());
211 fixEdge<NumberUse>(node->child2());
217 if (Node::shouldSpeculateInt32ForArithmetic(node->child1().node(), node->child2().node())
218 && node->canSpeculateInt32()) {
219 if (isX86() || isARMv7s()) {
220 fixEdge<Int32Use>(node->child1());
221 fixEdge<Int32Use>(node->child2());
224 injectInt32ToDoubleNode(node->child1());
225 injectInt32ToDoubleNode(node->child2());
227 // We don't need to do ref'ing on the children because we're stealing them from
228 // the original division.
229 Node* newDivision = m_insertionSet.insertNode(
230 m_indexInBlock, SpecDouble, *node);
232 node->setOp(DoubleAsInt32);
233 node->children.initialize(Edge(newDivision, KnownNumberUse), Edge(), Edge());
236 fixEdge<NumberUse>(node->child1());
237 fixEdge<NumberUse>(node->child2());
243 if (Node::shouldSpeculateInt32ForArithmetic(node->child1().node(), node->child2().node())
244 && node->canSpeculateInt32()) {
245 fixEdge<Int32Use>(node->child1());
246 fixEdge<Int32Use>(node->child2());
249 fixEdge<NumberUse>(node->child1());
250 fixEdge<NumberUse>(node->child2());
255 if (node->child1()->shouldSpeculateInt32ForArithmetic()
256 && node->canSpeculateInt32()) {
257 fixEdge<Int32Use>(node->child1());
260 fixEdge<NumberUse>(node->child1());
265 fixEdge<NumberUse>(node->child1());
270 if (node->child1()->shouldSpeculateBoolean())
271 fixEdge<BooleanUse>(node->child1());
272 else if (node->child1()->shouldSpeculateObjectOrOther())
273 fixEdge<ObjectOrOtherUse>(node->child1());
274 else if (node->child1()->shouldSpeculateInt32())
275 fixEdge<Int32Use>(node->child1());
276 else if (node->child1()->shouldSpeculateNumber())
277 fixEdge<NumberUse>(node->child1());
282 if (node->child1()->shouldSpeculateString())
283 fixEdge<StringUse>(node->child1());
284 else if (node->child1()->shouldSpeculateCell())
285 fixEdge<CellUse>(node->child1());
289 case CompareEqConstant: {
297 case CompareGreaterEq: {
298 if (Node::shouldSpeculateInt32(node->child1().node(), node->child2().node())) {
299 fixEdge<Int32Use>(node->child1());
300 fixEdge<Int32Use>(node->child2());
303 if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
304 fixEdge<NumberUse>(node->child1());
305 fixEdge<NumberUse>(node->child2());
308 if (node->op() != CompareEq)
310 if (Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
311 fixEdge<BooleanUse>(node->child1());
312 fixEdge<BooleanUse>(node->child2());
315 if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) {
316 fixEdge<StringIdentUse>(node->child1());
317 fixEdge<StringIdentUse>(node->child2());
320 if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && GPRInfo::numberOfRegisters >= 7) {
321 fixEdge<StringUse>(node->child1());
322 fixEdge<StringUse>(node->child2());
325 if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
326 fixEdge<ObjectUse>(node->child1());
327 fixEdge<ObjectUse>(node->child2());
330 if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObjectOrOther()) {
331 fixEdge<ObjectUse>(node->child1());
332 fixEdge<ObjectOrOtherUse>(node->child2());
335 if (node->child1()->shouldSpeculateObjectOrOther() && node->child2()->shouldSpeculateObject()) {
336 fixEdge<ObjectOrOtherUse>(node->child1());
337 fixEdge<ObjectUse>(node->child2());
343 case CompareStrictEqConstant: {
347 case CompareStrictEq: {
348 if (Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
349 fixEdge<BooleanUse>(node->child1());
350 fixEdge<BooleanUse>(node->child2());
353 if (Node::shouldSpeculateInt32(node->child1().node(), node->child2().node())) {
354 fixEdge<Int32Use>(node->child1());
355 fixEdge<Int32Use>(node->child2());
358 if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
359 fixEdge<NumberUse>(node->child1());
360 fixEdge<NumberUse>(node->child2());
363 if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) {
364 fixEdge<StringIdentUse>(node->child1());
365 fixEdge<StringIdentUse>(node->child2());
368 if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && GPRInfo::numberOfRegisters >= 7) {
369 fixEdge<StringUse>(node->child1());
370 fixEdge<StringUse>(node->child2());
373 if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
374 fixEdge<ObjectUse>(node->child1());
375 fixEdge<ObjectUse>(node->child2());
381 case StringFromCharCode:
382 fixEdge<Int32Use>(node->child1());
386 case StringCharCodeAt: {
387 // Currently we have no good way of refining these.
388 ASSERT(node->arrayMode() == ArrayMode(Array::String));
389 blessArrayOperation(node->child1(), node->child2(), node->child3());
390 fixEdge<KnownCellUse>(node->child1());
391 fixEdge<Int32Use>(node->child2());
397 node->arrayMode().refine(
398 node->child1()->prediction(),
399 node->child2()->prediction(),
400 SpecNone, node->flags()));
402 blessArrayOperation(node->child1(), node->child2(), node->child3());
404 ArrayMode arrayMode = node->arrayMode();
405 switch (arrayMode.type()) {
407 if (arrayMode.arrayClass() == Array::OriginalArray
408 && arrayMode.speculation() == Array::InBounds
409 && m_graph.globalObjectFor(node->codeOrigin)->arrayPrototypeChainIsSane()
410 && !(node->flags() & NodeBytecodeUsesAsOther))
411 node->setArrayMode(arrayMode.withSpeculation(Array::SaneChain));
415 if ((node->prediction() & ~SpecString)
416 || m_graph.hasExitSite(node->codeOrigin, OutOfBounds))
417 node->setArrayMode(arrayMode.withSpeculation(Array::OutOfBounds));
424 switch (node->arrayMode().type()) {
425 case Array::SelectUsingPredictions:
426 case Array::Unprofiled:
427 case Array::Undecided:
428 RELEASE_ASSERT_NOT_REACHED();
431 #if USE(JSVALUE32_64)
432 fixEdge<CellUse>(node->child1()); // Speculating cell due to register pressure on 32-bit.
435 case Array::ForceExit:
438 fixEdge<KnownCellUse>(node->child1());
439 fixEdge<Int32Use>(node->child2());
447 case PutByValAlias: {
448 Edge& child1 = m_graph.varArgChild(node, 0);
449 Edge& child2 = m_graph.varArgChild(node, 1);
450 Edge& child3 = m_graph.varArgChild(node, 2);
453 node->arrayMode().refine(
454 child1->prediction(),
455 child2->prediction(),
456 child3->prediction()));
458 blessArrayOperation(child1, child2, m_graph.varArgChild(node, 3));
460 switch (node->arrayMode().modeForPut().type()) {
461 case Array::SelectUsingPredictions:
462 case Array::Unprofiled:
463 case Array::Undecided:
464 RELEASE_ASSERT_NOT_REACHED();
466 case Array::ForceExit:
468 #if USE(JSVALUE32_64)
469 // Due to register pressure on 32-bit, we speculate cell and
470 // ignore the base-is-not-cell case entirely by letting the
471 // baseline JIT handle it.
472 fixEdge<CellUse>(child1);
476 fixEdge<KnownCellUse>(child1);
477 fixEdge<Int32Use>(child2);
478 fixEdge<Int32Use>(child3);
481 fixEdge<KnownCellUse>(child1);
482 fixEdge<Int32Use>(child2);
483 fixEdge<RealNumberUse>(child3);
485 case Array::Int8Array:
486 case Array::Int16Array:
487 case Array::Int32Array:
488 case Array::Uint8Array:
489 case Array::Uint8ClampedArray:
490 case Array::Uint16Array:
491 case Array::Uint32Array:
492 fixEdge<KnownCellUse>(child1);
493 fixEdge<Int32Use>(child2);
494 if (child3->shouldSpeculateInt32())
495 fixEdge<Int32Use>(child3);
497 fixEdge<NumberUse>(child3);
499 case Array::Float32Array:
500 case Array::Float64Array:
501 fixEdge<KnownCellUse>(child1);
502 fixEdge<Int32Use>(child2);
503 fixEdge<NumberUse>(child3);
506 fixEdge<KnownCellUse>(child1);
507 fixEdge<Int32Use>(child2);
514 // May need to refine the array mode in case the value prediction contravenes
515 // the array prediction. For example, we may have evidence showing that the
516 // array is in Int32 mode, but the value we're storing is likely to be a double.
517 // Then we should turn this into a conversion to Double array followed by the
518 // push. On the other hand, we absolutely don't want to refine based on the
519 // base prediction. If it has non-cell garbage in it, then we want that to be
520 // ignored. That's because ArrayPush can't handle any array modes that aren't
521 // array-related - so if refine() turned this into a "Generic" ArrayPush then
522 // that would break things.
524 node->arrayMode().refine(
525 node->child1()->prediction() & SpecCell,
527 node->child2()->prediction()));
528 blessArrayOperation(node->child1(), Edge(), node->child3());
529 fixEdge<KnownCellUse>(node->child1());
531 switch (node->arrayMode().type()) {
533 fixEdge<Int32Use>(node->child2());
536 fixEdge<RealNumberUse>(node->child2());
545 blessArrayOperation(node->child1(), Edge(), node->child2());
546 fixEdge<KnownCellUse>(node->child1());
552 fixEdge<CellUse>(node->child1());
553 fixEdge<CellUse>(node->child2());
558 if (node->child1()->shouldSpeculateBoolean())
559 fixEdge<BooleanUse>(node->child1());
560 else if (node->child1()->shouldSpeculateObjectOrOther())
561 fixEdge<ObjectOrOtherUse>(node->child1());
562 else if (node->child1()->shouldSpeculateInt32())
563 fixEdge<Int32Use>(node->child1());
564 else if (node->child1()->shouldSpeculateNumber())
565 fixEdge<NumberUse>(node->child1());
567 Node* logicalNot = node->child1().node();
568 if (logicalNot->op() == LogicalNot) {
570 // Make sure that OSR exit can't observe the LogicalNot. If it can,
571 // then we must compute it and cannot peephole around it.
574 for (unsigned i = m_indexInBlock; i--;) {
575 Node* candidate = m_block->at(i);
576 if (candidate == logicalNot) {
580 if (candidate->canExit()) {
586 ASSERT_UNUSED(found, found);
589 Edge newChildEdge = logicalNot->child1();
590 if (newChildEdge->hasBooleanResult()) {
591 node->children.setChild1(newChildEdge);
593 BasicBlock* toBeTaken = node->notTakenBlock();
594 BasicBlock* toBeNotTaken = node->takenBlock();
595 node->setTakenBlock(toBeTaken);
596 node->setNotTakenBlock(toBeNotTaken);
604 SwitchData* data = node->switchData();
605 switch (data->kind) {
607 if (node->child1()->shouldSpeculateInt32())
608 fixEdge<Int32Use>(node->child1());
611 if (node->child1()->shouldSpeculateString())
612 fixEdge<StringUse>(node->child1());
615 if (node->child1()->shouldSpeculateStringIdent())
616 fixEdge<StringIdentUse>(node->child1());
617 else if (node->child1()->shouldSpeculateString())
618 fixEdge<StringUse>(node->child1());
625 fixupToPrimitive(node);
634 case NewStringObject: {
635 fixEdge<KnownStringUse>(node->child1());
640 for (unsigned i = m_graph.varArgNumChildren(node); i--;) {
641 node->setIndexingType(
642 leastUpperBoundOfIndexingTypeAndType(
643 node->indexingType(), m_graph.varArgChild(node, i)->prediction()));
645 switch (node->indexingType()) {
646 case ALL_BLANK_INDEXING_TYPES:
649 case ALL_UNDECIDED_INDEXING_TYPES:
650 if (node->numChildren()) {
651 // This will only happen if the children have no type predictions. We
652 // would have already exited by now, but insert a forced exit just to
654 m_insertionSet.insertNode(
655 m_indexInBlock, SpecNone, ForceOSRExit, node->codeOrigin);
658 case ALL_INT32_INDEXING_TYPES:
659 for (unsigned operandIndex = 0; operandIndex < node->numChildren(); ++operandIndex)
660 fixEdge<Int32Use>(m_graph.m_varArgChildren[node->firstChild() + operandIndex]);
662 case ALL_DOUBLE_INDEXING_TYPES:
663 for (unsigned operandIndex = 0; operandIndex < node->numChildren(); ++operandIndex)
664 fixEdge<RealNumberUse>(m_graph.m_varArgChildren[node->firstChild() + operandIndex]);
666 case ALL_CONTIGUOUS_INDEXING_TYPES:
667 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
676 case NewTypedArray: {
677 if (node->child1()->shouldSpeculateInt32()) {
678 fixEdge<Int32Use>(node->child1());
679 node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
685 case NewArrayWithSize: {
686 fixEdge<Int32Use>(node->child1());
691 ECMAMode ecmaMode = m_graph.executableFor(node->codeOrigin)->isStrictMode() ? StrictMode : NotStrictMode;
693 if (isOtherSpeculation(node->child1()->prediction())) {
694 if (ecmaMode == StrictMode) {
695 fixEdge<OtherUse>(node->child1());
696 node->convertToIdentity();
700 m_insertionSet.insertNode(
701 m_indexInBlock, SpecNone, Phantom, node->codeOrigin,
702 Edge(node->child1().node(), OtherUse));
703 observeUseKindOnNode<OtherUse>(node->child1().node());
704 node->convertToWeakConstant(m_graph.globalThisObjectFor(node->codeOrigin));
708 if (isFinalObjectSpeculation(node->child1()->prediction())) {
709 fixEdge<FinalObjectUse>(node->child1());
710 node->convertToIdentity();
717 case GetMyArgumentByVal:
718 case GetMyArgumentByValSafe: {
719 fixEdge<Int32Use>(node->child1());
723 case GetClosureRegisters:
730 case AllocatePropertyStorage:
731 case ReallocatePropertyStorage:
733 fixEdge<KnownCellUse>(node->child1());
739 if (!node->child1()->shouldSpeculateCell())
741 StringImpl* impl = m_graph.identifiers()[node->identifierNumber()];
742 if (impl == vm().propertyNames->length.impl()) {
743 attemptToMakeGetArrayLength(node);
746 if (impl == vm().propertyNames->byteLength.impl()) {
747 attemptToMakeGetTypedArrayByteLength(node);
750 if (impl == vm().propertyNames->byteOffset.impl()) {
751 attemptToMakeGetTypedArrayByteOffset(node);
754 fixEdge<CellUse>(node->child1());
758 case CheckExecutable:
760 case StructureTransitionWatchpoint:
764 case CheckHasInstance:
767 fixEdge<CellUse>(node->child1());
772 switch (node->arrayMode().type()) {
774 fixEdge<StringUse>(node->child1());
777 fixEdge<CellUse>(node->child1());
784 case ArrayifyToStructure: {
785 fixEdge<CellUse>(node->child1());
787 fixEdge<Int32Use>(node->child2());
792 if (!node->child1()->hasStorageResult())
793 fixEdge<KnownCellUse>(node->child1());
794 fixEdge<KnownCellUse>(node->child2());
799 if (!node->child1()->hasStorageResult())
800 fixEdge<KnownCellUse>(node->child1());
801 fixEdge<KnownCellUse>(node->child2());
806 // FIXME: This appears broken: CheckHasInstance already does an unconditional cell
807 // check. https://bugs.webkit.org/show_bug.cgi?id=107479
808 if (!(node->child1()->prediction() & ~SpecCell))
809 fixEdge<CellUse>(node->child1());
810 fixEdge<CellUse>(node->child2());
815 // FIXME: We should at some point have array profiling on op_in, in which
816 // case we would be able to turn this into a kind of GetByVal.
818 fixEdge<CellUse>(node->child2());
824 switch (node->child1().useKind()) {
826 if (node->child1()->shouldSpeculateInt32ForArithmetic())
827 node->child1().setUseKind(Int32Use);
832 observeUseKindOnEdge(node->child1());
840 case PhantomPutStructure:
841 case GetIndexedPropertyStorage:
842 case GetTypedArrayByteOffset:
845 case MovHintAndCheck:
847 case CheckTierUpInLoop:
848 case CheckTierUpAtReturn:
849 case CheckTierUpAndOSREnter:
850 RELEASE_ASSERT_NOT_REACHED();
854 // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
862 case GetLocalUnlinked:
868 case GlobalVarWatchpoint:
869 case VarInjectionWatchpoint:
870 case AllocationProfileWatchpoint:
883 case CreateActivation:
884 case TearOffActivation:
885 case CreateArguments:
886 case PhantomArguments:
887 case TearOffArguments:
888 case GetMyArgumentsLength:
889 case GetMyArgumentsLengthSafe:
890 case CheckArgumentsNotCreated:
892 case NewFunctionNoCheck:
893 case NewFunctionExpression:
897 case ThrowReferenceError:
900 case CheckWatchdogTimer:
902 case ExtractOSREntryLocal:
911 DFG_NODE_DO_TO_CHILDREN(m_graph, node, observeUntypedEdge);
913 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
914 if (!(node->flags() & NodeHasVarArgs)) {
915 dataLogF("new children: ");
916 node->dumpChildren(WTF::dataFile());
922 void observeUntypedEdge(Node*, Edge& edge)
924 if (edge.useKind() != UntypedUse)
926 fixEdge<UntypedUse>(edge);
929 template<UseKind useKind>
930 void createToString(Node* node, Edge& edge)
932 edge.setNode(m_insertionSet.insertNode(
933 m_indexInBlock, SpecString, ToString, node->codeOrigin,
934 Edge(edge.node(), useKind)));
937 template<UseKind useKind>
938 void attemptToForceStringArrayModeByToStringConversion(ArrayMode& arrayMode, Node* node)
940 ASSERT(arrayMode == ArrayMode(Array::Generic));
942 if (!canOptimizeStringObjectAccess(node->codeOrigin))
945 createToString<useKind>(node, node->child1());
946 arrayMode = ArrayMode(Array::String);
949 template<UseKind useKind>
950 bool isStringObjectUse()
953 case StringObjectUse:
954 case StringOrStringObjectUse:
961 template<UseKind useKind>
962 void convertStringAddUse(Node* node, Edge& edge)
964 if (useKind == StringUse) {
965 // This preserves the binaryUseKind() invariant ot ValueAdd: ValueAdd's
966 // two edges will always have identical use kinds, which makes the
967 // decision process much easier.
968 observeUseKindOnNode<StringUse>(edge.node());
969 m_insertionSet.insertNode(
970 m_indexInBlock, SpecNone, Phantom, node->codeOrigin,
971 Edge(edge.node(), StringUse));
972 edge.setUseKind(KnownStringUse);
976 // FIXME: We ought to be able to have a ToPrimitiveToString node.
978 observeUseKindOnNode<useKind>(edge.node());
979 createToString<useKind>(node, edge);
982 void convertToMakeRope(Node* node)
984 node->setOpAndDefaultFlags(MakeRope);
988 void fixupMakeRope(Node* node)
990 for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
991 Edge& edge = node->children.child(i);
994 edge.setUseKind(KnownStringUse);
995 if (!m_graph.isConstant(edge.node()))
997 JSString* string = jsCast<JSString*>(m_graph.valueOfJSConstant(edge.node()).asCell());
998 if (string->length())
1001 // Don't allow the MakeRope to have zero children.
1002 if (!i && !node->child2())
1005 node->children.removeEdge(i--);
1008 if (!node->child2()) {
1009 ASSERT(!node->child3());
1010 node->convertToIdentity();
1014 void fixupToPrimitive(Node* node)
1016 if (node->child1()->shouldSpeculateInt32()) {
1017 fixEdge<Int32Use>(node->child1());
1018 node->convertToIdentity();
1022 if (node->child1()->shouldSpeculateString()) {
1023 fixEdge<StringUse>(node->child1());
1024 node->convertToIdentity();
1028 if (node->child1()->shouldSpeculateStringObject()
1029 && canOptimizeStringObjectAccess(node->codeOrigin)) {
1030 fixEdge<StringObjectUse>(node->child1());
1031 node->convertToToString();
1035 if (node->child1()->shouldSpeculateStringOrStringObject()
1036 && canOptimizeStringObjectAccess(node->codeOrigin)) {
1037 fixEdge<StringOrStringObjectUse>(node->child1());
1038 node->convertToToString();
1043 void fixupToString(Node* node)
1045 if (node->child1()->shouldSpeculateString()) {
1046 fixEdge<StringUse>(node->child1());
1047 node->convertToIdentity();
1051 if (node->child1()->shouldSpeculateStringObject()
1052 && canOptimizeStringObjectAccess(node->codeOrigin)) {
1053 fixEdge<StringObjectUse>(node->child1());
1057 if (node->child1()->shouldSpeculateStringOrStringObject()
1058 && canOptimizeStringObjectAccess(node->codeOrigin)) {
1059 fixEdge<StringOrStringObjectUse>(node->child1());
1063 if (node->child1()->shouldSpeculateCell()) {
1064 fixEdge<CellUse>(node->child1());
1069 template<UseKind leftUseKind>
1070 bool attemptToMakeFastStringAdd(Node* node, Edge& left, Edge& right)
1072 Node* originalLeft = left.node();
1073 Node* originalRight = right.node();
1075 ASSERT(leftUseKind == StringUse || leftUseKind == StringObjectUse || leftUseKind == StringOrStringObjectUse);
1077 if (isStringObjectUse<leftUseKind>() && !canOptimizeStringObjectAccess(node->codeOrigin))
1080 convertStringAddUse<leftUseKind>(node, left);
1082 if (right->shouldSpeculateString())
1083 convertStringAddUse<StringUse>(node, right);
1084 else if (right->shouldSpeculateStringObject() && canOptimizeStringObjectAccess(node->codeOrigin))
1085 convertStringAddUse<StringObjectUse>(node, right);
1086 else if (right->shouldSpeculateStringOrStringObject() && canOptimizeStringObjectAccess(node->codeOrigin))
1087 convertStringAddUse<StringOrStringObjectUse>(node, right);
1089 // At this point we know that the other operand is something weird. The semantically correct
1090 // way of dealing with this is:
1092 // MakeRope(@left, ToString(ToPrimitive(@right)))
1094 // So that's what we emit. NB, we need to do all relevant type checks on @left before we do
1095 // anything to @right, since ToPrimitive may be effectful.
1097 Node* toPrimitive = m_insertionSet.insertNode(
1098 m_indexInBlock, resultOfToPrimitive(right->prediction()), ToPrimitive, node->codeOrigin,
1099 Edge(right.node()));
1100 Node* toString = m_insertionSet.insertNode(
1101 m_indexInBlock, SpecString, ToString, node->codeOrigin, Edge(toPrimitive));
1103 fixupToPrimitive(toPrimitive);
1104 fixupToString(toString);
1106 right.setNode(toString);
1109 // We're doing checks up there, so we need to make sure that the
1110 // *original* inputs to the addition are live up to here.
1111 m_insertionSet.insertNode(
1112 m_indexInBlock, SpecNone, Phantom, node->codeOrigin,
1113 Edge(originalLeft), Edge(originalRight));
1115 convertToMakeRope(node);
1119 bool isStringPrototypeMethodSane(Structure* stringPrototypeStructure, StringImpl* uid)
1121 unsigned attributesUnused;
1122 JSCell* specificValue;
1123 PropertyOffset offset = stringPrototypeStructure->getConcurrently(
1124 vm(), uid, attributesUnused, specificValue);
1125 if (!isValidOffset(offset))
1131 if (!specificValue->inherits(JSFunction::info()))
1134 JSFunction* function = jsCast<JSFunction*>(specificValue);
1135 if (function->executable()->intrinsicFor(CodeForCall) != StringPrototypeValueOfIntrinsic)
1141 bool canOptimizeStringObjectAccess(const CodeOrigin& codeOrigin)
1143 if (m_graph.hasExitSite(codeOrigin, NotStringObject))
1146 Structure* stringObjectStructure = m_graph.globalObjectFor(codeOrigin)->stringObjectStructure();
1147 ASSERT(stringObjectStructure->storedPrototype().isObject());
1148 ASSERT(stringObjectStructure->storedPrototype().asCell()->classInfo() == StringPrototype::info());
1150 JSObject* stringPrototypeObject = asObject(stringObjectStructure->storedPrototype());
1151 Structure* stringPrototypeStructure = stringPrototypeObject->structure();
1152 if (!m_graph.watchpoints().isStillValid(stringPrototypeStructure->transitionWatchpointSet()))
1155 if (stringPrototypeStructure->isDictionary())
1158 // We're being conservative here. We want DFG's ToString on StringObject to be
1159 // used in both numeric contexts (that would call valueOf()) and string contexts
1160 // (that would call toString()). We don't want the DFG to have to distinguish
1161 // between the two, just because that seems like it would get confusing. So we
1162 // just require both methods to be sane.
1163 if (!isStringPrototypeMethodSane(stringPrototypeStructure, vm().propertyNames->valueOf.impl()))
1165 if (!isStringPrototypeMethodSane(stringPrototypeStructure, vm().propertyNames->toString.impl()))
1171 void fixupSetLocalsInBlock(BasicBlock* block)
1175 ASSERT(block->isReachable);
1177 for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
1178 Node* node = m_currentNode = block->at(m_indexInBlock);
1179 if (node->op() != SetLocal)
1182 VariableAccessData* variable = node->variableAccessData();
1183 switch (variable->flushFormat()) {
1184 case FlushedJSValue:
1187 fixEdge<NumberUse>(node->child1(), ForwardSpeculation);
1190 fixEdge<Int32Use>(node->child1());
1193 fixEdge<CellUse>(node->child1());
1195 case FlushedBoolean:
1196 fixEdge<BooleanUse>(node->child1());
1199 RELEASE_ASSERT_NOT_REACHED();
1203 m_insertionSet.execute(block);
1206 Node* checkArray(ArrayMode arrayMode, const CodeOrigin& codeOrigin, Node* array, Node* index, bool (*storageCheck)(const ArrayMode&) = canCSEStorage)
1208 ASSERT(arrayMode.isSpecific());
1210 Structure* structure = arrayMode.originalArrayStructure(m_graph, codeOrigin);
1212 Edge indexEdge = index ? Edge(index, Int32Use) : Edge();
1214 if (arrayMode.doesConversion()) {
1216 m_insertionSet.insertNode(
1217 m_indexInBlock, SpecNone, ArrayifyToStructure, codeOrigin,
1218 OpInfo(structure), OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
1220 m_insertionSet.insertNode(
1221 m_indexInBlock, SpecNone, Arrayify, codeOrigin,
1222 OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
1226 m_insertionSet.insertNode(
1227 m_indexInBlock, SpecNone, CheckStructure, codeOrigin,
1228 OpInfo(m_graph.addStructureSet(structure)), Edge(array, CellUse));
1230 m_insertionSet.insertNode(
1231 m_indexInBlock, SpecNone, CheckArray, codeOrigin,
1232 OpInfo(arrayMode.asWord()), Edge(array, CellUse));
1236 if (!storageCheck(arrayMode))
1239 if (arrayMode.usesButterfly()) {
1240 return m_insertionSet.insertNode(
1241 m_indexInBlock, SpecNone, GetButterfly, codeOrigin, Edge(array, CellUse));
1244 return m_insertionSet.insertNode(
1245 m_indexInBlock, SpecNone, GetIndexedPropertyStorage, codeOrigin,
1246 OpInfo(arrayMode.asWord()), Edge(array, KnownCellUse));
1249 void blessArrayOperation(Edge base, Edge index, Edge& storageChild)
1251 Node* node = m_currentNode;
1253 switch (node->arrayMode().type()) {
1254 case Array::ForceExit: {
1255 m_insertionSet.insertNode(
1256 m_indexInBlock, SpecNone, ForceOSRExit, node->codeOrigin);
1260 case Array::SelectUsingPredictions:
1261 case Array::Unprofiled:
1262 RELEASE_ASSERT_NOT_REACHED();
1265 case Array::Generic:
1269 Node* storage = checkArray(node->arrayMode(), node->codeOrigin, base.node(), index.node());
1273 storageChild = Edge(storage);
1278 bool alwaysUnboxSimplePrimitives()
1283 // Any boolean, int, or cell value is profitable to unbox on 32-bit because it
1289 template<UseKind useKind>
1290 void observeUseKindOnNode(Node* node)
1292 if (useKind == UntypedUse)
1294 observeUseKindOnNode(node, useKind);
1297 void observeUseKindOnEdge(Edge edge)
1299 observeUseKindOnNode(edge.node(), edge.useKind());
1302 void observeUseKindOnNode(Node* node, UseKind useKind)
1304 if (node->op() != GetLocal)
1307 VariableAccessData* variable = node->variableAccessData();
1310 if (alwaysUnboxSimplePrimitives()
1311 || isInt32Speculation(variable->prediction()))
1312 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
1316 if (variable->doubleFormatState() == UsingDoubleFormat)
1317 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
1320 if (alwaysUnboxSimplePrimitives()
1321 || isBooleanSpeculation(variable->prediction()))
1322 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
1328 case KnownStringUse:
1329 case StringObjectUse:
1330 case StringOrStringObjectUse:
1331 if (alwaysUnboxSimplePrimitives()
1332 || isCellSpeculation(variable->prediction()))
1333 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
1340 // Set the use kind of the edge and perform any actions that need to be done for
1341 // that use kind, like inserting intermediate conversion nodes. Never call this
1342 // with useKind = UntypedUse explicitly; edges have UntypedUse implicitly and any
1343 // edge that survives fixup and still has UntypedUse will have this method called
1344 // from observeUntypedEdge(). Also, make sure that if you do change the type of an
1345 // edge, you either call fixEdge() or perform the equivalent functionality
1346 // yourself. Obviously, you should have a really good reason if you do the latter.
1347 template<UseKind useKind>
1348 void fixEdge(Edge& edge, SpeculationDirection direction = BackwardSpeculation)
1350 if (isDouble(useKind) && edge->shouldSpeculateInt32ForArithmetic()) {
1351 injectInt32ToDoubleNode(edge, useKind, direction);
1355 observeUseKindOnNode<useKind>(edge.node());
1356 edge.setUseKind(useKind);
1359 void fixIntEdge(Edge& edge)
1361 Node* node = edge.node();
1362 if (node->op() != ValueToInt32) {
1363 fixEdge<KnownInt32Use>(edge);
1367 Edge newEdge = node->child1();
1369 if (newEdge.useKind() != Int32Use) {
1370 edge.setUseKind(KnownInt32Use);
1374 ASSERT(newEdge->shouldSpeculateInt32());
1378 void injectInt32ToDoubleNode(Edge& edge, UseKind useKind = NumberUse, SpeculationDirection direction = BackwardSpeculation)
1380 Node* result = m_insertionSet.insertNode(
1381 m_indexInBlock, SpecInt48, Int32ToDouble,
1382 m_currentNode->codeOrigin, Edge(edge.node(), NumberUse));
1383 if (direction == ForwardSpeculation)
1384 result->mergeFlags(NodeExitsForward);
1386 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
1388 "(replacing @%u->@%u with @%u->@%u) ",
1389 m_currentNode->index(), edge->index(), m_currentNode->index(), result->index());
1392 edge = Edge(result, useKind);
1395 void truncateConstantToInt32(Edge& edge)
1397 Node* oldNode = edge.node();
1399 ASSERT(oldNode->hasConstant());
1400 JSValue value = m_graph.valueOfJSConstant(oldNode);
1401 if (value.isInt32())
1404 value = jsNumber(JSC::toInt32(value.asNumber()));
1405 ASSERT(value.isInt32());
1406 unsigned constantRegister;
1407 if (!codeBlock()->findConstant(value, constantRegister)) {
1408 constantRegister = codeBlock()->addConstantLazily();
1409 initializeLazyWriteBarrierForConstant(
1410 m_graph.m_plan.writeBarriers,
1411 codeBlock()->constants()[constantRegister],
1414 codeBlock()->ownerExecutable(),
1417 edge.setNode(m_insertionSet.insertNode(
1418 m_indexInBlock, SpecInt32, JSConstant, m_currentNode->codeOrigin,
1419 OpInfo(constantRegister)));
1422 void truncateConstantsIfNecessary(Node* node, AddSpeculationMode mode)
1424 if (mode != SpeculateInt32AndTruncateConstants)
1427 ASSERT(node->child1()->hasConstant() || node->child2()->hasConstant());
1428 if (node->child1()->hasConstant())
1429 truncateConstantToInt32(node->child1());
1431 truncateConstantToInt32(node->child2());
1434 bool attemptToMakeIntegerAdd(Node* node)
1436 AddSpeculationMode mode = m_graph.addSpeculationMode(node);
1437 if (mode == DontSpeculateInt32)
1440 truncateConstantsIfNecessary(node, mode);
1441 fixEdge<Int32Use>(node->child1());
1442 fixEdge<Int32Use>(node->child2());
1446 bool attemptToMakeGetArrayLength(Node* node)
1448 if (!isInt32Speculation(node->prediction()))
1450 CodeBlock* profiledBlock = m_graph.baselineCodeBlockFor(node->codeOrigin);
1451 ArrayProfile* arrayProfile =
1452 profiledBlock->getArrayProfile(node->codeOrigin.bytecodeIndex);
1453 ArrayMode arrayMode = ArrayMode(Array::SelectUsingPredictions);
1455 ConcurrentJITLocker locker(profiledBlock->m_lock);
1456 arrayProfile->computeUpdatedPrediction(locker, profiledBlock);
1457 arrayMode = ArrayMode::fromObserved(locker, arrayProfile, Array::Read, false);
1458 if (arrayMode.type() == Array::Unprofiled) {
1459 // For normal array operations, it makes sense to treat Unprofiled
1460 // accesses as ForceExit and get more data rather than using
1461 // predictions and then possibly ending up with a Generic. But here,
1462 // we treat anything that is Unprofiled as Generic and keep the
1463 // GetById. I.e. ForceExit = Generic. So, there is no harm - and only
1464 // profit - from treating the Unprofiled case as
1465 // SelectUsingPredictions.
1466 arrayMode = ArrayMode(Array::SelectUsingPredictions);
1470 arrayMode = arrayMode.refine(node->child1()->prediction(), node->prediction());
1472 if (arrayMode.type() == Array::Generic) {
1473 // Check if the input is something that we can't get array length for, but for which we
1474 // could insert some conversions in order to transform it into something that we can do it
1476 if (node->child1()->shouldSpeculateStringObject())
1477 attemptToForceStringArrayModeByToStringConversion<StringObjectUse>(arrayMode, node);
1478 else if (node->child1()->shouldSpeculateStringOrStringObject())
1479 attemptToForceStringArrayModeByToStringConversion<StringOrStringObjectUse>(arrayMode, node);
1482 if (!arrayMode.supportsLength())
1485 convertToGetArrayLength(node, arrayMode);
1489 bool attemptToMakeGetTypedArrayByteLength(Node* node)
1491 if (!isInt32Speculation(node->prediction()))
1494 TypedArrayType type = typedArrayTypeFromSpeculation(node->child1()->prediction());
1495 if (!isTypedView(type))
1498 if (elementSize(type) == 1) {
1499 convertToGetArrayLength(node, ArrayMode(toArrayType(type)));
1503 Node* length = prependGetArrayLength(
1504 node->codeOrigin, node->child1().node(), ArrayMode(toArrayType(type)));
1506 Node* shiftAmount = m_insertionSet.insertNode(
1507 m_indexInBlock, SpecInt32, JSConstant, node->codeOrigin,
1508 OpInfo(m_graph.constantRegisterForConstant(jsNumber(logElementSize(type)))));
1510 // We can use a BitLShift here because typed arrays will never have a byteLength
1511 // that overflows int32.
1512 node->setOp(BitLShift);
1513 node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
1514 observeUseKindOnNode(length, Int32Use);
1515 observeUseKindOnNode(shiftAmount, Int32Use);
1516 node->child1() = Edge(length, Int32Use);
1517 node->child2() = Edge(shiftAmount, Int32Use);
1521 void convertToGetArrayLength(Node* node, ArrayMode arrayMode)
1523 node->setOp(GetArrayLength);
1524 node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
1525 fixEdge<KnownCellUse>(node->child1());
1526 node->setArrayMode(arrayMode);
1528 Node* storage = checkArray(arrayMode, node->codeOrigin, node->child1().node(), 0, lengthNeedsStorage);
1532 node->child2() = Edge(storage);
1535 Node* prependGetArrayLength(CodeOrigin codeOrigin, Node* child, ArrayMode arrayMode)
1537 Node* storage = checkArray(arrayMode, codeOrigin, child, 0, lengthNeedsStorage);
1538 return m_insertionSet.insertNode(
1539 m_indexInBlock, SpecInt32, GetArrayLength, codeOrigin,
1540 OpInfo(arrayMode.asWord()), Edge(child, KnownCellUse), Edge(storage));
1543 bool attemptToMakeGetTypedArrayByteOffset(Node* node)
1545 if (!isInt32Speculation(node->prediction()))
1548 TypedArrayType type = typedArrayTypeFromSpeculation(node->child1()->prediction());
1549 if (!isTypedView(type))
1553 ArrayMode(toArrayType(type)), node->codeOrigin, node->child1().node(),
1554 0, neverNeedsStorage);
1556 node->setOp(GetTypedArrayByteOffset);
1557 node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
1558 fixEdge<KnownCellUse>(node->child1());
1562 BasicBlock* m_block;
1563 unsigned m_indexInBlock;
1564 Node* m_currentNode;
1565 InsertionSet m_insertionSet;
1566 bool m_profitabilityChanged;
1569 bool performFixup(Graph& graph)
1571 SamplingRegion samplingRegion("DFG Fixup Phase");
1572 return runPhase<FixupPhase>(graph);
1575 } } // namespace JSC::DFG
1577 #endif // ENABLE(DFG_JIT)