예제 #1
0
TR::Register *
OMR::CodeGenerator::evaluate(TR::Node * node)
   {
   TR::Register *reg;

   bool trace = self()->comp()->getOptions()->getTraceCGOption(TR_TraceCGEvaluation);
   TR::ILOpCodes opcode = node->getOpCodeValue();

   TR_ASSERT(!self()->comp()->getOption(TR_EnableParanoidRefCountChecks) || node->getOpCode().isTreeTop() || node->getReferenceCount() > 0,
      "OMR::CodeGenerator::evaluate invoked for nontreetop node [%s] with count == 0", node->getName(self()->comp()->getDebug()));

   if (opcode != TR::BBStart && node->getRegister())
      {
      reg = node->getRegister();
      if (trace)
         {
         self()->getDebug()->printNodeEvaluation(node, ":  ", reg);
         }
      }
   else
      {
      if (trace)
         {
         self()->getDebug()->printNodeEvaluation(node);
         _indentation += 2;
         }

      // Evaluation of a TR IL tree can be performed by many functions:
      //
      // 1) evaluate(...)
      // 2) populateMemoryReference(...)
      // 3) populateAddTree(...)
      // ...
      //
      // However all of these functions can be categorized into two classes:
      //
      // A) functions which completely evaluate their subtree.
      // B) functions which partially evaluate their subtree.
      //
      // Because functions of class A and class B can be used interchangably to
      // perform a recursive decent of a TR IL tree, and because A or B functions
      // can perform a destructive evaluation of their subtree, a bug can occur where
      // the results of a partial evalutation are destructively overwritten before
      // being completely evalutated.
      //
      // Ex: the motivating case is the following evaluation pattern:
      //
      // node_A evaluate
      //    node_B populateMemoryReference
      //    node_C evaluate
      //
      // where
      //
      // a) there is a common node between the subtrees of node_B and node_C.
      // b) calling populateMemoryReference on node_B reduces the reference count of one
      //    of the base or index nodes to 1, creating the "opportunity" for a destructive
      //    evaluation.
      //
      // The following chain of events occurs:
      //
      // 1) evaluate is called on node_A. This evaluator can produce instructions of RX form,
      //    and chooses to do so for this node.
      //
      // 2) populateMemoryReference is called on node_B, and evaluates the subtree, returning
      //    a TR_MemoryReference to node_A's evaluator. This memory reference has not been
      //    dereferenced yet, and the base (and optionally index) nodes may have registers
      //    assigned to them.
      //
      // 3) evaluate is called on node_C, which chooses to destructively evaluate the commoned
      //    base node. The memory reference's base register now contains a garbage value.
      //
      // 4) control passes to node_A's evaluator, which emits an RX instruction using node_B's
      //    memory reference and node_C's register.
      //
      // In the past, the fix for this was to switch the order of evaluation: call evaluate
      // on node_C and then call populateMemoryReference on node_B. This fixes this scenario, but
      // the capability of another tree and evaluation pattern to create this bug still exists.
      //
      // As well, more insidious trees exist:
      //
      // ificmpeq
      //    iiload
      //       i2l
      //          x
      //    iiload
      //       ishl
      //          ==> i2l
      //          4
      //
      // The evaluation pattern here could be:
      //
      // evaluate
      //    populateMemoryReference
      //       evaluate
      //    populateMemoryReference
      //       evaluate
      //
      // If the commoned node's reference count is 2 coming into ificmpeq's evaluator, then
      // the second sub-evaluate call could be destructive to the first populateMemoryReference.
      //
      // Even worse, if either subtree could be destructive, then there would be no correct order to
      // perform the function calls:
      //
      // ificmpeq
      //    iiload
      //       ishl
      //          ==> x
      //          7
      //    iiload
      //       ishl
      //          ==> x
      //          4
      //
      // Generally, two conditions must be true for this bug to be possible:
      //
      // 1) the following two classes of recursive decent functions must exist:
      //    A) functions which completely evaluate their subtree.
      //    B) functions which partially evaluate their subtree.
      //
      // 2) destructive evaluation by either class of function must be possible.
      //
      // This code implements changes to eliminate the second condition for this bug by performing
      // the following check and fixup:
      //
      // If in a function which partially evaluates its subtree, note all non-restricted nodes that
      // have a reference count > 1. If any of those node's reference counts reach 1, then artificially
      // inflate those reference counts by 1 for the lifetime of the parent evaluation.
      //
      int32_t topOfNodeStackBeforeEvaluation = _stackOfArtificiallyInflatedNodes.topIndex();

      // Memory references are not like registers, and should not be allowed to escape their evaluator.
      // Explicitly note memory references that are not loaded into registers and automatically call
      // stopUsingMemRefRegister on all memory references that have "escaped".
      //
      // Only the s390 memory references are tracked in this way.
      //
      int32_t topOfMemRefStackBeforeEvaluation = _stackOfMemoryReferencesCreatedDuringEvaluation.topIndex();

      reg = _nodeToInstrEvaluators[opcode](node, self());

      if (self()->comp()->getOptions()->getTraceCGOption(TR_TraceCGEvaluation))
         {
         self()->getDebug()->printNodeEvaluation(node, "<- ", reg, false);
         _indentation -= 2;
         }
      if (self()->comp()->getOption(TR_TraceRegisterPressureDetails))
         {
         traceMsg(self()->comp(), "  evaluated %s", self()->getDebug()->getName(node));
         self()->getDebug()->dumpLiveRegisters();
         traceMsg(self()->comp(), "\n");
         }

      // Pop off and decrement tracked nodes
      //
      while (_stackOfArtificiallyInflatedNodes.topIndex() > topOfNodeStackBeforeEvaluation)
         {
         TR::Node * artificiallyInflatedNode = _stackOfArtificiallyInflatedNodes.pop();

         if (artificiallyInflatedNode->getReferenceCount() == 1)
            {
            // When inflating reference counts, two cases exist:
            //
            // 1) N's ref count reaches 1 in a populate* call, which is then inc'ed to 2.
            //
            // 1a) N is never evaluated, so the ref count never goes down to 1. (node was not commoned in another subtree)
            //
            //     - no tree difference should be seen in this case.
            //
            // 1b) N is evaluated, so the ref count then goes down to 1. (node was commoned in another subtree)
            //
            //     - register shuffling _could_ be seen in this case.
            //     - but a bug might have been avoided: partial and complete evaluation of a commoned node occurred.
            //
            if (self()->comp()->getOption(TR_TraceCG))
               {
               self()->comp()->getDebug()->trace(" _stackOfArtificiallyInflatedNodes.pop(): node %p part of commoned case, might have avoided a bug!\n", artificiallyInflatedNode);
               }
            }

         self()->decReferenceCount(artificiallyInflatedNode);

#ifdef J9_PROJECT_SPECIFIC
#if defined(TR_TARGET_S390)
         if (artificiallyInflatedNode->getOpaquePseudoRegister())
            {
            TR_OpaquePseudoRegister *reg = artificiallyInflatedNode->getOpaquePseudoRegister();
            TR_StorageReference *ref = reg->getStorageReference();
            self()->processUnusedStorageRef(ref);
            }
#endif
#endif

         if (self()->comp()->getOption(TR_TraceCG))
            {
            self()->comp()->getDebug()->trace(" _stackOfArtificiallyInflatedNodes.pop() %p, decReferenceCount(...) called. reg=%s\n", artificiallyInflatedNode,
                                      artificiallyInflatedNode->getRegister()?artificiallyInflatedNode->getRegister()->getRegisterName(self()->comp()):"null");
            }
         }

#if defined(TR_TARGET_S390)
      self()->StopUsingEscapedMemRefsRegisters(topOfMemRefStackBeforeEvaluation);
#endif

      bool checkRefCount = (node->getReferenceCount() <= 1 ||
                              (reg && reg == node->getRegister()));
      // for anchor mode, if node is an indirect store, it can have
      // ref count <= 2
      // but for compressedRefs, the indirect store must be an address
      if (self()->comp()->useAnchors())
         {
         if (((node->getOpCode().isStoreIndirect() &&
               (self()->comp()->useCompressedPointers() && (node->getSymbolReference()->getSymbol()->getDataType() == TR::Address))) ||
                opcode == TR::wrtbari) &&
               node->getReferenceCount() <= 2 &&
               !checkRefCount)
            checkRefCount = true;
         }

      TR_ASSERT(checkRefCount,
                  "evaluate: the node's register wasn't set (node [%s])", node->getName(self()->comp()->getDebug()));
      }

   return reg;
   }