Skip to content

Can be Optimized Linked Library Address Bytecode Fragment #16096

Open
@Hellobloc

Description

@Hellobloc

Abstract

In Solidity, we can delegatecall public functions of a library to execute external library code, a pattern originally introduced to help contracts stay below the byte-size limit at deployment time. Unfortunately, the current compiler implementation defeats this purpose: on every delegatecall the generated bytecode embeds a redundant PUSH20 <LibraryAddress> instruction—often longer than the library code itself. As a result, in many scenarios the delegatecall pattern simultaneously increases gas consumption and bytecode size. This is a problem that the compiler could solve through optimization.

Motivation

Consider the following example:

pragma solidity >=0.7.0 <0.9.0;

library Ballot {
    function B() public { }
    function C() public { }
}

contract A {
    function C() public {
        Ballot.B();
    }
    function D() public {
        Ballot.C();
    }
}

The bytecode of contract A is roughly when Optimization is set.

60806040..73__$17280f6b09cfc0597fda7b4937e1c059ab$__63c89e43..
73__$17280f6b09cfc0597fda7b4937e1c059ab$__63fe073d1160..

Because A.C() and A.D() each make a library call, we see two separate PUSH20 <LibraryAddress> sequences in the bytecode. A feature meant to compress code actually injects sizeable, duplicate address literals every time the library is invoked. Hoisting this address into a shared basic block would eliminate the redundancy.

Most libraries function are far smaller than 20 bytes, yet each external call still emits a full PUSH20.

Proposal

For the library delegatecall scenario, users care primarily about shrinking deployment bytecode, not marginal gas savings. We therefore propose that the compiler, by default, consolidate all identical PUSH20 <address> instructions for a given library into a single basic block and reuse it across every call site. This would remove redundant code fragments and restore the original byte-size advantage of the library mechanism.

PUSH20 Address
...
PUSH20 Address 

TO

JUMPDEST
PUSH20 Address
JUMP
...
PUSH <ORIGINPC>
PUSH <PUSHADDREPC>
JUMP
...
PUSH <ORIGINPC>
PUSH <PUSHADDRE>
JUMP

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions