Skip to content

Commit ce0a3e9

Browse files
committed
Store whether an evmasm Assembly is creation code.
1 parent c6fcb6c commit ce0a3e9

23 files changed

+62
-47
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Compiler Features:
88
* JSON-AST: Added selector field for errors and events.
99

1010
Bugfixes:
11+
* Yul IR Code Generation: Optimize embedded creation code with correct settings. This fixes potential mismatches between the constructor code of a contract compiled in isolation and the bytecode in ``type(C).creationCode``, resp. the bytecode used for ``new C(...)``.
1112

1213

1314
### 0.8.12 (2022-02-16)

libevmasm/Assembly.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -411,13 +411,15 @@ map<u256, u256> const& Assembly::optimiseInternal(
411411
if (m_tagReplacements)
412412
return *m_tagReplacements;
413413

414+
assertThrow(_settings.isCreation == m_creation, OptimizerException, "Mismatching creation settings.");
415+
414416
// Run optimisation for sub-assemblies.
415417
for (size_t subId = 0; subId < m_subs.size(); ++subId)
416418
{
417419
OptimiserSettings settings = _settings;
418-
// Disable creation mode for sub-assemblies.
419-
settings.isCreation = false;
420-
map<u256, u256> const& subTagReplacements = m_subs[subId]->optimiseInternal(
420+
Assembly& sub = *m_subs[subId];
421+
settings.isCreation = sub.isCreation();
422+
map<u256, u256> const& subTagReplacements = sub.optimiseInternal(
421423
settings,
422424
JumpdestRemover::referencedTags(m_items, subId)
423425
);

libevmasm/Assembly.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ using AssemblyPointer = std::shared_ptr<Assembly>;
4848
class Assembly
4949
{
5050
public:
51-
explicit Assembly(std::string _name = std::string()):m_name(std::move(_name)) { }
51+
Assembly(bool _creation, std::string _name): m_creation(_creation), m_name(std::move(_name)) { }
5252

5353
AssemblyItem newTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(Tag, m_usedTags++); }
5454
AssemblyItem newPushTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(PushTag, m_usedTags++); }
@@ -157,6 +157,8 @@ class Assembly
157157
std::vector<size_t> decodeSubPath(size_t _subObjectId) const;
158158
size_t encodeSubPath(std::vector<size_t> const& _subPath);
159159

160+
bool isCreation() const { return m_creation; }
161+
160162
protected:
161163
/// Does the same operations as @a optimise, but should only be applied to a sub and
162164
/// returns the replaced tags. Also takes an argument containing the tags of this assembly
@@ -214,6 +216,8 @@ class Assembly
214216
mutable std::vector<size_t> m_tagPositionsInBytecode;
215217

216218
int m_deposit = 0;
219+
/// True, if the assembly contains contract creation code.
220+
bool const m_creation = false;
217221
/// Internal name of the assembly object, only used with the Yul backend
218222
/// currently
219223
std::string m_name;

libsolidity/codegen/CompilerContext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class CompilerContext
6565
RevertStrings _revertStrings,
6666
CompilerContext* _runtimeContext = nullptr
6767
):
68-
m_asm(std::make_shared<evmasm::Assembly>()),
68+
m_asm(std::make_shared<evmasm::Assembly>(_runtimeContext != nullptr, std::string{})),
6969
m_evmVersion(_evmVersion),
7070
m_revertStrings(_revertStrings),
7171
m_reservedMemory{0},

libyul/AssemblyStack.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
#include <libevmasm/Assembly.h>
4040
#include <liblangutil/Scanner.h>
41+
#include <boost/algorithm/string.hpp>
4142
#include <optional>
4243

4344
using namespace std;
@@ -194,7 +195,10 @@ void AssemblyStack::optimize(Object& _object, bool _isCreation)
194195
yulAssert(_object.analysisInfo, "");
195196
for (auto& subNode: _object.subObjects)
196197
if (auto subObject = dynamic_cast<Object*>(subNode.get()))
197-
optimize(*subObject, false);
198+
{
199+
bool isCreation = !boost::ends_with(subObject->name.str(), "_deployed");
200+
optimize(*subObject, isCreation);
201+
}
198202

199203
Dialect const& dialect = languageToDialect(m_language, m_evmVersion);
200204
unique_ptr<GasMeter> meter;
@@ -281,7 +285,7 @@ AssemblyStack::assembleEVMWithDeployed(optional<string_view> _deployName) const
281285
yulAssert(m_parserResult->code, "");
282286
yulAssert(m_parserResult->analysisInfo, "");
283287

284-
evmasm::Assembly assembly;
288+
evmasm::Assembly assembly(true, {});
285289
EthAssemblyAdapter adapter(assembly);
286290
compileEVM(adapter, m_optimiserSettings.optimizeStackAllocation);
287291

libyul/backends/evm/AbstractAssembly.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ class AbstractAssembly
9898
/// Append the assembled size as a constant.
9999
virtual void appendAssemblySize() = 0;
100100
/// Creates a new sub-assembly, which can be referenced using dataSize and dataOffset.
101-
virtual std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(std::string _name = "") = 0;
101+
virtual std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::string _name = "") = 0;
102102
/// Appends the offset of the given sub-assembly or data.
103103
virtual void appendDataOffset(std::vector<SubID> const& _subPath) = 0;
104104
/// Appends the size of the given sub-assembly or data.

libyul/backends/evm/EVMObjectCompiler.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#include <libyul/Object.h>
3131
#include <libyul/Exceptions.h>
3232

33+
#include <boost/algorithm/string.hpp>
34+
3335
using namespace solidity::yul;
3436
using namespace std;
3537

@@ -48,7 +50,8 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize)
4850
for (auto const& subNode: _object.subObjects)
4951
if (auto* subObject = dynamic_cast<Object*>(subNode.get()))
5052
{
51-
auto subAssemblyAndID = m_assembly.createSubAssembly(subObject->name.str());
53+
bool isCreation = !boost::ends_with(subObject->name.str(), "_deployed");
54+
auto subAssemblyAndID = m_assembly.createSubAssembly(isCreation, subObject->name.str());
5255
context.subIDs[subObject->name] = subAssemblyAndID.second;
5356
subObject->subId = subAssemblyAndID.second;
5457
compile(*subObject, *subAssemblyAndID.first, m_dialect, _optimize);

libyul/backends/evm/EthAssemblyAdapter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,9 @@ void EthAssemblyAdapter::appendAssemblySize()
122122
m_assembly.appendProgramSize();
123123
}
124124

125-
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(string _name)
125+
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(bool _creation, string _name)
126126
{
127-
shared_ptr<evmasm::Assembly> assembly{make_shared<evmasm::Assembly>(std::move(_name))};
127+
shared_ptr<evmasm::Assembly> assembly{make_shared<evmasm::Assembly>(_creation, std::move(_name))};
128128
auto sub = m_assembly.newSub(assembly);
129129
return {make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
130130
}

libyul/backends/evm/EthAssemblyAdapter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class EthAssemblyAdapter: public AbstractAssembly
5555
void appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) override;
5656
void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override;
5757
void appendAssemblySize() override;
58-
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(std::string _name = {}) override;
58+
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::string _name = {}) override;
5959
void appendDataOffset(std::vector<SubID> const& _subPath) override;
6060
void appendDataSize(std::vector<SubID> const& _subPath) override;
6161
SubID appendData(bytes const& _data) override;

libyul/backends/evm/NoOutputAssembly.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ void NoOutputAssembly::appendAssemblySize()
9898
appendInstruction(evmasm::Instruction::PUSH1);
9999
}
100100

101-
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(std::string)
101+
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(bool, std::string)
102102
{
103103
yulAssert(false, "Sub assemblies not implemented.");
104104
return {};

0 commit comments

Comments
 (0)