Skip to content

Commit

Permalink
Comment addressing.
Browse files Browse the repository at this point in the history
  • Loading branch information
rodiazet committed Nov 28, 2024
1 parent 36b9d44 commit d43a66a
Show file tree
Hide file tree
Showing 19 changed files with 1,167 additions and 68 deletions.
6 changes: 5 additions & 1 deletion libevmasm/Assembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,7 @@ AssemblyItem Assembly::newFunctionCall(uint16_t _functionID) const

AssemblyItem Assembly::newFunctionReturn() const
{
solAssert(m_currentCodeSection != 0, "Appending function return without begin function.");
return AssemblyItem::functionReturn(m_codeSections.at(m_currentCodeSection).outputs);
}

Expand All @@ -724,13 +725,15 @@ uint16_t Assembly::createFunction(uint8_t _args, uint8_t _rets)
solAssert(functionID < 1024, "Too many functions.");
solAssert(m_currentCodeSection == 0, "Functions need to be declared from the main block.");
solAssert(_rets <= 0x80, "Too many function returns.");
solAssert(_args <= 127, "Too many function inputs.");
m_codeSections.emplace_back(CodeSection{_args, _rets, {}});
return static_cast<uint16_t>(functionID);
}

void Assembly::beginFunction(uint16_t _functionID)
{
solAssert(m_currentCodeSection == 0, "Atempted to begin a function before ending the last one.");
solAssert(m_currentCodeSection == 0, "Attempted to begin a function before ending the last one.");
solAssert(_functionID != 0, "Attempt to begin a function with id 0");
solAssert(_functionID < m_codeSections.size(), "Attempt to begin an undeclared function.");
auto& section = m_codeSections.at(_functionID);
solAssert(section.items.empty(), "Function already defined.");
Expand Down Expand Up @@ -1448,6 +1451,7 @@ LinkerObject const& Assembly::assembleEOF() const
for (auto&& [codeSectionIndex, codeSection]: m_codeSections | ranges::views::enumerate)
{
auto const sectionStart = ret.bytecode.size();
solAssert(!codeSection.items.empty(), "Empty code section.");
for (AssemblyItem const& item: codeSection.items)
{
// store position of the invalid jump destination
Expand Down
2 changes: 1 addition & 1 deletion libevmasm/Instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ enum class Instruction: uint8_t
RJUMP = 0xe0, ///< relative jump
RJUMPI = 0xe1, ///< conditional relative jump
CALLF = 0xe3, ///< call function in a EOF code section
RETF = 0xe4, ///< return to caller from the code section of EOF continer
RETF = 0xe4, ///< return to caller from the code section of EOF container
JUMPF = 0xe5, ///< jump to a code section of EOF container without adding a new return stack frame.
EOFCREATE = 0xec, ///< create a new account with associated container code.
RETURNCONTRACT = 0xee, ///< return container to be deployed with axiliary data filled in.
Expand Down
12 changes: 1 addition & 11 deletions libevmasm/SemanticInformation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,17 +304,6 @@ bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item)
return evmasm::isSwapInstruction(_item.instruction());
}

bool SemanticInformation::isJumpInstruction(AssemblyItem const& _item)
{
return
_item == Instruction::JUMP ||
_item == Instruction::JUMPI ||
_item == Instruction::RJUMP ||
_item == Instruction::RJUMPI ||
_item.type() == RelativeJump ||
_item.type() == ConditionalRelativeJump;
}

bool SemanticInformation::altersControlFlow(AssemblyItem const& _item)
{
if (!_item.hasInstruction())
Expand Down Expand Up @@ -404,6 +393,7 @@ bool SemanticInformation::isDeterministic(AssemblyItem const& _item)
case Instruction::RETURNDATASIZE:
case Instruction::EOFCREATE:
case Instruction::CALLF:
case Instruction::JUMPF:
return false;
default:
return true;
Expand Down
1 change: 0 additions & 1 deletion libevmasm/SemanticInformation.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ struct SemanticInformation
static bool isCommutativeOperation(AssemblyItem const& _item);
static bool isDupInstruction(AssemblyItem const& _item);
static bool isSwapInstruction(AssemblyItem const& _item);
static bool isJumpInstruction(AssemblyItem const& _item);
static bool altersControlFlow(AssemblyItem const& _item);
static bool terminatesControlFlow(AssemblyItem const& _item);
static bool terminatesControlFlow(Instruction _instruction);
Expand Down
22 changes: 22 additions & 0 deletions libyul/AsmAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ bool AsmAnalyzer::analyze(Block const& _block)
if (!(ScopeFiller(m_info, m_errorReporter))(_block))
return false;

if (m_eofVersion.has_value() && m_info.virtualBlocks.size() >= 1024)
m_errorReporter.syntaxError(
9633_error,
nativeLocationOf(_block),
fmt::format(
"Too many functions defined in object \"{objectName}\". At most 1023 function definitions are allowed for EOF.",
fmt::arg("objectName", m_objectStructure.objectName)
)
);

(*this)(_block);
}
catch (FatalError const& error)
Expand Down Expand Up @@ -290,6 +300,18 @@ void AsmAnalyzer::operator()(FunctionDefinition const& _funDef)
m_activeVariables.insert(&std::get<Scope::Variable>(varScope.identifiers.at(var.name)));
}

if (m_eofVersion.has_value())
{
if (_funDef.parameters.size() >= 0x80)
m_errorReporter.typeError(8534_error, nativeLocationOf(_funDef),
"Too many function parameters. At most 127 parameters allowed for EOF");

if (_funDef.returnVariables.size() >= 0x80)
m_errorReporter.typeError(2101_error, nativeLocationOf(_funDef),
"Too many function return variables. At most 127 return variables allowed for EOF");

}

(*this)(_funDef.body);
}

Expand Down
17 changes: 11 additions & 6 deletions libyul/backends/evm/AbstractAssembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,16 +103,21 @@ class AbstractAssembly
/// Creates a new sub-assembly, which can be referenced using dataSize and dataOffset.
virtual std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::string _name = "") = 0;

/// Creates new function with given signature and returns newly created function ID
virtual FunctionID createFunction(uint8_t _args, uint8_t _rets) = 0;
/// Starts filling function body under given function ID
/// Registers a new function with given signature and returns its ID.
/// The function is initially empty and its body must be filled with instructions.
virtual FunctionID registerFunction(uint8_t _args, uint8_t _rets) = 0;
/// Selects a function as a target for newly appended instructions.
/// Must not be called when another function is already selected.
/// Filling the same function more than once is not allowed.
/// @a endFunction() must be called at the end to finalize the function.
virtual void beginFunction(FunctionID _functionID) = 0;
/// Ends currently being filled function
/// Finalizes the process of filling a function body and switches back to the main code section.
/// Must not be called if no function is selected.
virtual void endFunction() = 0;

/// Appends function call to a function under given ID
virtual void appendFunctionCall(FunctionID _functionID) = 0;
/// Appends function return from currently being filled function.
/// Appends an instruction that returns values from the current function.
/// Only allowed inside a function body.
virtual void appendFunctionReturn() = 0;

/// Appends the offset of the given sub-assembly or data.
Expand Down
6 changes: 3 additions & 3 deletions libyul/backends/evm/ControlFlowGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ inline bool canBeFreelyGenerated(StackSlot const& _slot)
/// Control flow graph consisting of ``CFG::BasicBlock``s connected by control flow.
struct CFG
{
explicit CFG(bool _useFunctions): useFunctions(_useFunctions) {}
explicit CFG(bool _simulateFunctionsWithJumps): simulateFunctionsWithJumps(_simulateFunctionsWithJumps) {}
CFG(CFG const&) = delete;
CFG(CFG&&) = delete;
CFG& operator=(CFG const&) = delete;
Expand Down Expand Up @@ -220,8 +220,8 @@ struct CFG
bool canContinue = true;
};

/// True if control flow graph uses functions. False otherwise.
bool useFunctions = false;
/// True if control flow graph simulates functions with jumps. False otherwise. True for legacy bytecode
bool simulateFunctionsWithJumps = true;
/// The main entry point, i.e. the start of the outermost Yul block.
BasicBlock* entry = nullptr;
/// Subgraphs for functions.
Expand Down
6 changes: 3 additions & 3 deletions libyul/backends/evm/ControlFlowGraphBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ std::unique_ptr<CFG> ControlFlowGraphBuilder::build(
if (yul::EVMDialect const* evmDialect = dynamic_cast<yul::EVMDialect const*>(&_dialect))
eofVersion = evmDialect->eofVersion();

auto result = std::make_unique<CFG>(eofVersion.has_value());
auto result = std::make_unique<CFG>(!eofVersion.has_value());
result->entry = &result->makeBlock(debugDataOf(_block));

ControlFlowSideEffectsCollector sideEffects(_dialect, _block);
Expand Down Expand Up @@ -547,8 +547,8 @@ Stack const& ControlFlowGraphBuilder::visitFunctionCall(FunctionCall const& _cal
Scope::Function const& function = lookupFunction(_call.functionName.name);
canContinue = m_graph.functionInfo.at(&function).canContinue;
Stack inputs;
// For EOF (useFunctions == true) we do not have to put return label on stack.
if (!m_graph.useFunctions && canContinue)
// For EOF (simulateFunctionsWithJumps == false) we do not have to put return label on stack.
if (m_graph.simulateFunctionsWithJumps && canContinue)
inputs.emplace_back(FunctionCallReturnLabelSlot{_call});
for (auto const& arg: _call.arguments | ranges::views::reverse)
inputs.emplace_back(std::visit(*this, arg));
Expand Down
3 changes: 3 additions & 0 deletions libyul/backends/evm/EVMDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ std::vector<std::optional<BuiltinFunctionForEVM>> createBuiltins(langutil::EVMVe
opcode != evmasm::Instruction::DATALOADN &&
opcode != evmasm::Instruction::EOFCREATE &&
opcode != evmasm::Instruction::RETURNCONTRACT &&
opcode != evmasm::Instruction::CALLF &&
opcode != evmasm::Instruction::JUMPF &&
opcode != evmasm::Instruction::RETF &&
_evmVersion.hasOpcode(opcode, _eofVersion) &&
!prevRandaoException(name)
)
Expand Down
2 changes: 1 addition & 1 deletion libyul/backends/evm/EthAssemblyAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ std::pair<std::shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssembl
return {std::make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
}

AbstractAssembly::FunctionID EthAssemblyAdapter::createFunction(uint8_t _args, uint8_t _rets)
AbstractAssembly::FunctionID EthAssemblyAdapter::registerFunction(uint8_t _args, uint8_t _rets)
{
return m_assembly.createFunction(_args, _rets);
}
Expand Down
2 changes: 1 addition & 1 deletion libyul/backends/evm/EthAssemblyAdapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class EthAssemblyAdapter: public AbstractAssembly
void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override;
void appendAssemblySize() override;
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::string _name = {}) override;
AbstractAssembly::FunctionID createFunction(uint8_t _args, uint8_t _rets) override;
AbstractAssembly::FunctionID registerFunction(uint8_t _args, uint8_t _rets) override;
void beginFunction(AbstractAssembly::FunctionID _functionID) override;
void endFunction() override;
void appendFunctionCall(FunctionID _functionID) override;
Expand Down
30 changes: 21 additions & 9 deletions libyul/backends/evm/NoOutputAssembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,29 +120,41 @@ std::pair<std::shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAs
return {};
}

AbstractAssembly::FunctionID NoOutputAssembly::createFunction(uint8_t _args, uint8_t _rets)
AbstractAssembly::FunctionID NoOutputAssembly::registerFunction(uint8_t _args, uint8_t _rets)
{
yulAssert(m_context->numFunctions <= std::numeric_limits<AbstractAssembly::FunctionID>::max());
AbstractAssembly::FunctionID id = static_cast<AbstractAssembly::FunctionID>(m_context->numFunctions++);
m_context->functionSignatures[id] = std::make_pair(_args, _rets);
yulAssert(m_context.numFunctions <= std::numeric_limits<AbstractAssembly::FunctionID>::max());
AbstractAssembly::FunctionID id = static_cast<AbstractAssembly::FunctionID>(m_context.numFunctions++);
m_context.functionSignatures[id] = std::make_pair(_args, _rets);
return id;
}

void NoOutputAssembly::beginFunction(FunctionID)
{}
void NoOutputAssembly::beginFunction(FunctionID _functionID)
{
yulAssert(m_currentFunctionID == 0, "Attempted to begin a function before ending the last one.");
yulAssert(m_context.functionSignatures.count(_functionID) == 1, "Filling unregistered function.");
yulAssert(m_stackHeight == 0, "Non-empty stack on beginFunction call.");
m_currentFunctionID = _functionID;
}

void NoOutputAssembly::endFunction()
{}
{
yulAssert(m_currentFunctionID != 0, "End function without begin function.");
auto const rets = m_context.functionSignatures.at(m_currentFunctionID).second;
yulAssert(rets == 0x80 || m_stackHeight == rets, "Stack height mismatch at function end.");
m_currentFunctionID = 0;
}

void NoOutputAssembly::appendFunctionCall(FunctionID _functionID)
{
auto [args, rets] = m_context->functionSignatures.at(_functionID);
auto [args, rets] = m_context.functionSignatures.at(_functionID);
m_stackHeight += static_cast<int>(rets) - static_cast<int>(args);
}

void NoOutputAssembly::appendFunctionReturn()
{
m_stackHeight = 0;
yulAssert(m_currentFunctionID != 0, "End function without begin function.");
auto const rets = m_context.functionSignatures.at(m_currentFunctionID).second;
yulAssert(rets == 0x80 || m_stackHeight == rets, "Stack height mismatch at function end.");
}

void NoOutputAssembly::appendDataOffset(std::vector<AbstractAssembly::SubID> const&)
Expand Down
7 changes: 4 additions & 3 deletions libyul/backends/evm/NoOutputAssembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ struct NoOutputAssemblyContext
class NoOutputAssembly: public AbstractAssembly
{
public:
explicit NoOutputAssembly(langutil::EVMVersion _evmVersion): m_context(std::make_shared<NoOutputAssemblyContext>()), m_evmVersion(_evmVersion) { }
explicit NoOutputAssembly(langutil::EVMVersion _evmVersion): m_evmVersion(_evmVersion) { }
~NoOutputAssembly() override = default;

void setSourceLocation(langutil::SourceLocation const&) override {}
Expand All @@ -73,7 +73,7 @@ class NoOutputAssembly: public AbstractAssembly

void appendAssemblySize() override;
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::string _name = "") override;
FunctionID createFunction(uint8_t _args, uint8_t _rets) override;
FunctionID registerFunction(uint8_t _args, uint8_t _rets) override;
void beginFunction(FunctionID) override;
void endFunction() override;
void appendFunctionCall(FunctionID _functionID) override;
Expand All @@ -96,8 +96,9 @@ class NoOutputAssembly: public AbstractAssembly
langutil::EVMVersion evmVersion() const override { return m_evmVersion; }

private:
std::shared_ptr<NoOutputAssemblyContext> m_context;
NoOutputAssemblyContext m_context = {};
int m_stackHeight = 0;
FunctionID m_currentFunctionID = 0;
langutil::EVMVersion m_evmVersion;
};

Expand Down
Loading

0 comments on commit d43a66a

Please sign in to comment.