mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Legacy codegeneration for immutable state variables.
This commit is contained in:
committed by
chriseth
parent
83cbfbb7bf
commit
04d8ad2ae1
+87
-2
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user