Unreviewed, rolling out r215476.
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGNode.h
index 88f8811..0d98caf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -42,6 +42,8 @@
 #include "DFGNodeType.h"
 #include "DFGObjectMaterializationData.h"
 #include "DFGOpInfo.h"
+#include "DFGRegisteredStructure.h"
+#include "DFGRegisteredStructureSet.h"
 #include "DFGTransition.h"
 #include "DFGUseKind.h"
 #include "DFGVariableAccessData.h"
@@ -55,6 +57,7 @@
 #include "ValueProfile.h"
 #include <type_traits>
 #include <wtf/ListDump.h>
+#include <wtf/LoggingHashSet.h>
 
 namespace JSC {
 
@@ -62,6 +65,7 @@ namespace DOMJIT {
 class GetterSetter;
 class Patchpoint;
 class CallDOMGetterPatchpoint;
+class Signature;
 }
 
 namespace Profiler {
@@ -243,6 +247,8 @@ struct CallDOMGetterData {
 // Node represents a single operation in the data flow graph.
 struct Node {
 public:
+    static const char HashSetTemplateInstantiationString[];
+    
     enum VarArgTag { VarArg };
     
     Node() { }
@@ -409,10 +415,10 @@ public:
 
     void remove();
 
-    void convertToCheckStructure(StructureSet* set)
+    void convertToCheckStructure(RegisteredStructureSet* set)
     {
         setOpAndDefaultFlags(CheckStructure);
-        m_opInfo = set; 
+        m_opInfo = set;
     }
 
     void convertToCheckStructureImmediate(Node* structure)
@@ -458,7 +464,6 @@ public:
             
         case PhantomDirectArguments:
         case PhantomClonedArguments:
-        case PhantomCreateRest:
             // These pretend to be the empty value constant for the benefit of the DFG backend, which
             // otherwise wouldn't take kindly to a node that doesn't compute a value.
             return true;
@@ -472,7 +477,7 @@ public:
     {
         ASSERT(hasConstant());
         
-        if (op() == PhantomDirectArguments || op() == PhantomClonedArguments || op() == PhantomCreateRest) {
+        if (op() == PhantomDirectArguments || op() == PhantomClonedArguments) {
             // These pretend to be the empty value constant for the benefit of the DFG backend, which
             // otherwise wouldn't take kindly to a node that doesn't compute a value.
             return FrozenValue::emptySingleton();
@@ -533,7 +538,7 @@ public:
     
     void convertToGetByOffset(StorageAccessData& data, Edge storage, Edge base)
     {
-        ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == PureGetById || m_op == MultiGetByOffset);
+        ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == MultiGetByOffset);
         m_opInfo = &data;
         children.setChild1(storage);
         children.setChild2(base);
@@ -543,7 +548,7 @@ public:
     
     void convertToMultiGetByOffset(MultiGetByOffsetData* data)
     {
-        ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == PureGetById);
+        ASSERT(m_op == GetById || m_op == GetByIdFlush);
         m_opInfo = data;
         child1().setUseKind(CellUse);
         m_op = MultiGetByOffset;
@@ -586,7 +591,7 @@ public:
 
     void convertToPhantomNewFunction()
     {
-        ASSERT(m_op == NewFunction || m_op == NewGeneratorFunction);
+        ASSERT(m_op == NewFunction || m_op == NewGeneratorFunction || m_op == NewAsyncFunction);
         m_op = PhantomNewFunction;
         m_flags |= NodeMustGenerate;
         m_opInfo = OpInfoWrapper();
@@ -604,6 +609,16 @@ public:
         children = AdjacencyList();
     }
 
+    void convertToPhantomNewAsyncFunction()
+    {
+        ASSERT(m_op == NewAsyncFunction);
+        m_op = PhantomNewAsyncFunction;
+        m_flags |= NodeMustGenerate;
+        m_opInfo = OpInfoWrapper();
+        m_opInfo2 = OpInfoWrapper();
+        children = AdjacencyList();
+    }
+
     void convertToPhantomCreateActivation()
     {
         ASSERT(m_op == CreateActivation || m_op == MaterializeCreateActivation);
@@ -652,6 +667,8 @@ public:
     }
     
     void convertToDirectCall(FrozenValue*);
+
+    void convertToCallDOM(Graph&);
     
     JSValue asJSValue()
     {
@@ -724,17 +741,17 @@ public:
     }
      
     template<typename T>
-    T dynamicCastConstant()
+    T dynamicCastConstant(VM& vm)
     {
         if (!isCellConstant())
             return nullptr;
-        return jsDynamicCast<T>(asCell());
+        return jsDynamicCast<T>(vm, asCell());
     }
     
     template<typename T>
-    T castConstant()
+    T castConstant(VM& vm)
     {
-        T result = dynamicCastConstant<T>();
+        T result = dynamicCastConstant<T>(vm);
         RELEASE_ASSERT(result);
         return result;
     }
@@ -919,7 +936,6 @@ public:
         switch (op()) {
         case TryGetById:
         case GetById:
-        case PureGetById:
         case GetByIdFlush:
         case GetByIdWithThis:
         case PutById:
@@ -1059,6 +1075,12 @@ public:
         }
     }
 
+    BitVector* bitVector()
+    {
+        ASSERT(op() == NewArrayWithSpread || op() == PhantomNewArrayWithSpread);
+        return m_opInfo.as<BitVector*>();
+    }
+
     // Return the indexing type that an array allocation *wants* to use. It may end up using a different
     // type if we're having a bad time. You can determine the actual indexing type by asking the global
     // object:
@@ -1430,7 +1452,6 @@ public:
         case ArithCeil:
         case ArithTrunc:
         case GetDirectPname:
-        case PureGetById:
         case GetById:
         case GetByIdFlush:
         case GetByIdWithThis:
@@ -1453,6 +1474,7 @@ public:
         case MultiGetByOffset:
         case GetClosureVar:
         case GetFromArguments:
+        case GetArgument:
         case ArrayPop:
         case ArrayPush:
         case RegExpExec:
@@ -1464,6 +1486,17 @@ public:
         case ToNumber:
         case LoadFromJSMapBucket:
         case CallDOMGetter:
+        case CallDOM:
+        case ParseInt:
+        case AtomicsAdd:
+        case AtomicsAnd:
+        case AtomicsCompareExchange:
+        case AtomicsExchange:
+        case AtomicsLoad:
+        case AtomicsOr:
+        case AtomicsStore:
+        case AtomicsSub:
+        case AtomicsXor:
             return true;
         default:
             return false;
@@ -1489,6 +1522,7 @@ public:
         case OverridesHasInstance:
         case NewFunction:
         case NewGeneratorFunction:
+        case NewAsyncFunction:
         case CreateActivation:
         case MaterializeCreateActivation:
         case NewRegexp:
@@ -1595,10 +1629,10 @@ public:
         }
     }
     
-    StructureSet& structureSet()
+    const RegisteredStructureSet& structureSet()
     {
         ASSERT(hasStructureSet());
-        return *m_opInfo.as<StructureSet*>();
+        return *m_opInfo.as<RegisteredStructureSet*>();
     }
     
     bool hasStructure()
@@ -1613,10 +1647,10 @@ public:
         }
     }
     
-    Structure* structure()
+    RegisteredStructure structure()
     {
         ASSERT(hasStructure());
-        return m_opInfo.as<Structure*>();
+        return m_opInfo.asRegisteredStructure();
     }
     
     bool hasStorageAccessData()
@@ -1724,6 +1758,7 @@ public:
         switch (op()) {
         case NewFunction:
         case NewGeneratorFunction:
+        case NewAsyncFunction:
             return true;
         default:
             return false;
@@ -1735,6 +1770,7 @@ public:
         switch (op()) {
         case PhantomNewFunction:
         case PhantomNewGeneratorFunction:
+        case PhantomNewAsyncFunction:
             return true;
         default:
             return false;
@@ -1747,9 +1783,12 @@ public:
         case PhantomNewObject:
         case PhantomDirectArguments:
         case PhantomCreateRest:
+        case PhantomSpread:
+        case PhantomNewArrayWithSpread:
         case PhantomClonedArguments:
         case PhantomNewFunction:
         case PhantomNewGeneratorFunction:
+        case PhantomNewAsyncFunction:
         case PhantomCreateActivation:
             return true;
         default:
@@ -1762,6 +1801,7 @@ public:
         switch (op()) {
         case GetIndexedPropertyStorage:
         case GetArrayLength:
+        case In:
         case PutByValDirect:
         case PutByVal:
         case PutByValAlias:
@@ -1774,6 +1814,15 @@ public:
         case ArrayPush:
         case ArrayPop:
         case HasIndexedProperty:
+        case AtomicsAdd:
+        case AtomicsAnd:
+        case AtomicsCompareExchange:
+        case AtomicsExchange:
+        case AtomicsLoad:
+        case AtomicsOr:
+        case AtomicsStore:
+        case AtomicsSub:
+        case AtomicsXor:
             return true;
         default:
             return false;
@@ -1877,9 +1926,11 @@ public:
         return m_refCount;
     }
     
+    // Return true if the execution of this Node does not affect our ability to OSR to the FTL.
+    // FIXME: Isn't this just like checking if the node has effects?
     bool isSemanticallySkippable()
     {
-        return op() == CountExecution;
+        return op() == CountExecution || op() == InvalidationPoint;
     }
 
     unsigned refCount()
@@ -1981,6 +2032,11 @@ public:
     {
         return isInt32Speculation(prediction());
     }
+
+    bool shouldSpeculateNotInt32()
+    {
+        return isNotInt32Speculation(prediction());
+    }
     
     bool sawBooleans()
     {
@@ -2041,6 +2097,11 @@ public:
     {
         return isBooleanSpeculation(prediction());
     }
+
+    bool shouldSpeculateNotBoolean()
+    {
+        return isNotBooleanSpeculation(prediction());
+    }
     
     bool shouldSpeculateOther()
     {
@@ -2066,6 +2127,11 @@ public:
     {
         return isStringSpeculation(prediction());
     }
+
+    bool shouldSpeculateNotString()
+    {
+        return isNotStringSpeculation(prediction());
+    }
  
     bool shouldSpeculateStringOrOther()
     {
@@ -2368,6 +2434,35 @@ public:
         return m_opInfo2.as<const ClassInfo*>();
     }
 
+    bool hasSignature() const
+    {
+        // Note that this does not include TailCall node types intentionally.
+        // CallDOM node types are always converted from Call.
+        return op() == Call || op() == CallDOM;
+    }
+
+    const DOMJIT::Signature* signature()
+    {
+        return m_opInfo.as<const DOMJIT::Signature*>();
+    }
+
+    bool hasInternalMethodType() const
+    {
+        return op() == HasIndexedProperty;
+    }
+
+    PropertySlot::InternalMethodType internalMethodType() const
+    {
+        ASSERT(hasInternalMethodType());
+        return static_cast<PropertySlot::InternalMethodType>(m_opInfo2.as<uint32_t>());
+    }
+
+    void setInternalMethodType(PropertySlot::InternalMethodType type)
+    {
+        ASSERT(hasInternalMethodType());
+        m_opInfo2 = static_cast<uint32_t>(type);
+    }
+
     Node* replacement() const
     {
         return m_misc.replacement;
@@ -2394,6 +2489,17 @@ public:
         return m_opInfo.as<unsigned>();
     }
 
+    bool hasArgumentIndex()
+    {
+        return op() == GetArgument;
+    }
+
+    unsigned argumentIndex()
+    {
+        ASSERT(hasArgumentIndex());
+        return m_opInfo.as<unsigned>();
+    }
+
     void dumpChildren(PrintStream& out)
     {
         if (!child1())
@@ -2451,6 +2557,11 @@ private:
             u.int64 = 0;
             u.constPointer = constPointer;
         }
+        OpInfoWrapper(RegisteredStructure structure)
+        {
+            u.int64 = 0;
+            u.pointer = bitwise_cast<void*>(structure);
+        }
         OpInfoWrapper& operator=(uint32_t int32)
         {
             u.int64 = 0;
@@ -2480,6 +2591,12 @@ private:
             u.constPointer = constPointer;
             return *this;
         }
+        OpInfoWrapper& operator=(RegisteredStructure structure)
+        {
+            u.int64 = 0;
+            u.pointer = bitwise_cast<void*>(structure);
+            return *this;
+        }
         template <typename T>
         ALWAYS_INLINE auto as() const -> typename std::enable_if<std::is_pointer<T>::value && !std::is_const<typename std::remove_pointer<T>::type>::value, T>::type
         {
@@ -2500,6 +2617,11 @@ private:
         {
             return u.int64;
         }
+        ALWAYS_INLINE RegisteredStructure asRegisteredStructure() const
+        {
+            return bitwise_cast<RegisteredStructure>(u.pointer);
+        }
+
         union {
             uint32_t int32;
             uint64_t int64;
@@ -2529,15 +2651,22 @@ public:
     BasicBlock* owner;
 };
 
-inline bool nodeComparator(Node* a, Node* b)
-{
-    return a->index() < b->index();
-}
+// Uncomment this to log NodeSet operations.
+// typedef LoggingHashSet<Node::HashSetTemplateInstantiationString, Node*> NodeSet;
+typedef HashSet<Node*> NodeSet;
+
+struct NodeComparator {
+    template<typename NodePtrType>
+    bool operator()(NodePtrType a, NodePtrType b) const
+    {
+        return a->index() < b->index();
+    }
+};
 
 template<typename T>
 CString nodeListDump(const T& nodeList)
 {
-    return sortedListDump(nodeList, nodeComparator);
+    return sortedListDump(nodeList, NodeComparator());
 }
 
 template<typename T>
@@ -2548,7 +2677,7 @@ CString nodeMapDump(const T& nodeMap, DumpContext* context = 0)
         typename T::const_iterator iter = nodeMap.begin();
         iter != nodeMap.end(); ++iter)
         keys.append(iter->key);
-    std::sort(keys.begin(), keys.end(), nodeComparator);
+    std::sort(keys.begin(), keys.end(), NodeComparator());
     StringPrintStream out;
     CommaPrinter comma;
     for(unsigned i = 0; i < keys.size(); ++i)
@@ -2562,7 +2691,7 @@ CString nodeValuePairListDump(const T& nodeValuePairList, DumpContext* context =
     using V = typename T::ValueType;
     T sortedList = nodeValuePairList;
     std::sort(sortedList.begin(), sortedList.end(), [](const V& a, const V& b) {
-        return nodeComparator(a.node, b.node);
+        return NodeComparator()(a.node, b.node);
     });
 
     StringPrintStream out;
@@ -2581,6 +2710,14 @@ void printInternal(PrintStream&, JSC::DFG::Node*);
 
 inline JSC::DFG::Node* inContext(JSC::DFG::Node* node, JSC::DumpContext*) { return node; }
 
+template<>
+struct LoggingHashKeyTraits<JSC::DFG::Node*> {
+    static void print(PrintStream& out, JSC::DFG::Node* key)
+    {
+        out.print("bitwise_cast<::JSC::DFG::Node*>(", RawPointer(key), "lu)");
+    }
+};
+
 } // namespace WTF
 
 using WTF::inContext;