Legacy codegeneration for immutable state variables.

This commit is contained in:
Daniel Kirchner
2020-03-24 16:45:25 +01:00
committed by chriseth
parent 83cbfbb7bf
commit 04d8ad2ae1
22 changed files with 471 additions and 17 deletions
+87 -2
View File
@@ -283,6 +283,24 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices)
createJsonValue("PUSHDEPLOYADDRESS", sourceIndex, i.location().start, i.location().end)
);
break;
case PushImmutable:
collection.append(createJsonValue(
"PUSHIMMUTABLE",
sourceIndex,
i.location().start,
i.location().end,
m_immutables.at(h256(i.data()))
));
break;
case AssignImmutable:
collection.append(createJsonValue(
"ASSIGNIMMUTABLE",
sourceIndex,
i.location().start,
i.location().end,
m_immutables.at(h256(i.data()))
));
break;
case Tag:
collection.append(
createJsonValue("tag", sourceIndex, i.location().start, i.location().end, toString(i.data())));
@@ -333,6 +351,20 @@ AssemblyItem Assembly::newPushLibraryAddress(string const& _identifier)
return AssemblyItem{PushLibraryAddress, h};
}
AssemblyItem Assembly::newPushImmutable(string const& _identifier)
{
h256 h(util::keccak256(_identifier));
m_immutables[h] = _identifier;
return AssemblyItem{PushImmutable, h};
}
AssemblyItem Assembly::newImmutableAssignment(string const& _identifier)
{
h256 h(util::keccak256(_identifier));
m_immutables[h] = _identifier;
return AssemblyItem{AssignImmutable, h};
}
Assembly& Assembly::optimise(bool _enable, EVMVersion _evmVersion, bool _isCreation, size_t _runs)
{
OptimiserSettings settings;
@@ -495,16 +527,44 @@ LinkerObject const& Assembly::assemble() const
// Otherwise ensure the object is actually clear.
assertThrow(m_assembledObject.linkReferences.empty(), AssemblyException, "Unexpected link references.");
LinkerObject& ret = m_assembledObject;
size_t subTagSize = 1;
map<u256, vector<size_t>> immutableReferencesBySub;
for (auto const& sub: m_subs)
{
sub->assemble();
auto const& linkerObject = sub->assemble();
if (!linkerObject.immutableReferences.empty())
{
assertThrow(
immutableReferencesBySub.empty(),
AssemblyException,
"More than one sub-assembly references immutables."
);
immutableReferencesBySub = linkerObject.immutableReferences;
}
for (size_t tagPos: sub->m_tagPositionsInBytecode)
if (tagPos != size_t(-1) && tagPos > subTagSize)
subTagSize = tagPos;
}
LinkerObject& ret = m_assembledObject;
bool setsImmutables = false;
bool pushesImmutables = false;
for (auto const& i: m_items)
if (i.type() == AssignImmutable)
{
i.setImmutableOccurrences(immutableReferencesBySub[i.data()].size());
setsImmutables = true;
}
else if (i.type() == PushImmutable)
pushesImmutables = true;
if (setsImmutables || pushesImmutables)
assertThrow(
setsImmutables != pushesImmutables,
AssemblyException,
"Cannot push and assign immutables in the same assembly subroutine."
);
size_t bytesRequiredForCode = bytesRequired(subTagSize);
m_tagPositionsInBytecode = vector<size_t>(m_usedTags, -1);
@@ -598,6 +658,24 @@ LinkerObject const& Assembly::assemble() const
ret.linkReferences[ret.bytecode.size()] = m_libraries.at(i.data());
ret.bytecode.resize(ret.bytecode.size() + 20);
break;
case PushImmutable:
ret.bytecode.push_back(uint8_t(Instruction::PUSH32));
ret.immutableReferences[i.data()].emplace_back(ret.bytecode.size());
ret.bytecode.resize(ret.bytecode.size() + 32);
break;
case AssignImmutable:
for (auto const& offset: immutableReferencesBySub[i.data()])
{
ret.bytecode.push_back(uint8_t(Instruction::DUP1));
// TODO: should we make use of the constant optimizer methods for pushing the offsets?
bytes offsetBytes = toCompactBigEndian(u256(offset));
ret.bytecode.push_back(uint8_t(Instruction::PUSH1) - 1 + offsetBytes.size());
ret.bytecode += offsetBytes;
ret.bytecode.push_back(uint8_t(Instruction::MSTORE));
}
immutableReferencesBySub.erase(i.data());
ret.bytecode.push_back(uint8_t(Instruction::POP));
break;
case PushDeployTimeAddress:
ret.bytecode.push_back(uint8_t(Instruction::PUSH20));
ret.bytecode.resize(ret.bytecode.size() + 20);
@@ -615,6 +693,13 @@ LinkerObject const& Assembly::assemble() const
}
}
assertThrow(
immutableReferencesBySub.empty(),
AssemblyException,
"Some immutables were read from but never assigned."
);
if (!m_subs.empty() || !m_data.empty() || !m_auxiliaryData.empty())
// Append an INVALID here to help tests find miscompilation.
ret.bytecode.push_back(uint8_t(Instruction::INVALID));