From aba06b1c635140f26cd26caf30ce5a6737cbe0e2 Mon Sep 17 00:00:00 2001 From: Nikola Matic Date: Mon, 20 Feb 2023 15:37:06 +0100 Subject: [PATCH] Add LinkerObject check and more tests --- libevmasm/Assembly.cpp | 22 ++++++++- libevmasm/LinkerObject.cpp | 12 +++++ libevmasm/LinkerObject.h | 3 ++ .../functionCall/failed_create.sol | 2 +- .../libraries/library_references_preserve.sol | 48 +++++++++++++++++++ .../libyul/objectCompiler/subObjectAccess.yul | 4 +- 6 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 test/libsolidity/semanticTests/libraries/library_references_preserve.sol diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index f596f6303..64e5555eb 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -679,11 +679,29 @@ LinkerObject const& Assembly::assemble() const // Append an INVALID here to help tests find miscompilation. ret.bytecode.push_back(static_cast(Instruction::INVALID)); + map subAssemblyOffsets; + map subAssemblyLinkerObjects; for (auto const& [subIdPath, bytecodeOffset]: subRef) { + LinkerObject subObject = subAssemblyById(subIdPath)->assemble(); + util::h256 h(util::keccak256(util::asString(subObject.bytecode))); bytesRef r(ret.bytecode.data() + bytecodeOffset, bytesPerDataRef); - toBigEndian(ret.bytecode.size(), r); - ret.append(subAssemblyById(subIdPath)->assemble()); + size_t* subAssemblyOffset = util::valueOrNullptr(subAssemblyOffsets, h); + LinkerObject* subAssemblyLinkerObject = util::valueOrNullptr(subAssemblyLinkerObjects, h); + + // In order for de-duplication to kick in, the bytecode must not only already be present in the + // subAssemblyOffset map, but the LinkerObjects must match as well (linker references, immutable references, etc.) + if (subAssemblyOffset && *subAssemblyLinkerObject == subObject) + toBigEndian(*subAssemblyOffset, r); + else + { + toBigEndian(ret.bytecode.size(), r); + subAssemblyOffsets[h] = ret.bytecode.size(); + subAssemblyLinkerObjects[h] = subObject; + ret.bytecode += subObject.bytecode; + } + for (auto const& ref: subObject.linkReferences) + ret.linkReferences[ref.first + subAssemblyOffsets[h]] = ref.second; } for (auto const& i: tagRef) diff --git a/libevmasm/LinkerObject.cpp b/libevmasm/LinkerObject.cpp index 07e34acab..8e36321d6 100644 --- a/libevmasm/LinkerObject.cpp +++ b/libevmasm/LinkerObject.cpp @@ -77,3 +77,15 @@ LinkerObject::matchLibrary( return &it->second; return nullptr; } + +bool LinkerObject::operator==(LinkerObject const& _other) const +{ + return this->bytecode == _other.bytecode && + this->linkReferences == _other.linkReferences && + this->immutableReferences == _other.immutableReferences; +} + +bool LinkerObject::operator!=(LinkerObject const& _other) const +{ + return !(*this == _other); +} \ No newline at end of file diff --git a/libevmasm/LinkerObject.h b/libevmasm/LinkerObject.h index c23426882..5d27ff7e6 100644 --- a/libevmasm/LinkerObject.h +++ b/libevmasm/LinkerObject.h @@ -72,6 +72,9 @@ struct LinkerObject /// of the first 18 bytes of the keccak-256 hash of @a _libraryName. static std::string libraryPlaceholder(std::string const& _libraryName); + bool operator==(LinkerObject const& _other) const; + bool operator!=(LinkerObject const& _other) const; + private: static util::h160 const* matchLibrary( std::string const& _linkRefName, diff --git a/test/libsolidity/semanticTests/functionCall/failed_create.sol b/test/libsolidity/semanticTests/functionCall/failed_create.sol index cf865ff19..aacaa0e0a 100644 --- a/test/libsolidity/semanticTests/functionCall/failed_create.sol +++ b/test/libsolidity/semanticTests/functionCall/failed_create.sol @@ -17,7 +17,7 @@ contract C { // EVMVersion: >=byzantium // ---- // constructor(), 20 wei -// gas irOptimized: 184005 +// gas irOptimized: 179697 // gas legacy: 294335 // gas legacyOptimized: 173427 // f(uint256): 20 -> 0x137aa4dfc0911524504fcd4d98501f179bc13b4a diff --git a/test/libsolidity/semanticTests/libraries/library_references_preserve.sol b/test/libsolidity/semanticTests/libraries/library_references_preserve.sol new file mode 100644 index 000000000..ce41e54e9 --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/library_references_preserve.sol @@ -0,0 +1,48 @@ +library L1 { + function add(uint256 a, uint256 b) external pure returns (uint256) { + return a + b + 1; + } +} + +library L2 { + function add(uint256 a, uint256 b) external pure returns (uint256) { + return a + b + 2; + } +} + +contract A { + uint256 sum; + constructor() { + sum = L1.add(1, 2); + } + function getSum() external view returns(uint256) { + return sum; + } +} + +contract B { + uint256 sum; + constructor() { + sum = L2.add(1, 2); + } + function getSum() external view returns(uint256) { + return sum; + } +} + +contract C { + A a = new A(); + B b = new B(); + function aSum() external view returns(uint256) { + return a.getSum(); + } + function bSum() external view returns(uint256) { + return b.getSum(); + } +} + +// ---- +// library: L1 +// library: L2 +// aSum() -> 4 +// bSum() -> 5 diff --git a/test/libyul/objectCompiler/subObjectAccess.yul b/test/libyul/objectCompiler/subObjectAccess.yul index 1e28ed5d5..1899551fd 100644 --- a/test/libyul/objectCompiler/subObjectAccess.yul +++ b/test/libyul/objectCompiler/subObjectAccess.yul @@ -249,6 +249,6 @@ object "A" { // invalid // } // } -// Bytecode: 600060996045603f60866013608560016084600189600055886020558760405586606055856080558460a0558360c0558260e055816101005580610120556101406000f3fe602a6013603d6001603e600185600055846020558360405582606055816080558060a05560c06000f3fe60126001816000558060205560406000f3fefefefefefe60126001816000558060205560406000f3fefe -// Opcodes: PUSH1 0x0 PUSH1 0x99 PUSH1 0x45 PUSH1 0x3F PUSH1 0x86 PUSH1 0x13 PUSH1 0x85 PUSH1 0x1 PUSH1 0x84 PUSH1 0x1 DUP10 PUSH1 0x0 SSTORE DUP9 PUSH1 0x20 SSTORE DUP8 PUSH1 0x40 SSTORE DUP7 PUSH1 0x60 SSTORE DUP6 PUSH1 0x80 SSTORE DUP5 PUSH1 0xA0 SSTORE DUP4 PUSH1 0xC0 SSTORE DUP3 PUSH1 0xE0 SSTORE DUP2 PUSH2 0x100 SSTORE DUP1 PUSH2 0x120 SSTORE PUSH2 0x140 PUSH1 0x0 RETURN INVALID PUSH1 0x2A PUSH1 0x13 PUSH1 0x3D PUSH1 0x1 PUSH1 0x3E PUSH1 0x1 DUP6 PUSH1 0x0 SSTORE DUP5 PUSH1 0x20 SSTORE DUP4 PUSH1 0x40 SSTORE DUP3 PUSH1 0x60 SSTORE DUP2 PUSH1 0x80 SSTORE DUP1 PUSH1 0xA0 SSTORE PUSH1 0xC0 PUSH1 0x0 RETURN INVALID PUSH1 0x12 PUSH1 0x1 DUP2 PUSH1 0x0 SSTORE DUP1 PUSH1 0x20 SSTORE PUSH1 0x40 PUSH1 0x0 RETURN INVALID INVALID INVALID INVALID INVALID INVALID PUSH1 0x12 PUSH1 0x1 DUP2 PUSH1 0x0 SSTORE DUP1 PUSH1 0x20 SSTORE PUSH1 0x40 PUSH1 0x0 RETURN INVALID INVALID +// Bytecode: 600060976045603e60846013608360016083600189600055886020558760405586606055856080558460a0558360c0558260e055816101005580610120556101406000f3fe602a6013603d6001603d600185600055846020558360405582606055816080558060a05560c06000f3fe60126001816000558060205560406000f3fefefefe60126001816000558060205560406000f3fefe +// Opcodes: PUSH1 0x0 PUSH1 0x97 PUSH1 0x45 PUSH1 0x3E PUSH1 0x84 PUSH1 0x13 PUSH1 0x83 PUSH1 0x1 PUSH1 0x83 PUSH1 0x1 DUP10 PUSH1 0x0 SSTORE DUP9 PUSH1 0x20 SSTORE DUP8 PUSH1 0x40 SSTORE DUP7 PUSH1 0x60 SSTORE DUP6 PUSH1 0x80 SSTORE DUP5 PUSH1 0xA0 SSTORE DUP4 PUSH1 0xC0 SSTORE DUP3 PUSH1 0xE0 SSTORE DUP2 PUSH2 0x100 SSTORE DUP1 PUSH2 0x120 SSTORE PUSH2 0x140 PUSH1 0x0 RETURN INVALID PUSH1 0x2A PUSH1 0x13 PUSH1 0x3D PUSH1 0x1 PUSH1 0x3D PUSH1 0x1 DUP6 PUSH1 0x0 SSTORE DUP5 PUSH1 0x20 SSTORE DUP4 PUSH1 0x40 SSTORE DUP3 PUSH1 0x60 SSTORE DUP2 PUSH1 0x80 SSTORE DUP1 PUSH1 0xA0 SSTORE PUSH1 0xC0 PUSH1 0x0 RETURN INVALID PUSH1 0x12 PUSH1 0x1 DUP2 PUSH1 0x0 SSTORE DUP1 PUSH1 0x20 SSTORE PUSH1 0x40 PUSH1 0x0 RETURN INVALID INVALID INVALID INVALID PUSH1 0x12 PUSH1 0x1 DUP2 PUSH1 0x0 SSTORE DUP1 PUSH1 0x20 SSTORE PUSH1 0x40 PUSH1 0x0 RETURN INVALID INVALID // SourceMappings: 37:15:0:-:0;68:13;97:15;128:13;158:17;192:15;224:17;258:15;291:19;328:17;361:3;358:1;351:14;381:3;377:2;370:15;401:3;397:2;390:15;421:3;417:2;410:15;442:4;437:3;430:17;464:4;459:3;452:17;486:4;481:3;474:17;508:4;503:3;496:17;530:5;525:3;518:18;553:5;548:3;541:18;574:3;571:1;564:14