Merge remote-tracking branch 'origin/develop' into breaking

This commit is contained in:
chriseth
2022-04-13 17:08:27 +02:00
186 changed files with 3081 additions and 976 deletions
+43 -107
View File
@@ -222,123 +222,59 @@ string Assembly::assemblyString(
return tmp.str();
}
Json::Value Assembly::createJsonValue(string _name, int _source, int _begin, int _end, string _value, string _jumpType)
{
Json::Value value{Json::objectValue};
value["name"] = _name;
value["source"] = _source;
value["begin"] = _begin;
value["end"] = _end;
if (!_value.empty())
value["value"] = _value;
if (!_jumpType.empty())
value["jumpType"] = _jumpType;
return value;
}
string Assembly::toStringInHex(u256 _value)
{
std::stringstream hexStr;
hexStr << std::uppercase << hex << _value;
return hexStr.str();
}
Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices) const
Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices, bool _includeSourceList) const
{
Json::Value root;
root[".code"] = Json::arrayValue;
Json::Value& collection = root[".code"];
for (AssemblyItem const& i: m_items)
Json::Value& code = root[".code"];
for (AssemblyItem const& item: m_items)
{
int sourceIndex = -1;
if (i.location().sourceName)
if (item.location().sourceName)
{
auto iter = _sourceIndices.find(*i.location().sourceName);
auto iter = _sourceIndices.find(*item.location().sourceName);
if (iter != _sourceIndices.end())
sourceIndex = static_cast<int>(iter->second);
}
switch (i.type())
auto [name, data] = item.nameAndData();
Json::Value jsonItem;
jsonItem["name"] = name;
jsonItem["begin"] = item.location().start;
jsonItem["end"] = item.location().end;
if (item.m_modifierDepth != 0)
jsonItem["modifierDepth"] = static_cast<int>(item.m_modifierDepth);
std::string jumpType = item.getJumpTypeAsString();
if (!jumpType.empty())
jsonItem["jumpType"] = jumpType;
if (name == "PUSHLIB")
data = m_libraries.at(h256(data));
else if (name == "PUSHIMMUTABLE" || name == "ASSIGNIMMUTABLE")
data = m_immutables.at(h256(data));
if (!data.empty())
jsonItem["value"] = data;
jsonItem["source"] = sourceIndex;
code.append(move(jsonItem));
if (item.type() == AssemblyItemType::Tag)
{
case Operation:
collection.append(
createJsonValue(
instructionInfo(i.instruction()).name,
sourceIndex,
i.location().start,
i.location().end,
i.getJumpTypeAsString())
);
break;
case Push:
collection.append(
createJsonValue("PUSH", sourceIndex, i.location().start, i.location().end, toStringInHex(i.data()), i.getJumpTypeAsString()));
break;
case PushTag:
if (i.data() == 0)
collection.append(
createJsonValue("PUSH [ErrorTag]", sourceIndex, i.location().start, i.location().end, ""));
else
collection.append(
createJsonValue("PUSH [tag]", sourceIndex, i.location().start, i.location().end, toString(i.data())));
break;
case PushSub:
collection.append(
createJsonValue("PUSH [$]", sourceIndex, i.location().start, i.location().end, toString(h256(i.data()))));
break;
case PushSubSize:
collection.append(
createJsonValue("PUSH #[$]", sourceIndex, i.location().start, i.location().end, toString(h256(i.data()))));
break;
case PushProgramSize:
collection.append(
createJsonValue("PUSHSIZE", sourceIndex, i.location().start, i.location().end));
break;
case PushLibraryAddress:
collection.append(
createJsonValue("PUSHLIB", sourceIndex, i.location().start, i.location().end, m_libraries.at(h256(i.data())))
);
break;
case PushDeployTimeAddress:
collection.append(
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())));
collection.append(
createJsonValue("JUMPDEST", sourceIndex, i.location().start, i.location().end));
break;
case PushData:
collection.append(createJsonValue("PUSH data", sourceIndex, i.location().start, i.location().end, toStringInHex(i.data())));
break;
case VerbatimBytecode:
collection.append(createJsonValue("VERBATIM", sourceIndex, i.location().start, i.location().end, util::toHex(i.verbatimData())));
break;
default:
assertThrow(false, InvalidOpcode, "");
Json::Value jumpdest;
jumpdest["name"] = "JUMPDEST";
jumpdest["begin"] = item.location().start;
jumpdest["end"] = item.location().end;
jumpdest["source"] = sourceIndex;
if (item.m_modifierDepth != 0)
jumpdest["modifierDepth"] = static_cast<int>(item.m_modifierDepth);
code.append(move(jumpdest));
}
}
if (_includeSourceList)
{
root["sourceList"] = Json::arrayValue;
Json::Value& jsonSourceList = root["sourceList"];
for (auto const& [name, index]: _sourceIndices)
jsonSourceList[index] = name;
}
if (!m_data.empty() || !m_subs.empty())
{
@@ -346,17 +282,17 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices)
Json::Value& data = root[".data"];
for (auto const& i: m_data)
if (u256(i.first) >= m_subs.size())
data[toStringInHex((u256)i.first)] = util::toHex(i.second);
data[util::toHex(toBigEndian((u256)i.first), util::HexPrefix::DontAdd, util::HexCase::Upper)] = util::toHex(i.second);
for (size_t i = 0; i < m_subs.size(); ++i)
{
std::stringstream hexStr;
hexStr << hex << i;
data[hexStr.str()] = m_subs[i]->assemblyJSON(_sourceIndices);
data[hexStr.str()] = m_subs[i]->assemblyJSON(_sourceIndices, /*_includeSourceList = */false);
}
}
if (m_auxiliaryData.size() > 0)
if (!m_auxiliaryData.empty())
root[".auxdata"] = util::toHex(m_auxiliaryData);
return root;
+4 -11
View File
@@ -39,6 +39,7 @@
#include <sstream>
#include <memory>
#include <map>
#include <utility>
namespace solidity::evmasm
{
@@ -147,7 +148,8 @@ public:
/// Create a JSON representation of the assembly.
Json::Value assemblyJSON(
std::map<std::string, unsigned> const& _sourceIndices = std::map<std::string, unsigned>()
std::map<std::string, unsigned> const& _sourceIndices = std::map<std::string, unsigned>(),
bool _includeSourceList = true
) const;
/// Mark this assembly as invalid. Calling ``assemble`` on it will throw.
@@ -167,16 +169,6 @@ protected:
unsigned codeSize(unsigned subTagSize) const;
private:
static Json::Value createJsonValue(
std::string _name,
int _source,
int _begin,
int _end,
std::string _value = std::string(),
std::string _jumpType = std::string()
);
static std::string toStringInHex(u256 _value);
bool m_invalid = false;
Assembly const* subAssemblyById(size_t _subId) const;
@@ -222,6 +214,7 @@ protected:
std::string m_name;
langutil::SourceLocation m_currentSourceLocation;
public:
size_t m_currentModifierDepth = 0;
};
+51
View File
@@ -21,6 +21,7 @@
#include <libevmasm/Assembly.h>
#include <libsolutil/CommonData.h>
#include <libsolutil/CommonIO.h>
#include <libsolutil/Numeric.h>
#include <libsolutil/StringUtils.h>
#include <libsolutil/FixedHash.h>
@@ -36,6 +37,18 @@ using namespace solidity::langutil;
static_assert(sizeof(size_t) <= 8, "size_t must be at most 64-bits wide");
namespace
{
string toStringInHex(u256 _value)
{
std::stringstream hexStr;
hexStr << std::uppercase << hex << _value;
return hexStr.str();
}
}
AssemblyItem AssemblyItem::toSubAssemblyTag(size_t _subId) const
{
assertThrow(data() < (u256(1) << 64), util::Exception, "Tag already has subassembly set.");
@@ -56,6 +69,44 @@ pair<size_t, size_t> AssemblyItem::splitForeignPushTag() const
return make_pair(subId, tag);
}
pair<string, string> AssemblyItem::nameAndData() const
{
switch (type())
{
case Operation:
return {instructionInfo(instruction()).name, m_data != nullptr ? toStringInHex(*m_data) : ""};
case Push:
return {"PUSH", toStringInHex(data())};
case PushTag:
if (data() == 0)
return {"PUSH [ErrorTag]", ""};
else
return {"PUSH [tag]", util::toString(data())};
case PushSub:
return {"PUSH [$]", toString(util::h256(data()))};
case PushSubSize:
return {"PUSH #[$]", toString(util::h256(data()))};
case PushProgramSize:
return {"PUSHSIZE", ""};
case PushLibraryAddress:
return {"PUSHLIB", toString(util::h256(data()))};
case PushDeployTimeAddress:
return {"PUSHDEPLOYADDRESS", ""};
case PushImmutable:
return {"PUSHIMMUTABLE", toString(util::h256(data()))};
case AssignImmutable:
return {"ASSIGNIMMUTABLE", toString(util::h256(data()))};
case Tag:
return {"tag", util::toString(data())};
case PushData:
return {"PUSH data", toStringInHex(data())};
case VerbatimBytecode:
return {"VERBATIM", util::toHex(verbatimData())};
default:
assertThrow(false, InvalidOpcode, "");
}
}
void AssemblyItem::setPushTagSubIdAndTag(size_t _subId, size_t _tag)
{
assertThrow(m_type == PushTag || m_type == Tag, util::Exception, "");
+7
View File
@@ -106,6 +106,13 @@ public:
u256 const& data() const { assertThrow(m_type != Operation, util::Exception, ""); return *m_data; }
void setData(u256 const& _data) { assertThrow(m_type != Operation, util::Exception, ""); m_data = std::make_shared<u256>(_data); }
/// This function is used in `Assembly::assemblyJSON`.
/// It returns the name & data of the current assembly item.
/// @returns a pair, where the first element is the json-assembly
/// item name, where second element is the string representation
/// of it's data.
std::pair<std::string, std::string> nameAndData() const;
bytes const& verbatimData() const { assertThrow(m_type == VerbatimBytecode, util::Exception, ""); return std::get<2>(*m_verbatimBytecode); }
/// @returns the instruction of this item (only valid if type() == Operation)
+30 -1
View File
@@ -146,6 +146,35 @@ struct OpStop: SimplePeepholeOptimizerMethod<OpStop>
}
};
struct OpReturnRevert: SimplePeepholeOptimizerMethod<OpReturnRevert>
{
static bool applySimple(
AssemblyItem const& _op,
AssemblyItem const& _push,
AssemblyItem const& _pushOrDup,
AssemblyItem const& _returnRevert,
std::back_insert_iterator<AssemblyItems> _out
)
{
if (
(_returnRevert == Instruction::RETURN || _returnRevert == Instruction::REVERT) &&
_push.type() == Push &&
(_pushOrDup.type() == Push || _pushOrDup == dupInstruction(1))
)
if (
(_op.type() == Operation && !instructionInfo(_op.instruction()).sideEffects) ||
_op.type() == Push
)
{
*_out = _push;
*_out = _pushOrDup;
*_out = _returnRevert;
return true;
}
return false;
}
};
struct DoubleSwap: SimplePeepholeOptimizerMethod<DoubleSwap>
{
static size_t applySimple(AssemblyItem const& _s1, AssemblyItem const& _s2, std::back_insert_iterator<AssemblyItems>)
@@ -459,7 +488,7 @@ bool PeepholeOptimiser::optimise()
while (state.i < m_items.size())
applyMethods(
state,
PushPop(), OpPop(), OpStop(), DoublePush(), DoubleSwap(), CommutativeSwap(), SwapComparison(),
PushPop(), OpPop(), OpStop(), OpReturnRevert(), DoublePush(), DoubleSwap(), CommutativeSwap(), SwapComparison(),
DupSwap(), IsZeroIsZeroJumpI(), EqIsZeroJumpI(), DoubleJump(), JumpToNext(), UnreachableCode(),
TagConjunctions(), TruthyAnd(), Identity()
);