diff --git a/libsolidity/codegen/ir/Common.cpp b/libsolidity/codegen/ir/Common.cpp index dba6aee07..1f1cc1cfe 100644 --- a/libsolidity/codegen/ir/Common.cpp +++ b/libsolidity/codegen/ir/Common.cpp @@ -53,6 +53,13 @@ string IRNames::runtimeObject(ContractDefinition const& _contract) return _contract.name() + "_" + toString(_contract.id()) + "_deployed"; } +string IRNames::internalDispatch(YulArity const& _arity) +{ + return "dispatch_internal" + "_in_" + to_string(_arity.in) + + "_out_" + to_string(_arity.out); +} + string IRNames::implicitConstructor(ContractDefinition const& _contract) { return "constructor_" + _contract.name() + "_" + to_string(_contract.id()); diff --git a/libsolidity/codegen/ir/Common.h b/libsolidity/codegen/ir/Common.h index 96e2a86ea..f1235553b 100644 --- a/libsolidity/codegen/ir/Common.h +++ b/libsolidity/codegen/ir/Common.h @@ -50,6 +50,7 @@ struct IRNames static std::string function(VariableDeclaration const& _varDecl); static std::string creationObject(ContractDefinition const& _contract); static std::string runtimeObject(ContractDefinition const& _contract); + static std::string internalDispatch(YulArity const& _arity); static std::string implicitConstructor(ContractDefinition const& _contract); static std::string constantValueFunction(VariableDeclaration const& _constant); static std::string localVariable(VariableDeclaration const& _declaration); diff --git a/libsolidity/codegen/ir/IRGenerationContext.cpp b/libsolidity/codegen/ir/IRGenerationContext.cpp index d5a926a0d..3fa403272 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.cpp +++ b/libsolidity/codegen/ir/IRGenerationContext.cpp @@ -121,9 +121,9 @@ string IRGenerationContext::newYulVariable() return "_" + to_string(++m_varCounter); } -string IRGenerationContext::internalDispatch(YulArity const& _arity) +string IRGenerationContext::generateInternalDispatchFunction(YulArity const& _arity) { - string funName = "dispatch_internal_in_" + to_string(_arity.in) + "_out_" + to_string(_arity.out); + string funName = IRNames::internalDispatch(_arity); return m_functions.createFunction(funName, [&]() { Whiskers templ(R"( function (fun ) { @@ -139,35 +139,32 @@ string IRGenerationContext::internalDispatch(YulArity const& _arity) )"); templ("functionName", funName); templ("comma", _arity.in > 0 ? "," : ""); - YulUtilFunctions utils(m_evmVersion, m_revertStrings, m_functions); templ("in", suffixedVariableNameList("in_", 0, _arity.in)); templ("arrow", _arity.out > 0 ? "->" : ""); templ("assignment_op", _arity.out > 0 ? ":=" : ""); templ("out", suffixedVariableNameList("out_", 0, _arity.out)); - // UNIMPLEMENTED: Internal library calls via pointers are not implemented yet. - // We're not generating code for internal library functions here even though it's possible - // to call them via pointers. Right now such calls end up triggering the `default` case in - // the switch above. - vector> functions; - for (auto const& contract: mostDerivedContract().annotation().linearizedBaseContracts) - for (FunctionDefinition const* function: contract->definedFunctions()) - if ( - !function->isConstructor() && - YulArity::fromType(*TypeProvider::function(*function, FunctionType::Kind::Internal)) == _arity - ) - { - // 0 is reserved for uninitialized function pointers - solAssert(function->id() != 0, "Unexpected function ID: 0"); + vector> cases; + for (FunctionDefinition const* function: collectFunctionsOfArity(_arity)) + { + solAssert(function, ""); + solAssert( + YulArity::fromType(*TypeProvider::function(*function, FunctionType::Kind::Internal)) == _arity, + "A single dispatch function can only handle functions of one arity" + ); + solAssert(!function->isConstructor(), ""); + // 0 is reserved for uninitialized function pointers + solAssert(function->id() != 0, "Unexpected function ID: 0"); - functions.emplace_back(map { - { "funID", to_string(function->id()) }, - { "name", IRNames::function(*function)} - }); + cases.emplace_back(map{ + {"funID", to_string(function->id())}, + {"name", IRNames::function(*function)} + }); - enqueueFunctionForCodeGeneration(*function); - } - templ("cases", move(functions)); + enqueueFunctionForCodeGeneration(*function); + } + + templ("cases", move(cases)); return templ.render(); }); } @@ -187,3 +184,20 @@ std::string IRGenerationContext::revertReasonIfDebug(std::string const& _message return YulUtilFunctions::revertReasonIfDebug(m_revertStrings, _message); } +set IRGenerationContext::collectFunctionsOfArity(YulArity const& _arity) +{ + // UNIMPLEMENTED: Internal library calls via pointers are not implemented yet. + // We're not returning any internal library functions here even though it's possible + // to call them via pointers. Right now such calls end will up triggering the `default` case in + // the switch in the generated dispatch function. + set functions; + for (auto const& contract: mostDerivedContract().annotation().linearizedBaseContracts) + for (FunctionDefinition const* function: contract->definedFunctions()) + if ( + !function->isConstructor() && + YulArity::fromType(*TypeProvider::function(*function, FunctionType::Kind::Internal)) == _arity + ) + functions.insert(function); + + return functions; +} diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index 2ae63ab2d..30aa5e220 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -102,7 +102,7 @@ public: std::string newYulVariable(); - std::string internalDispatch(YulArity const& _arity); + std::string generateInternalDispatchFunction(YulArity const& _arity); /// @returns a new copy of the utility function generator (but using the same function set). YulUtilFunctions utils(); @@ -120,6 +120,8 @@ public: std::set& subObjectsCreated() { return m_subObjects; } private: + std::set collectFunctionsOfArity(YulArity const& _arity); + langutil::EVMVersion m_evmVersion; RevertStrings m_revertStrings; OptimiserSettings m_optimiserSettings; diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 788498c06..b91ed9f2b 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -695,8 +695,8 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) { YulArity arity = YulArity::fromType(*functionType); define(_functionCall) << - // NOTE: internalDispatch() takes care of adding the function to function generation queue - m_context.internalDispatch(arity) << + // NOTE: generateInternalDispatchFunction() takes care of adding the function to function generation queue + m_context.generateInternalDispatchFunction(arity) << "(" << IRVariable(_functionCall.expression()).part("functionIdentifier").name() << joinHumanReadablePrefixed(args) <<