| 222 | }; |
| 223 | |
| 224 | TestCase::TestResult StackLayoutGeneratorTest::run(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted) |
| 225 | { |
| 226 | YulStack yulStack = parseYul(m_source); |
| 227 | solUnimplementedAssert(yulStack.parserResult()->subObjects.empty(), "Tests with subobjects not supported."); |
| 228 | |
| 229 | if (yulStack.hasErrors()) |
| 230 | { |
| 231 | printYulErrors(yulStack, _stream, _linePrefix, _formatted); |
| 232 | return TestResult::FatalError; |
| 233 | } |
| 234 | |
| 235 | std::ostringstream output; |
| 236 | |
| 237 | std::unique_ptr<CFG> cfg = ControlFlowGraphBuilder::build( |
| 238 | *yulStack.parserResult()->analysisInfo, |
| 239 | yulStack.dialect(), |
| 240 | yulStack.parserResult()->code()->root() |
| 241 | ); |
| 242 | |
| 243 | auto const* evmDialect = dynamic_cast<EVMDialect const*>(&yulStack.dialect()); |
| 244 | solAssert(evmDialect, "StackLayoutGenerator can only be run on EVM dialects."); |
| 245 | |
| 246 | StackLayout stackLayout = StackLayoutGenerator::run(*cfg, *evmDialect); |
| 247 | |
| 248 | output << "digraph CFG {\nnodesep=0.7;\nnode[shape=box];\n\n"; |
| 249 | StackLayoutPrinter printer{output, stackLayout, yulStack.dialect()}; |
| 250 | printer(*cfg->entry); |
| 251 | for (auto function: cfg->functions) |
| 252 | printer(cfg->functionInfo.at(function)); |
| 253 | output << "}\n"; |
| 254 | |
| 255 | m_obtainedResult = output.str(); |
| 256 | |
| 257 | auto result = checkResult(_stream, _linePrefix, _formatted); |
| 258 | |
| 259 | #ifdef ISOLTEST |
| 260 | char* graphDisplayer = nullptr; |
| 261 | if (result == TestResult::Failure) |
| 262 | graphDisplayer = getenv("ISOLTEST_DISPLAY_GRAPHS_FAILURE"); |
| 263 | else if (result == TestResult::Success) |
| 264 | graphDisplayer = getenv("ISOLTEST_DISPLAY_GRAPHS_SUCCESS"); |
| 265 | |
| 266 | if (graphDisplayer) |
| 267 | { |
| 268 | if (result == TestResult::Success) |
| 269 | std::cout << std::endl << m_source << std::endl; |
| 270 | boost::process::opstream pipe; |
| 271 | boost::process::child child(graphDisplayer, boost::process::std_in < pipe); |
| 272 | |
| 273 | pipe << output.str(); |
| 274 | pipe.flush(); |
| 275 | pipe.pipe().close(); |
| 276 | if (result == TestResult::Success) |
| 277 | child.wait(); |
| 278 | else |
| 279 | child.detach(); |
| 280 | } |
| 281 | #endif |