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; }