mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #9162 from ethereum/memoryEscalator
Memory Escalator
This commit is contained in:
@@ -142,6 +142,9 @@ public:
|
||||
|
||||
std::set<ContractDefinition const*, ASTNode::CompareByID>& subObjectsCreated() { return m_subObjects; }
|
||||
|
||||
bool inlineAssemblySeen() const { return m_inlineAssemblySeen; }
|
||||
void setInlineAssemblySeen() { m_inlineAssemblySeen = true; }
|
||||
|
||||
private:
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
RevertStrings m_revertStrings;
|
||||
@@ -159,6 +162,9 @@ private:
|
||||
MultiUseYulFunctionCollector m_functions;
|
||||
size_t m_varCounter = 0;
|
||||
|
||||
/// Flag indicating whether any inline assembly block was seen.
|
||||
bool m_inlineAssemblySeen = false;
|
||||
|
||||
/// Function definitions queued for code generation. They're the Solidity functions whose calls
|
||||
/// were discovered by the IR generator during AST traversal.
|
||||
/// Note that the queue gets filled in a lazy way - new definitions can be added while the
|
||||
|
||||
@@ -92,7 +92,7 @@ string IRGenerator::generate(
|
||||
Whiskers t(R"(
|
||||
object "<CreationObject>" {
|
||||
code {
|
||||
<memoryInit>
|
||||
<memoryInitCreation>
|
||||
<callValueCheck>
|
||||
<?notLibrary>
|
||||
<?constructorHasParams> let <constructorParams> := <copyConstructorArguments>() </constructorHasParams>
|
||||
@@ -103,7 +103,7 @@ string IRGenerator::generate(
|
||||
}
|
||||
object "<RuntimeObject>" {
|
||||
code {
|
||||
<memoryInit>
|
||||
<memoryInitRuntime>
|
||||
<dispatch>
|
||||
<runtimeFunctions>
|
||||
}
|
||||
@@ -118,7 +118,6 @@ string IRGenerator::generate(
|
||||
m_context.registerImmutableVariable(*var);
|
||||
|
||||
t("CreationObject", IRNames::creationObject(_contract));
|
||||
t("memoryInit", memoryInit());
|
||||
t("notLibrary", !_contract.isLibrary());
|
||||
|
||||
FunctionDefinition const* constructor = _contract.constructor();
|
||||
@@ -144,6 +143,10 @@ string IRGenerator::generate(
|
||||
t("functions", m_context.functionCollector().requestedFunctions());
|
||||
t("subObjects", subObjectSources(m_context.subObjectsCreated()));
|
||||
|
||||
// This has to be called only after all other code generation for the creation object is complete.
|
||||
bool creationInvolvesAssembly = m_context.inlineAssemblySeen();
|
||||
t("memoryInitCreation", memoryInit(!creationInvolvesAssembly));
|
||||
|
||||
resetContext(_contract);
|
||||
|
||||
// NOTE: Function pointers can be passed from creation code via storage variables. We need to
|
||||
@@ -158,6 +161,10 @@ string IRGenerator::generate(
|
||||
generateInternalDispatchFunctions();
|
||||
t("runtimeFunctions", m_context.functionCollector().requestedFunctions());
|
||||
t("runtimeSubObjects", subObjectSources(m_context.subObjectsCreated()));
|
||||
|
||||
// This has to be called only after all other code generation for the runtime object is complete.
|
||||
bool runtimeInvolvesAssembly = m_context.inlineAssemblySeen();
|
||||
t("memoryInitRuntime", memoryInit(!runtimeInvolvesAssembly));
|
||||
return t.render();
|
||||
}
|
||||
|
||||
@@ -651,16 +658,22 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
||||
return t.render();
|
||||
}
|
||||
|
||||
string IRGenerator::memoryInit()
|
||||
string IRGenerator::memoryInit(bool _useMemoryGuard)
|
||||
{
|
||||
// This function should be called at the beginning of the EVM call frame
|
||||
// and thus can assume all memory to be zero, including the contents of
|
||||
// the "zero memory area" (the position CompilerUtils::zeroPointer points to).
|
||||
return
|
||||
Whiskers{"mstore(<memPtr>, <freeMemoryStart>)"}
|
||||
Whiskers{
|
||||
_useMemoryGuard ?
|
||||
"mstore(<memPtr>, memoryguard(<freeMemoryStart>))" :
|
||||
"mstore(<memPtr>, <freeMemoryStart>)"
|
||||
}
|
||||
("memPtr", to_string(CompilerUtils::freeMemoryPointer))
|
||||
("freeMemoryStart", to_string(CompilerUtils::generalPurposeMemoryStart + m_context.reservedMemory()))
|
||||
.render();
|
||||
(
|
||||
"freeMemoryStart",
|
||||
to_string(CompilerUtils::generalPurposeMemoryStart + m_context.reservedMemory())
|
||||
).render();
|
||||
}
|
||||
|
||||
void IRGenerator::resetContext(ContractDefinition const& _contract)
|
||||
|
||||
@@ -100,7 +100,9 @@ private:
|
||||
|
||||
std::string dispatchRoutine(ContractDefinition const& _contract);
|
||||
|
||||
std::string memoryInit();
|
||||
/// @a _useMemoryGuard If true, use a memory guard, allowing the optimiser
|
||||
/// to perform memory optimizations.
|
||||
std::string memoryInit(bool _useMemoryGuard);
|
||||
|
||||
void resetContext(ContractDefinition const& _contract);
|
||||
|
||||
|
||||
@@ -1858,6 +1858,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
|
||||
{
|
||||
setLocation(_inlineAsm);
|
||||
m_context.setInlineAssemblySeen();
|
||||
CopyTranslate bodyCopier{_inlineAsm.dialect(), m_context, _inlineAsm.annotation().externalReferences};
|
||||
|
||||
yul::Statement modified = bodyCopier(_inlineAsm.operations());
|
||||
|
||||
Reference in New Issue
Block a user