From 678e352f2093184b5cd1faee54783cfab74978ed Mon Sep 17 00:00:00 2001 From: clonker Date: Mon, 15 Jul 2024 10:55:03 +0200 Subject: [PATCH] Yul: Object node names are std::string instead of YulString --- libsolidity/interface/StandardCompiler.cpp | 2 +- libyul/AsmAnalysis.cpp | 2 +- libyul/AsmAnalysis.h | 4 +-- libyul/Object.cpp | 41 +++++++++++----------- libyul/Object.h | 10 +++--- libyul/ObjectParser.cpp | 18 ++++++---- libyul/ObjectParser.h | 4 +-- libyul/YulStack.cpp | 2 +- libyul/backends/evm/EVMDialect.cpp | 16 ++++----- libyul/backends/evm/EVMDialect.h | 2 +- libyul/backends/evm/EVMObjectCompiler.cpp | 6 ++-- test/libsolidity/MemoryGuardTest.cpp | 2 +- tools/yulPhaser/Program.cpp | 2 +- 13 files changed, 57 insertions(+), 54 deletions(-) diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 5510b543077c..b908ab0cc6fd 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -1638,7 +1638,7 @@ Json StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) return output; } - std::string contractName = stack.parserResult()->name.str(); + std::string contractName = stack.parserResult()->name; bool const wildcardMatchesExperimental = true; if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "ir", wildcardMatchesExperimental)) diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index ac97f988d47d..38b9c782e0fc 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -428,7 +428,7 @@ std::vector AsmAnalyzer::operator()(FunctionCall const& _funCall) if (functionName == "datasize" || functionName == "dataoffset") { auto const& argumentAsLiteral = std::get(arg); - if (!m_dataNames.count(YulString(formatLiteral(argumentAsLiteral)))) + if (!m_dataNames.count(formatLiteral(argumentAsLiteral))) m_errorReporter.typeError( 3517_error, nativeLocationOf(arg), diff --git a/libyul/AsmAnalysis.h b/libyul/AsmAnalysis.h index c49e6855914d..9dd4b2292383 100644 --- a/libyul/AsmAnalysis.h +++ b/libyul/AsmAnalysis.h @@ -61,7 +61,7 @@ class AsmAnalyzer langutil::ErrorReporter& _errorReporter, Dialect const& _dialect, ExternalIdentifierAccess::Resolver _resolver = ExternalIdentifierAccess::Resolver(), - std::set _dataNames = {} + std::set _dataNames = {} ): m_resolver(std::move(_resolver)), m_info(_analysisInfo), @@ -128,7 +128,7 @@ class AsmAnalyzer langutil::EVMVersion m_evmVersion; Dialect const& m_dialect; /// Names of data objects to be referenced by builtin functions with literal arguments. - std::set m_dataNames; + std::set m_dataNames; ForLoop const* m_currentForLoop = nullptr; /// Worst side effects encountered during analysis (including within defined functions). SideEffects m_sideEffects; diff --git a/libyul/Object.cpp b/libyul/Object.cpp index 260cb733011f..76d8bdc66780 100644 --- a/libyul/Object.cpp +++ b/libyul/Object.cpp @@ -40,7 +40,7 @@ using namespace solidity::yul; std::string Data::toString(Dialect const*, DebugInfoSelection const&, CharStreamProvider const*) const { - return "data \"" + name.str() + "\" hex\"" + util::toHex(data) + "\""; + return "data \"" + name + "\" hex\"" + util::toHex(data) + "\""; } std::string Object::toString( @@ -72,7 +72,7 @@ std::string Object::toString( for (auto const& obj: subObjects) inner += "\n" + obj->toString(_dialect, _debugInfoSelection, _soliditySourceProvider); - return useSrcComment + "object \"" + name.str() + "\" {\n" + indent(inner) + "\n}"; + return useSrcComment + "object \"" + name + "\" {\n" + indent(inner) + "\n}"; } Json Data::toJson() const @@ -97,62 +97,61 @@ Json Object::toJson() const Json ret; ret["nodeType"] = "YulObject"; - ret["name"] = name.str(); + ret["name"] = name; ret["code"] = codeJson; ret["subObjects"] = subObjectsJson; return ret; } -std::set Object::qualifiedDataNames() const +std::set Object::qualifiedDataNames() const { - std::set qualifiedNames = - name.empty() || util::contains(name.str(), '.') ? - std::set{} : - std::set{name}; + std::set qualifiedNames = + name.empty() || util::contains(name, '.') ? + std::set{} : + std::set{name}; for (std::shared_ptr const& subObjectNode: subObjects) { yulAssert(qualifiedNames.count(subObjectNode->name) == 0, ""); - if (util::contains(subObjectNode->name.str(), '.')) + if (util::contains(subObjectNode->name, '.')) continue; qualifiedNames.insert(subObjectNode->name); if (auto const* subObject = dynamic_cast(subObjectNode.get())) - for (YulString const& subSubObj: subObject->qualifiedDataNames()) + for (auto const& subSubObj: subObject->qualifiedDataNames()) if (subObject->name != subSubObj) { - yulAssert(qualifiedNames.count(YulString{subObject->name.str() + "." + subSubObj.str()}) == 0, ""); - qualifiedNames.insert(YulString{subObject->name.str() + "." + subSubObj.str()}); + yulAssert(qualifiedNames.count(subObject->name + "." + subSubObj) == 0, ""); + qualifiedNames.insert(subObject->name + "." + subSubObj); } } - yulAssert(qualifiedNames.count(YulString{}) == 0, ""); - qualifiedNames.erase(YulString{}); + yulAssert(qualifiedNames.count("") == 0, ""); return qualifiedNames; } -std::vector Object::pathToSubObject(YulString _qualifiedName) const +std::vector Object::pathToSubObject(std::string_view _qualifiedName) const { yulAssert(_qualifiedName != name, ""); yulAssert(subIndexByName.count(name) == 0, ""); - if (boost::algorithm::starts_with(_qualifiedName.str(), name.str() + ".")) - _qualifiedName = YulString{_qualifiedName.str().substr(name.str().length() + 1)}; + if (boost::algorithm::starts_with(_qualifiedName, name + ".")) + _qualifiedName = _qualifiedName.substr(name.length() + 1); yulAssert(!_qualifiedName.empty(), ""); std::vector subObjectPathComponents; - boost::algorithm::split(subObjectPathComponents, _qualifiedName.str(), boost::is_any_of(".")); + boost::algorithm::split(subObjectPathComponents, _qualifiedName, boost::is_any_of(".")); std::vector path; Object const* object = this; for (std::string const& currentSubObjectName: subObjectPathComponents) { yulAssert(!currentSubObjectName.empty(), ""); - auto subIndexIt = object->subIndexByName.find(YulString{currentSubObjectName}); + auto subIndexIt = object->subIndexByName.find(currentSubObjectName); yulAssert( subIndexIt != object->subIndexByName.end(), - "Assembly object <" + _qualifiedName.str() + "> not found or does not contain code." + "Assembly object <" + std::string(_qualifiedName) + "> not found or does not contain code." ); object = dynamic_cast(object->subObjects[subIndexIt->second].get()); - yulAssert(object, "Assembly object <" + _qualifiedName.str() + "> not found or does not contain code."); + yulAssert(object, "Assembly object <" + std::string(_qualifiedName) + "> not found or does not contain code."); yulAssert(object->subId != std::numeric_limits::max(), ""); path.push_back({object->subId}); } diff --git a/libyul/Object.h b/libyul/Object.h index 54a8080d08c0..c1ca9244d98d 100644 --- a/libyul/Object.h +++ b/libyul/Object.h @@ -52,7 +52,7 @@ struct ObjectNode /// Name of the object. /// Can be empty since .yul files can also just contain code, without explicitly placing it in an object. - YulString name; + std::string name; virtual std::string toString( Dialect const* _dialect, langutil::DebugInfoSelection const& _debugInfoSelection, @@ -66,7 +66,7 @@ struct ObjectNode */ struct Data: public ObjectNode { - Data(YulString _name, bytes _data): data(std::move(_data)) { name = _name; } + Data(std::string _name, bytes _data): data(std::move(_data)) { name = _name; } bytes data; @@ -102,7 +102,7 @@ struct Object: public ObjectNode /// @returns the set of names of data objects accessible from within the code of /// this object, including the name of object itself /// Handles all names containing dots as reserved identifiers, not accessible as data. - std::set qualifiedDataNames() const; + std::set qualifiedDataNames() const; /// @returns vector of subIDs if possible to reach subobject with @a _qualifiedName, throws otherwise /// For "B.C" should return vector of two values if success (subId of B and subId of C in B). @@ -114,14 +114,14 @@ struct Object: public ObjectNode /// pathToSubObject("E2.F3.H4") == {1, 0, 2} /// pathToSubObject("A1.E2") == {1} /// The path must not lead to a @a Data object (will throw in that case). - std::vector pathToSubObject(YulString _qualifiedName) const; + std::vector pathToSubObject(std::string_view _qualifiedName) const; /// sub id for object if it is subobject of another object, max value if it is not subobject size_t subId = std::numeric_limits::max(); std::shared_ptr code; std::vector> subObjects; - std::map subIndexByName; + std::map> subIndexByName; std::shared_ptr analysisInfo; std::shared_ptr debugData; diff --git a/libyul/ObjectParser.cpp b/libyul/ObjectParser.cpp index a02b9660b978..1f5363fd8d59 100644 --- a/libyul/ObjectParser.cpp +++ b/libyul/ObjectParser.cpp @@ -50,7 +50,7 @@ std::shared_ptr ObjectParser::parse(std::shared_ptr const& _sca { // Special case: Code-only form. object = std::make_shared(); - object->name = "object"_yulstring; + object->name = "object"; auto sourceNameMapping = tryParseSourceNameMapping(); object->debugData = std::make_shared(ObjectDebugData{sourceNameMapping}); object->code = parseBlock(sourceNameMapping); @@ -185,7 +185,7 @@ void ObjectParser::parseData(Object& _containingObject) ); advance(); - YulString name = parseUniqueName(&_containingObject); + auto const name = parseUniqueName(&_containingObject); if (currentToken() == Token::HexStringLiteral) expectToken(Token::HexStringLiteral, false); @@ -195,22 +195,26 @@ void ObjectParser::parseData(Object& _containingObject) advance(); } -YulString ObjectParser::parseUniqueName(Object const* _containingObject) +std::string ObjectParser::parseUniqueName(Object const* _containingObject) { expectToken(Token::StringLiteral, false); - YulString name{currentLiteral()}; + auto const name = currentLiteral(); if (name.empty()) parserError(3287_error, "Object name cannot be empty."); else if (_containingObject && _containingObject->name == name) parserError(8311_error, "Object name cannot be the same as the name of the containing object."); else if (_containingObject && _containingObject->subIndexByName.count(name)) - parserError(8794_error, "Object name \"" + name.str() + "\" already exists inside the containing object."); + parserError(8794_error, "Object name \"" + name + "\" already exists inside the containing object."); advance(); return name; } -void ObjectParser::addNamedSubObject(Object& _container, YulString _name, std::shared_ptr _subObject) +void ObjectParser::addNamedSubObject(Object& _container, std::string_view const _name, std::shared_ptr _subObject) { - _container.subIndexByName[_name] = _container.subObjects.size(); + _container.subIndexByName.emplace( + std::piecewise_construct, + std::forward_as_tuple(_name), + std::forward_as_tuple(_container.subObjects.size()) + ); _container.subObjects.emplace_back(std::move(_subObject)); } diff --git a/libyul/ObjectParser.h b/libyul/ObjectParser.h index 716a191ea878..08a852991203 100644 --- a/libyul/ObjectParser.h +++ b/libyul/ObjectParser.h @@ -63,8 +63,8 @@ class ObjectParser: public langutil::ParserBase void parseData(Object& _containingObject); /// Tries to parse a name that is non-empty and unique inside the containing object. - YulString parseUniqueName(Object const* _containingObject); - void addNamedSubObject(Object& _container, YulString _name, std::shared_ptr _subObject); + std::string parseUniqueName(Object const* _containingObject); + void addNamedSubObject(Object& _container, std::string_view _name, std::shared_ptr _subObject); Dialect const& m_dialect; }; diff --git a/libyul/YulStack.cpp b/libyul/YulStack.cpp index 94e9ad7a8d55..27b4b5526b85 100644 --- a/libyul/YulStack.cpp +++ b/libyul/YulStack.cpp @@ -198,7 +198,7 @@ void YulStack::optimize(Object& _object, bool _isCreation) for (auto& subNode: _object.subObjects) if (auto subObject = dynamic_cast(subNode.get())) { - bool isCreation = !boost::ends_with(subObject->name.str(), "_deployed"); + bool isCreation = !boost::ends_with(subObject->name, "_deployed"); optimize(*subObject, isCreation); } diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index 856689c91ad4..d3b9c34bcb5a 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -249,14 +249,14 @@ std::map createBuiltins(langutil::EVMVersion _ yulAssert(_call.arguments.size() == 1, ""); Expression const& arg = _call.arguments.front(); YulString const dataName (formatLiteral(std::get(arg))); - if (_context.currentObject->name == dataName) + if (_context.currentObject->name == dataName.str()) _assembly.appendAssemblySize(); else { std::vector subIdPath = - _context.subIDs.count(dataName) == 0 ? - _context.currentObject->pathToSubObject(dataName) : - std::vector{_context.subIDs.at(dataName)}; + _context.subIDs.count(dataName.str()) == 0 ? + _context.currentObject->pathToSubObject(dataName.str()) : + std::vector{_context.subIDs.at(dataName.str())}; yulAssert(!subIdPath.empty(), "Could not find assembly object <" + dataName.str() + ">."); _assembly.appendDataSize(subIdPath); } @@ -270,14 +270,14 @@ std::map createBuiltins(langutil::EVMVersion _ yulAssert(_call.arguments.size() == 1, ""); Expression const& arg = _call.arguments.front(); YulString const dataName (formatLiteral(std::get(arg))); - if (_context.currentObject->name == dataName) + if (_context.currentObject->name == dataName.str()) _assembly.appendConstant(0); else { std::vector subIdPath = - _context.subIDs.count(dataName) == 0 ? - _context.currentObject->pathToSubObject(dataName) : - std::vector{_context.subIDs.at(dataName)}; + _context.subIDs.count(dataName.str()) == 0 ? + _context.currentObject->pathToSubObject(dataName.str()) : + std::vector{_context.subIDs.at(dataName.str())}; yulAssert(!subIdPath.empty(), "Could not find assembly object <" + dataName.str() + ">."); _assembly.appendDataOffset(subIdPath); } diff --git a/libyul/backends/evm/EVMDialect.h b/libyul/backends/evm/EVMDialect.h index 28649f3e5e90..f0455a8e4240 100644 --- a/libyul/backends/evm/EVMDialect.h +++ b/libyul/backends/evm/EVMDialect.h @@ -45,7 +45,7 @@ struct BuiltinContext { Object const* currentObject = nullptr; /// Mapping from named objects to abstract assembly sub IDs. - std::map subIDs; + std::map subIDs; }; struct BuiltinFunctionForEVM: public BuiltinFunction diff --git a/libyul/backends/evm/EVMObjectCompiler.cpp b/libyul/backends/evm/EVMObjectCompiler.cpp index 0bd064940eb7..81a345f90889 100644 --- a/libyul/backends/evm/EVMObjectCompiler.cpp +++ b/libyul/backends/evm/EVMObjectCompiler.cpp @@ -55,8 +55,8 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize) for (auto const& subNode: _object.subObjects) if (auto* subObject = dynamic_cast(subNode.get())) { - bool isCreation = !boost::ends_with(subObject->name.str(), "_deployed"); - auto subAssemblyAndID = m_assembly.createSubAssembly(isCreation, subObject->name.str()); + bool isCreation = !boost::ends_with(subObject->name, "_deployed"); + auto subAssemblyAndID = m_assembly.createSubAssembly(isCreation, subObject->name); context.subIDs[subObject->name] = subAssemblyAndID.second; subObject->subId = subAssemblyAndID.second; compile(*subObject, *subAssemblyAndID.first, m_dialect, _optimize, m_eofVersion); @@ -65,7 +65,7 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize) { Data const& data = dynamic_cast(*subNode); // Special handling of metadata. - if (data.name.str() == Object::metadataName()) + if (data.name == Object::metadataName()) m_assembly.appendToAuxiliaryData(data.data); else context.subIDs[data.name] = m_assembly.appendData(data.data); diff --git a/test/libsolidity/MemoryGuardTest.cpp b/test/libsolidity/MemoryGuardTest.cpp index caa85c6fde8f..6e44afccf4f7 100644 --- a/test/libsolidity/MemoryGuardTest.cpp +++ b/test/libsolidity/MemoryGuardTest.cpp @@ -80,7 +80,7 @@ TestCase::TestResult MemoryGuardTest::run(std::ostream& _stream, std::string con }; handleObject("creation", *object); size_t deployedIndex = object->subIndexByName.at( - YulString(IRNames::deployedObject(compiler().contractDefinition(contractName))) + IRNames::deployedObject(compiler().contractDefinition(contractName)) ); handleObject("runtime", dynamic_cast(*object->subObjects[deployedIndex])); } diff --git a/tools/yulPhaser/Program.cpp b/tools/yulPhaser/Program.cpp index 00abcc8e5c31..1586f602064b 100644 --- a/tools/yulPhaser/Program.cpp +++ b/tools/yulPhaser/Program.cpp @@ -135,7 +135,7 @@ std::variant, ErrorList> Program::parseObject(Dialect con // The other object references the nested one which makes analysis fail. Below we try to // extract just the nested one for that reason. This is just a heuristic. If there's no // subobject with such a suffix we fall back to accepting the whole object as is. - if (subObject != nullptr && subObject->name.str() == object->name.str() + "_deployed") + if (subObject != nullptr && subObject->name == object->name + "_deployed") { deployedObject = dynamic_cast(subObject.get()); if (deployedObject != nullptr)