std::string tree2str(ACCExpr *expr) { if (!expr) return ""; std::string ret, sep, op = expr->value; if (isParen(op)) { ret += op; if (expr->operands.size()) ret += " "; op = ","; } else if (isIdChar(op[0])) { ret += op; } else if (!expr->operands.size() || ((op == "-" || op == "!")/*unary*/ && expr->operands.size() == 1)) ret += op; bool topOp = checkOperand(expr->value) || expr->value == "," || expr->value == "[" || expr->value == PARAMETER_MARKER; for (auto item: expr->operands) { ret += sep; bool addParen = !topOp && !checkOperand(item->value) && item->value != ","; if (addParen) ret += "( "; ret += tree2str(item); if (addParen) ret += " )"; sep = " " + op + " "; if (op == "?") op = ":"; } ret += treePost(expr); return ret; }
void validate() { // NB. This code is not written for performance, since it is not intended to run // in release builds. // Validate that all local variables at the head of the root block are dead. BasicBlock* root = m_graph.m_blocks[0].get(); for (unsigned i = 0; i < root->variablesAtHead.numberOfLocals(); ++i) V_EQUAL((static_cast<VirtualRegister>(i), 0), static_cast<Node*>(0), root->variablesAtHead.local(i)); // Validate ref counts and uses. HashMap<Node*, unsigned> myRefCounts; for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { BasicBlock* block = m_graph.m_blocks[blockIndex].get(); if (!block || !block->isReachable) continue; for (size_t i = 0; i < block->numNodes(); ++i) myRefCounts.add(block->node(i), 0); } HashSet<Node*> acceptableNodes; for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { BasicBlock* block = m_graph.m_blocks[blockIndex].get(); if (!block || !block->isReachable) continue; for (size_t i = 0; i < block->numNodes(); ++i) { Node* node = block->node(i); acceptableNodes.add(node); if (!node->shouldGenerate()) continue; for (unsigned j = 0; j < m_graph.numChildren(node); ++j) { // Phi children in LoadStore form are invalid. if (m_graph.m_form == LoadStore && block->isPhiIndex(i)) continue; Edge edge = m_graph.child(node, j); if (!edge) continue; myRefCounts.find(edge.node())->value++; // Unless I'm a Flush, Phantom, GetLocal, or Phi, my children should hasResult(). switch (node->op()) { case Flush: case GetLocal: case PhantomLocal: VALIDATE((node, edge), edge->hasVariableAccessData()); VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData()); break; case Phi: VALIDATE((node, edge), edge->hasVariableAccessData()); if (m_graph.m_unificationState == LocallyUnified) break; VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData()); break; case Phantom: if (m_graph.m_form == LoadStore && !j) break; default: VALIDATE((node, edge), edge->hasResult()); break; } } } } for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { BasicBlock* block = m_graph.m_blocks[blockIndex].get(); if (!block || !block->isReachable) continue; HashSet<Node*> phisInThisBlock; HashSet<Node*> nodesInThisBlock; for (size_t i = 0; i < block->numNodes(); ++i) { Node* node = block->node(i); nodesInThisBlock.add(node); if (block->isPhiIndex(i)) phisInThisBlock.add(node); if (m_graph.m_form == ThreadedCPS || !node->hasVariableAccessData()) V_EQUAL((node), myRefCounts.get(node), node->adjustedRefCount()); else VALIDATE((node), myRefCounts.get(node) ? node->adjustedRefCount() : true); for (unsigned j = 0; j < m_graph.numChildren(node); ++j) { Edge edge = m_graph.child(node, j); if (!edge) continue; VALIDATE((node, edge), acceptableNodes.contains(edge.node())); } } for (size_t i = 0; i < block->phis.size(); ++i) { Node* node = block->phis[i]; ASSERT(phisInThisBlock.contains(node)); VALIDATE((node), node->op() == Phi); VirtualRegister local = node->local(); for (unsigned j = 0; j < m_graph.numChildren(node); ++j) { // Phi children in LoadStore form are invalid. if (m_graph.m_form == LoadStore && block->isPhiIndex(i)) continue; Edge edge = m_graph.child(node, j); if (!edge) continue; VALIDATE( (node, edge), edge->op() == SetLocal || edge->op() == SetArgument || edge->op() == Flush || edge->op() == Phi); if (phisInThisBlock.contains(edge.node())) continue; if (nodesInThisBlock.contains(edge.node())) { VALIDATE( (node, edge), edge->op() == SetLocal || edge->op() == SetArgument || edge->op() == Flush); continue; } // There must exist a predecessor block that has this node index in // its tail variables. bool found = false; for (unsigned k = 0; k < block->m_predecessors.size(); ++k) { BasicBlock* prevBlock = m_graph.m_blocks[block->m_predecessors[k]].get(); VALIDATE((Block, block->m_predecessors[k]), prevBlock); VALIDATE((Block, block->m_predecessors[k]), prevBlock->isReachable); Node* prevNode = prevBlock->variablesAtTail.operand(local); // If we have a Phi that is not referring to *this* block then all predecessors // must have that local available. VALIDATE((local, blockIndex, Block, block->m_predecessors[k]), prevNode); switch (prevNode->op()) { case GetLocal: case Flush: case PhantomLocal: prevNode = prevNode->child1().node(); break; default: break; } if (node->shouldGenerate()) { VALIDATE((local, block->m_predecessors[k], prevNode), prevNode->shouldGenerate()); } VALIDATE( (local, block->m_predecessors[k], prevNode), prevNode->op() == SetLocal || prevNode->op() == SetArgument || prevNode->op() == Phi); if (prevNode == edge.node()) { found = true; break; } // At this point it cannot refer into this block. VALIDATE((local, block->m_predecessors[k], prevNode), !prevBlock->isInBlock(edge.node())); } VALIDATE((node, edge), found); } } Operands<size_t> getLocalPositions( block->variablesAtHead.numberOfArguments(), block->variablesAtHead.numberOfLocals()); Operands<size_t> setLocalPositions( block->variablesAtHead.numberOfArguments(), block->variablesAtHead.numberOfLocals()); for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) { VALIDATE((static_cast<VirtualRegister>(argumentToOperand(i)), blockIndex), !block->variablesAtHead.argument(i) || block->variablesAtHead.argument(i)->hasVariableAccessData()); if (m_graph.m_form == ThreadedCPS) VALIDATE((static_cast<VirtualRegister>(argumentToOperand(i)), blockIndex), !block->variablesAtTail.argument(i) || block->variablesAtTail.argument(i)->hasVariableAccessData()); getLocalPositions.argument(i) = notSet; setLocalPositions.argument(i) = notSet; } for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) { VALIDATE((static_cast<VirtualRegister>(i), blockIndex), !block->variablesAtHead.local(i) || block->variablesAtHead.local(i)->hasVariableAccessData()); if (m_graph.m_form == ThreadedCPS) VALIDATE((static_cast<VirtualRegister>(i), blockIndex), !block->variablesAtTail.local(i) || block->variablesAtTail.local(i)->hasVariableAccessData()); getLocalPositions.local(i) = notSet; setLocalPositions.local(i) = notSet; } for (size_t i = 0; i < block->size(); ++i) { Node* node = block->at(i); ASSERT(nodesInThisBlock.contains(node)); VALIDATE((node), node->op() != Phi); for (unsigned j = 0; j < m_graph.numChildren(node); ++j) { Edge edge = m_graph.child(node, j); if (!edge) continue; VALIDATE((node, edge), nodesInThisBlock.contains(edge.node())); switch (node->op()) { case PhantomLocal: case GetLocal: case Flush: break; case Phantom: if (m_graph.m_form == LoadStore && !j) break; default: VALIDATE((node, edge), !phisInThisBlock.contains(edge.node())); break; } } if (!node->shouldGenerate()) continue; switch (node->op()) { case GetLocal: if (node->variableAccessData()->isCaptured()) break; if (m_graph.m_form == ThreadedCPS) VALIDATE((node, blockIndex), getLocalPositions.operand(node->local()) == notSet); getLocalPositions.operand(node->local()) = i; break; case SetLocal: if (node->variableAccessData()->isCaptured()) break; // Only record the first SetLocal. There may be multiple SetLocals // because of flushing. if (setLocalPositions.operand(node->local()) != notSet) break; setLocalPositions.operand(node->local()) = i; break; default: break; } } if (m_graph.m_form == LoadStore) continue; for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) { checkOperand( blockIndex, getLocalPositions, setLocalPositions, argumentToOperand(i)); } for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) { checkOperand( blockIndex, getLocalPositions, setLocalPositions, i); } } }
static ACCExpr *getExprList(ACCExpr *head, std::string terminator, bool repeatCurrentToken, bool preserveParen) { bool parseState = false; ACCExpr *currentOperand = nullptr; ACCExpr *tok; ACCExpr *exprStack[MAX_EXPR_DEPTH]; int exprStackIndex = 0; #define TOP exprStack[exprStackIndex] TOP = nullptr; if (trace_expr) printf("[%s:%d] head %s\n", __FUNCTION__, __LINE__, head ? head->value.c_str() : "(nil)"); if (head) { while ((tok = get1Token()) && tok->value != terminator) { if (trace_expr) printf("[%s:%d] parseState %d tok->value %s repeat %d\n", __FUNCTION__, __LINE__, parseState, tok->value.c_str(), repeatCurrentToken); if ((parseState = !parseState)) { /* Operand */ ACCExpr *unary = nullptr; ACCExpr *tnext = tok; if (repeatCurrentToken) tok = head; else tnext = get1Token(); repeatCurrentToken = false; if ((tok->value == "-" || tok->value == "!") && !tok->operands.size()) { // unary '-' unary = tok; tok = tnext; tnext = get1Token(); if (trace_expr) printf("[%s:%d] unary '-' unary %p tok %p tnext %p\n", __FUNCTION__, __LINE__, (void *)unary, (void *)tok, (void *)tnext); } if (!checkOperand(tok->value) && !checkOperator(tok->value)) { printf("[%s:%d] OPERAND CHECKFAILLLLLLLLLLLLLLL %s from %s\n", __FUNCTION__, __LINE__, tree2str(tok).c_str(), lexString.c_str()); exit(-1); } while (tnext && (isParen(tnext->value) || isIdChar(tnext->value[0]))) { assert(isIdChar(tok->value[0])); tok->operands.push_back(tnext); tnext = get1Token(); } repeatGet1Token = tnext; if (unary) { unary->operands.push_back(tok); tok = unary; } currentOperand = tok; } else { /* Operator */ std::string L = TOP ? TOP->value : "", R = tok->value; if (!checkOperator(R)) { printf("[%s:%d] OPERATOR CHECKFAILLLLLLLLLLLLLLL %s from %s\n", __FUNCTION__, __LINE__, R.c_str(), lexString.c_str()); exit(-1); } else if (!((L == R && L != "?") || (L == "?" && R == ":"))) { if (TOP) { int lprec = findPrec(L), rprec = findPrec(R); if (lprec < rprec) { exprStackIndex++; TOP = nullptr; } else { TOP->operands.push_back(currentOperand); currentOperand = TOP; while (exprStackIndex > 0 && lprec >= rprec) { exprStackIndex--; TOP->operands.push_back(currentOperand); currentOperand = TOP; L = TOP->value; lprec = findPrec(L); } } } TOP = tok; } TOP->operands.push_back(currentOperand); currentOperand = nullptr; } } while (exprStackIndex != 0) { TOP->operands.push_back(currentOperand); currentOperand = TOP; exprStackIndex--; } if (currentOperand) { if (TOP) TOP->operands.push_back(currentOperand); else TOP = currentOperand; } if (TOP) { if (terminator != "") head->operands.push_back(TOP); // the first item in a recursed list else head = TOP; } } head = cleanupExpr(head, preserveParen); return head; }