Do not duplicate subassemblies.

Add LinkerObject check and more tests
This commit is contained in:
Daniel Kirchner 2022-12-14 15:52:05 +01:00 committed by Nikola Matic
parent 18b42dccd6
commit 4064116df4
8 changed files with 117 additions and 6 deletions

View File

@ -9,6 +9,7 @@ Compiler Features:
Bugfixes: Bugfixes:
* Code Generator: Avoid including references to the deployed label of referenced functions if they are called right away. * Code Generator: Avoid including references to the deployed label of referenced functions if they are called right away.
* Assembler: Avoid duplicating subassembly bytecode where possible.
* ContractLevelChecker: Properly distinguish the case of missing base constructor arguments from having an unimplemented base function. * ContractLevelChecker: Properly distinguish the case of missing base constructor arguments from having an unimplemented base function.
* SMTChecker: Fix internal error when using the custom NatSpec annotation to abstract free functions. * SMTChecker: Fix internal error when using the custom NatSpec annotation to abstract free functions.
* TypeChecker: Also allow external library functions in ``using for``. * TypeChecker: Also allow external library functions in ``using for``.

View File

@ -679,13 +679,25 @@ LinkerObject const& Assembly::assemble() const
// Append an INVALID here to help tests find miscompilation. // Append an INVALID here to help tests find miscompilation.
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::INVALID)); ret.bytecode.push_back(static_cast<uint8_t>(Instruction::INVALID));
map<LinkerObject, size_t> subAssemblyOffsets;
for (auto const& [subIdPath, bytecodeOffset]: subRef) for (auto const& [subIdPath, bytecodeOffset]: subRef)
{ {
LinkerObject subObject = subAssemblyById(subIdPath)->assemble();
bytesRef r(ret.bytecode.data() + bytecodeOffset, bytesPerDataRef); bytesRef r(ret.bytecode.data() + bytecodeOffset, bytesPerDataRef);
toBigEndian(ret.bytecode.size(), r);
ret.append(subAssemblyById(subIdPath)->assemble());
}
// In order for de-duplication to kick in, not only must the bytecode be identical, but
// link and immutables references as well.
if (size_t* subAssemblyOffset = util::valueOrNullptr(subAssemblyOffsets, subObject))
toBigEndian(*subAssemblyOffset, r);
else
{
toBigEndian(ret.bytecode.size(), r);
subAssemblyOffsets[subObject] = ret.bytecode.size();
ret.bytecode += subObject.bytecode;
}
for (auto const& ref: subObject.linkReferences)
ret.linkReferences[ref.first + subAssemblyOffsets[subObject]] = ref.second;
}
for (auto const& i: tagRef) for (auto const& i: tagRef)
{ {
size_t subId; size_t subId;

View File

@ -77,3 +77,9 @@ LinkerObject::matchLibrary(
return &it->second; return &it->second;
return nullptr; return nullptr;
} }
bool LinkerObject::operator<(LinkerObject const& _other) const
{
return tie(this->bytecode, this->linkReferences, this->immutableReferences) <
tie(_other.bytecode, _other.linkReferences, _other.immutableReferences);
}

View File

@ -72,6 +72,8 @@ struct LinkerObject
/// of the first 18 bytes of the keccak-256 hash of @a _libraryName. /// of the first 18 bytes of the keccak-256 hash of @a _libraryName.
static std::string libraryPlaceholder(std::string const& _libraryName); static std::string libraryPlaceholder(std::string const& _libraryName);
bool operator<(LinkerObject const& _other) const;
private: private:
static util::h160 const* matchLibrary( static util::h160 const* matchLibrary(
std::string const& _linkRefName, std::string const& _linkRefName,

View File

@ -0,0 +1,42 @@
contract A {
function longdata() pure external returns (bytes memory) {
return
"xasopca.pngaibngidak.jbtnudak.cAP.BRRSMCPJAGPD KIAJDOMHUKR,SCPID"
"xasopca.pngaibngidak.jbtnudak.cAP.BRRSMCPJAGPD KIAJDOMHUKR,SCPID"
"M,SEYBDXCNTKIMNJGO;DUIAQBQUEHAKMPGIDSAJCOUKANJBCUEBKNA.GIAKMV.TI"
"AJMO<KXBANJCPGUD ABKCJIDHA NKIMAJU,EKAMHSO;PYCAKUM,L.UCA MR;KITA"
"M,SEYBDXCNTKIMNJGO;DUIAQBQUEHAKMPGIDSAJCOUKANJBCUEBKNA.GIAKMV.TI"
"AJMO<KXBANJCPGUD ABKCJIDHA NKIMAJU,EKAMHSO;PYCAKUM,L.UCA MR;KITA"
" .RPOKIDAS,.CKUMT.,ORKAD ,NOKIDHA .CGKIAD OVHAMS CUAOGT DAKN OIT"
"xasopca.pngaibngidak.jbtnudak.cAP.BRRSMCPJAGPD KIAJDOMHUKR,SCPID"
"M,SEYBDXCNTKIMNJGO;DUIAQBQUEHAKMPGIDSAJCOUKANJBCUEBKNA.GIAKMV.TI"
"AJMO<KXBANJCPGUD ABKCJIDHA NKIMAJU,EKAMHSO;PYCAKUM,L.UCA MR;KITA"
"apibakrpidbacnidkacjadtnpdkylca.,jda,r.kuadc,jdlkjd',c'dj, ncg d"
"anosumantkudkc,djntudkantuadnc,ui,c.ud,.nujdncud,j.rsch'pkl.'pih";
}
}
contract C {
constructor() {
}
function a() external returns (bytes memory) {
return type(A).creationCode;
}
function b() external returns (A) {
return new A();
}
function test() public view returns (bool) {
uint x;
assembly {
x := codesize()
}
return type(A).creationCode.length < x &&
x < 2 * type(A).creationCode.length;
}
}
// ----
// test() -> true

View File

@ -17,7 +17,7 @@ contract C {
// EVMVersion: >=byzantium // EVMVersion: >=byzantium
// ---- // ----
// constructor(), 20 wei // constructor(), 20 wei
// gas irOptimized: 184005 // gas irOptimized: 179697
// gas legacy: 294335 // gas legacy: 294335
// gas legacyOptimized: 173427 // gas legacyOptimized: 173427
// f(uint256): 20 -> 0x137aa4dfc0911524504fcd4d98501f179bc13b4a // f(uint256): 20 -> 0x137aa4dfc0911524504fcd4d98501f179bc13b4a

View File

@ -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

View File

@ -249,6 +249,6 @@ object "A" {
// invalid // invalid
// } // }
// } // }
// Bytecode: 600060996045603f60866013608560016084600189600055886020558760405586606055856080558460a0558360c0558260e055816101005580610120556101406000f3fe602a6013603d6001603e600185600055846020558360405582606055816080558060a05560c06000f3fe60126001816000558060205560406000f3fefefefefefe60126001816000558060205560406000f3fefe // Bytecode: 600060976045603e60846013608360016083600189600055886020558760405586606055856080558460a0558360c0558260e055816101005580610120556101406000f3fe602a6013603d6001603d600185600055846020558360405582606055816080558060a05560c06000f3fe60126001816000558060205560406000f3fefefefe60126001816000558060205560406000f3fefe
// 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 // 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 // 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