/* * Copyright (C) 2013-2020 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "DFGNode.h" #if ENABLE(DFG_JIT) #include "DFGGraph.h" #include "DFGPromotedHeapLocation.h" #include "DOMJITSignature.h" #include "JSImmutableButterfly.h" namespace JSC { namespace DFG { const char Node::HashSetTemplateInstantiationString[] = "::JSC::DFG::Node*"; DEFINE_ALLOCATOR_WITH_HEAP_IDENTIFIER(DFGNode); bool MultiPutByOffsetData::writesStructures() const { for (unsigned i = variants.size(); i--;) { if (variants[i].writesStructures()) return true; } return false; } bool MultiPutByOffsetData::reallocatesStorage() const { for (unsigned i = variants.size(); i--;) { if (variants[i].reallocatesStorage()) return true; } return false; } bool MultiDeleteByOffsetData::writesStructures() const { for (unsigned i = variants.size(); i--;) { if (variants[i].writesStructures()) return true; } return false; } bool MultiDeleteByOffsetData::allVariantsStoreEmpty() const { for (unsigned i = variants.size(); i--;) { if (!variants[i].newStructure()) return false; } return true; } void BranchTarget::dump(PrintStream& out) const { if (!block) return; out.print(*block); if (count == count) // If the count is not NaN, then print it. out.print("/w:", count); } bool Node::hasVariableAccessData(Graph& graph) { switch (op()) { case Phi: return graph.m_form != SSA; case GetLocal: case SetLocal: case SetArgumentDefinitely: case SetArgumentMaybe: case Flush: case PhantomLocal: return true; default: return false; } } void Node::remove(Graph& graph) { switch (op()) { case MultiGetByOffset: { MultiGetByOffsetData& data = multiGetByOffsetData(); StructureSet set; for (MultiGetByOffsetCase& getCase : data.cases) { getCase.set().forEach( [&] (RegisteredStructure structure) { set.add(structure.get()); }); } convertToCheckStructure(graph.addStructureSet(set)); return; } case MatchStructure: { MatchStructureData& data = matchStructureData(); RegisteredStructureSet set; for (MatchStructureVariant& variant : data.variants) set.add(variant.structure); convertToCheckStructure(graph.addStructureSet(set)); return; } default: if (flags() & NodeHasVarArgs) { unsigned targetIndex = 0; for (unsigned i = 0; i < numChildren(); ++i) { Edge& edge = graph.varArgChild(this, i); if (!edge) continue; if (edge.willHaveCheck()) { Edge& dst = graph.varArgChild(this, targetIndex++); std::swap(dst, edge); continue; } edge = Edge(); } setOpAndDefaultFlags(CheckVarargs); children.setNumChildren(targetIndex); } else { children = children.justChecks(); setOpAndDefaultFlags(Check); } return; } } void Node::removeWithoutChecks() { children = AdjacencyList(); setOpAndDefaultFlags(Check); } void Node::replaceWith(Graph& graph, Node* other) { remove(graph); setReplacement(other); } void Node::replaceWithWithoutChecks(Node* other) { removeWithoutChecks(); setReplacement(other); } void Node::convertToIdentity() { RELEASE_ASSERT(child1()); RELEASE_ASSERT(!child2()); NodeFlags result = canonicalResultRepresentation(this->result()); setOpAndDefaultFlags(Identity); setResult(result); } void Node::convertToIdentityOn(Node* child) { children.reset(); clearFlags(NodeHasVarArgs); child1() = child->defaultEdge(); NodeFlags output = canonicalResultRepresentation(this->result()); NodeFlags input = canonicalResultRepresentation(child->result()); if (output == input) { setOpAndDefaultFlags(Identity); setResult(output); return; } switch (output) { case NodeResultDouble: setOpAndDefaultFlags(DoubleRep); switch (input) { case NodeResultInt52: child1().setUseKind(Int52RepUse); return; case NodeResultJS: child1().setUseKind(NumberUse); return; default: RELEASE_ASSERT_NOT_REACHED(); return; } case NodeResultInt52: setOpAndDefaultFlags(Int52Rep); switch (input) { case NodeResultDouble: child1().setUseKind(DoubleRepAnyIntUse); return; case NodeResultJS: child1().setUseKind(AnyIntUse); return; default: RELEASE_ASSERT_NOT_REACHED(); return; } case NodeResultJS: setOpAndDefaultFlags(ValueRep); switch (input) { case NodeResultDouble: child1().setUseKind(DoubleRepUse); return; case NodeResultInt52: child1().setUseKind(Int52RepUse); return; default: RELEASE_ASSERT_NOT_REACHED(); return; } default: RELEASE_ASSERT_NOT_REACHED(); return; } } void Node::convertToLazyJSConstant(Graph& graph, LazyJSValue value) { m_op = LazyJSConstant; m_flags &= ~NodeMustGenerate; m_opInfo = graph.m_lazyJSValues.add(value); children.reset(); } void Node::convertToNewArrayBuffer(FrozenValue* immutableButterfly) { setOpAndDefaultFlags(NewArrayBuffer); NewArrayBufferData data { }; data.indexingMode = immutableButterfly->cast<JSImmutableButterfly*>()->indexingMode(); data.vectorLengthHint = immutableButterfly->cast<JSImmutableButterfly*>()->toButterfly()->vectorLength(); children.reset(); m_opInfo = immutableButterfly; m_opInfo2 = data.asQuadWord; } void Node::convertToDirectCall(FrozenValue* executable) { NodeType newOp = LastNodeType; switch (op()) { case Call: newOp = DirectCall; break; case Construct: newOp = DirectConstruct; break; case TailCallInlinedCaller: newOp = DirectTailCallInlinedCaller; break; case TailCall: newOp = DirectTailCall; break; default: RELEASE_ASSERT_NOT_REACHED(); break; } m_op = newOp; m_opInfo = executable; } void Node::convertToCallDOM(Graph& graph) { ASSERT(op() == Call); ASSERT(signature()); Edge edges[3]; // Skip the first one. This is callee. RELEASE_ASSERT(numChildren() <= 4); for (unsigned i = 1; i < numChildren(); ++i) edges[i - 1] = graph.varArgChild(this, i); setOpAndDefaultFlags(CallDOM); children.setChild1(edges[0]); children.setChild2(edges[1]); children.setChild3(edges[2]); if (!signature()->effect.mustGenerate()) clearFlags(NodeMustGenerate); } void Node::convertToRegExpExecNonGlobalOrStickyWithoutChecks(FrozenValue* regExp) { ASSERT(op() == RegExpExec); setOpAndDefaultFlags(RegExpExecNonGlobalOrSticky); children.child1() = Edge(children.child1().node(), KnownCellUse); children.child2() = Edge(children.child3().node(), KnownStringUse); children.child3() = Edge(); m_opInfo = regExp; } void Node::convertToRegExpMatchFastGlobalWithoutChecks(FrozenValue* regExp) { ASSERT(op() == RegExpMatchFast); setOpAndDefaultFlags(RegExpMatchFastGlobal); children.child1() = Edge(children.child1().node(), KnownCellUse); children.child2() = Edge(children.child3().node(), KnownStringUse); children.child3() = Edge(); m_opInfo = regExp; } String Node::tryGetString(Graph& graph) { if (hasConstant()) return constant()->tryGetString(graph); if (hasLazyJSValue()) return lazyJSValue().tryGetString(graph); return String(); } PromotedLocationDescriptor Node::promotedLocationDescriptor() { return PromotedLocationDescriptor(static_cast<PromotedLocationKind>(m_opInfo.as<uint32_t>()), m_opInfo2.as<uint32_t>()); } } } // namespace JSC::DFG namespace WTF { using namespace JSC; using namespace JSC::DFG; void printInternal(PrintStream& out, SwitchKind kind) { switch (kind) { case SwitchImm: out.print("SwitchImm"); return; case SwitchChar: out.print("SwitchChar"); return; case SwitchString: out.print("SwitchString"); return; case SwitchCell: out.print("SwitchCell"); return; } RELEASE_ASSERT_NOT_REACHED(); } void printInternal(PrintStream& out, Node* node) { if (!node) { out.print("-"); return; } out.print("D@", node->index()); if (node->hasDoubleResult()) out.print("<Double>"); else if (node->hasInt52Result()) out.print("<Int52>"); } } // namespace WTF #endif // ENABLE(DFG_JIT)