Skip to content

Commit

Permalink
Merge branch 'develop' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
haoyang9804 authored Oct 30, 2024
2 parents 901bef0 + fd96fcf commit 7a0e70d
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 23 deletions.
23 changes: 19 additions & 4 deletions libyul/AsmAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ bool AsmAnalyzer::analyze(Block const& _block)
auto watcher = m_errorReporter.errorWatcher();
try
{
// FIXME: Pass location of the object name. Now it's a location of first code section in yul
validateObjectStructure(nativeLocationOf(_block));
if (!(ScopeFiller(m_info, m_errorReporter))(_block))
return false;

Expand All @@ -86,13 +88,13 @@ bool AsmAnalyzer::analyze(Block const& _block)

AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect, Object const& _object)
{
return analyzeStrictAssertCorrect(_dialect, _object.code()->root(), _object.qualifiedDataNames());
return analyzeStrictAssertCorrect(_dialect, _object.code()->root(), _object.summarizeStructure());
}

AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(
Dialect const& _dialect,
Block const& _astRoot,
std::set<std::string> const& _qualifiedDataNames
Object::Structure const _objectStructure
)
{
ErrorList errorList;
Expand All @@ -103,7 +105,7 @@ AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(
errors,
_dialect,
{},
_qualifiedDataNames
std::move(_objectStructure)
).analyze(_astRoot);
yulAssert(success && !errors.hasErrors(), "Invalid assembly/yul code.");
return analysisInfo;
Expand Down Expand Up @@ -408,7 +410,7 @@ size_t AsmAnalyzer::operator()(FunctionCall const& _funCall)
if (functionName == "datasize" || functionName == "dataoffset")
{
auto const& argumentAsLiteral = std::get<Literal>(arg);
if (!m_dataNames.count(formatLiteral(argumentAsLiteral)))
if (!m_objectStructure.contains(formatLiteral(argumentAsLiteral)))
m_errorReporter.typeError(
3517_error,
nativeLocationOf(arg),
Expand Down Expand Up @@ -766,3 +768,16 @@ bool AsmAnalyzer::validateInstructions(FunctionCall const& _functionCall)
{
return validateInstructions(_functionCall.functionName.name.str(), nativeLocationOf(_functionCall.functionName));
}

void AsmAnalyzer::validateObjectStructure(langutil::SourceLocation _astRootLocation)
{
if (m_eofVersion.has_value() && util::contains(m_objectStructure.objectName, '.')) // No dots in object name for EOF
m_errorReporter.syntaxError(
9822_error,
_astRootLocation,
fmt::format(
"The object name \"{objectName}\" is invalid in EOF context. Object names must not contain 'dot' character.",
fmt::arg("objectName", m_objectStructure.objectName)
)
);
}
11 changes: 7 additions & 4 deletions libyul/AsmAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include <libyul/backends/evm/AbstractAssembly.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <libyul/Object.h>

#include <functional>
#include <list>
Expand Down Expand Up @@ -61,13 +62,13 @@ class AsmAnalyzer
langutil::ErrorReporter& _errorReporter,
Dialect const& _dialect,
ExternalIdentifierAccess::Resolver _resolver = ExternalIdentifierAccess::Resolver(),
std::set<std::string> _dataNames = {}
Object::Structure const _objectStructure = {}
):
m_resolver(std::move(_resolver)),
m_info(_analysisInfo),
m_errorReporter(_errorReporter),
m_dialect(_dialect),
m_dataNames(std::move(_dataNames))
m_objectStructure(std::move(_objectStructure))
{
if (EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&m_dialect))
{
Expand All @@ -84,7 +85,7 @@ class AsmAnalyzer
static AsmAnalysisInfo analyzeStrictAssertCorrect(
Dialect const& _dialect,
Block const& _astRoot,
std::set<std::string> const& _qualifiedDataNames
Object::Structure const _objectStructure
);

size_t operator()(Literal const& _literal);
Expand Down Expand Up @@ -120,6 +121,8 @@ class AsmAnalyzer
bool validateInstructions(std::string const& _instrIdentifier, langutil::SourceLocation const& _location);
bool validateInstructions(FunctionCall const& _functionCall);

void validateObjectStructure(langutil::SourceLocation _astRootLocation);

yul::ExternalIdentifierAccess::Resolver m_resolver;
Scope* m_currentScope = nullptr;
/// Variables that are active at the current point in assembly (as opposed to
Expand All @@ -131,7 +134,7 @@ class AsmAnalyzer
std::optional<uint8_t> m_eofVersion;
Dialect const& m_dialect;
/// Names of data objects to be referenced by builtin functions with literal arguments.
std::set<std::string> m_dataNames;
Object::Structure m_objectStructure;
ForLoop const* m_currentForLoop = nullptr;
/// Worst side effects encountered during analysis (including within defined functions).
SideEffects m_sideEffects;
Expand Down
2 changes: 1 addition & 1 deletion libyul/CompilabilityChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ CompilabilityChecker::CompilabilityChecker(
yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(
noOutputDialect,
_object.code()->root(),
_object.qualifiedDataNames()
_object.summarizeStructure()
);

BuiltinContext builtinContext;
Expand Down
49 changes: 40 additions & 9 deletions libyul/Object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,29 +110,60 @@ Json Object::toJson() const
return ret;
}

std::set<std::string> Object::qualifiedDataNames() const

std::set<std::string> Object::Structure::topLevelSubObjectNames() const
{
std::set<std::string> topLevelObjectNames;

for (auto const& path: objectPaths)
if (!util::contains(path, '.') && path != objectName)
topLevelObjectNames.insert(path);

return topLevelObjectNames;
}

Object::Structure Object::summarizeStructure() const
{
std::set<std::string> qualifiedNames =
Structure structure;

structure.objectPaths =
name.empty() || util::contains(name, '.') ?
std::set<std::string>{} :
std::set<std::string>{name};

structure.objectName = name;

for (std::shared_ptr<ObjectNode> const& subObjectNode: subObjects)
{
yulAssert(qualifiedNames.count(subObjectNode->name) == 0, "");
yulAssert(!structure.contains(subObjectNode->name));
if (util::contains(subObjectNode->name, '.'))
continue;
qualifiedNames.insert(subObjectNode->name);

if (auto const* subObject = dynamic_cast<Object const*>(subObjectNode.get()))
for (auto const& subSubObj: subObject->qualifiedDataNames())
{
structure.objectPaths.insert(subObjectNode->name);

auto const subObjectStructure = subObject->summarizeStructure();

for (auto const& subSubObj: subObjectStructure.objectPaths)
if (subObject->name != subSubObj)
{
yulAssert(qualifiedNames.count(subObject->name + "." + subSubObj) == 0, "");
qualifiedNames.insert(subObject->name + "." + subSubObj);
yulAssert(!structure.contains(subObject->name + "." + subSubObj));
structure.objectPaths.insert(subObject->name + "." + subSubObj);
}
for (auto const& subSubObjData: subObjectStructure.dataPaths)
if (subObject->name != subSubObjData)
{
yulAssert(!structure.contains(subObject->name + "." + subSubObjData));
structure.dataPaths.insert(subObject->name + "." + subSubObjData);
}
}
else
structure.dataPaths.insert(subObjectNode->name);
}

yulAssert(qualifiedNames.count("") == 0, "");
return qualifiedNames;
yulAssert(!structure.contains(""));
return structure;
}

std::vector<size_t> Object::pathToSubObject(std::string_view _qualifiedName) const
Expand Down
24 changes: 23 additions & 1 deletion libyul/Object.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,32 @@ struct Object: public ObjectNode
) const override;
/// @returns a compact JSON representation of the AST.
Json toJson() const override;

/// Summarizes the structure of the subtree rooted at a given object,
/// in particular the paths that can be used from within to refer to nested nodes (objects and data).
struct Structure
{
/// The name of the object
std::string objectName;
/// Available dot-separated paths to nested objects (relative to current object).
std::set<std::string> objectPaths;
/// Available dot-separated paths to nested data entries (relative to current object).
std::set<std::string> dataPaths;

/// Checks if a path is available.
bool contains(std::string const& _path) const { return containsObject(_path) || containsData(_path); }
/// Checks if a path is available and leads to an object.
bool containsObject(std::string const& _path) const { return objectPaths.count(_path) > 0; }
/// Checks if a path is available and leads to a data entry.
bool containsData(std::string const& _path) const { return dataPaths.count(_path) > 0; }

std::set<std::string> topLevelSubObjectNames() const;
};

/// @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<std::string> qualifiedDataNames() const;
Structure summarizeStructure() 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).
Expand Down
2 changes: 1 addition & 1 deletion libyul/YulStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ bool YulStack::analyzeParsed(Object& _object)
m_errorReporter,
languageToDialect(m_language, m_evmVersion, m_eofVersion),
{},
_object.qualifiedDataNames()
_object.summarizeStructure()
);

bool success = false;
Expand Down
6 changes: 5 additions & 1 deletion libyul/optimiser/StackCompressor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,11 @@ std::tuple<bool, Block> StackCompressor::run(
Block astRoot = std::get<Block>(ASTCopier{}(_object.code()->root()));
if (usesOptimizedCodeGenerator)
{
yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, astRoot, _object.qualifiedDataNames());
yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(
_dialect,
astRoot,
_object.summarizeStructure()
);
std::unique_ptr<CFG> cfg = ControlFlowGraphBuilder::build(analysisInfo, _dialect, astRoot);
eliminateVariablesOptimizedCodegen(
_dialect,
Expand Down
6 changes: 5 additions & 1 deletion libyul/optimiser/StackLimitEvader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,11 @@ Block StackLimitEvader::run(
auto astRoot = std::get<Block>(ASTCopier{}(_object.code()->root()));
if (evmDialect && evmDialect->evmVersion().canOverchargeGasForCall())
{
yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(*evmDialect, astRoot, _object.qualifiedDataNames());
yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(
*evmDialect,
astRoot,
_object.summarizeStructure()
);
std::unique_ptr<CFG> cfg = ControlFlowGraphBuilder::build(analysisInfo, *evmDialect, astRoot);
run(_context, astRoot, StackLayoutGenerator::reportStackTooDeep(*cfg));
}
Expand Down
2 changes: 1 addition & 1 deletion test/libyul/Common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ std::pair<std::shared_ptr<Object>, std::shared_ptr<yul::AsmAnalysisInfo>> yul::t
if (!parserResult->hasCode() || errorReporter.hasErrors())
return {};
std::shared_ptr<AsmAnalysisInfo> analysisInfo = std::make_shared<AsmAnalysisInfo>();
AsmAnalyzer analyzer(*analysisInfo, errorReporter, _dialect, {}, parserResult->qualifiedDataNames());
AsmAnalyzer analyzer(*analysisInfo, errorReporter, _dialect, {}, parserResult->summarizeStructure());
// TODO this should be done recursively.
if (!analyzer.analyze(parserResult->code()->root()) || errorReporter.hasErrors())
return {};
Expand Down
9 changes: 9 additions & 0 deletions test/libyul/yulSyntaxTests/eof/object_name_in_eof.yul
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
object "a.b" {
code {}
}

// ====
// EVMVersion: >=shanghai
// bytecodeFormat: >=EOFv1
// ----
// SyntaxError 9822: (24-26): The object name "a.b" is invalid in EOF context. Object names must not contain 'dot' character.

0 comments on commit 7a0e70d

Please sign in to comment.