Coverage Report

Created: 2026-10-26 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/solidity/libyul/backends/evm/EVMObjectCompiler.cpp
Line
Count
Source
1
/*
2
  This file is part of solidity.
3
4
  solidity is free software: you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation, either version 3 of the License, or
7
  (at your option) any later version.
8
9
  solidity is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
14
  You should have received a copy of the GNU General Public License
15
  along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
// SPDX-License-Identifier: GPL-3.0
18
/**
19
 * Compiler that transforms Yul Objects to EVM bytecode objects.
20
 */
21
22
#include <libyul/backends/evm/EVMObjectCompiler.h>
23
24
#include <libyul/backends/evm/ssa/CodeTransform.h>
25
#include <libyul/backends/evm/ssa/SSACFGBuilder.h>
26
#include <libyul/backends/evm/ssa/ControlFlowGraphs.h>
27
28
#include <libyul/backends/evm/ssa/transform/OptimizationPipeline.h>
29
30
#include <libyul/backends/evm/EVMCodeTransform.h>
31
#include <libyul/backends/evm/EVMDialect.h>
32
#include <libyul/backends/evm/OptimizedEVMCodeTransform.h>
33
34
#include <libyul/optimiser/FunctionCallFinder.h>
35
36
#include <libyul/Object.h>
37
#include <libyul/Exceptions.h>
38
39
#include <boost/algorithm/string.hpp>
40
41
using namespace solidity::yul;
42
43
void EVMObjectCompiler::compile(
44
  Object const& _object,
45
  AbstractAssembly& _assembly,
46
  bool _optimize,
47
  bool _viaSSACFG
48
)
49
48.3k
{
50
48.3k
  EVMObjectCompiler compiler(_assembly);
51
48.3k
  compiler.run(_object, _optimize, _viaSSACFG);
52
48.3k
}
53
54
void EVMObjectCompiler::run(Object const& _object, bool _optimize, bool _viaSSACFG)
55
48.3k
{
56
48.3k
  yulAssert(_object.dialect());
57
48.3k
  auto const* evmDialect = dynamic_cast<EVMDialect const*>(_object.dialect());
58
48.3k
  yulAssert(evmDialect);
59
60
48.3k
  BuiltinContext context;
61
48.3k
  context.currentObject = &_object;
62
63
64
48.3k
  for (auto const& subNode: _object.subObjects)
65
23.3k
    if (auto* subObject = dynamic_cast<Object*>(subNode.get()))
66
11.5k
    {
67
11.5k
      bool isCreation = !boost::ends_with(subObject->name, "_deployed");
68
11.5k
      auto subAssemblyAndID = m_assembly.createSubAssembly(isCreation, subObject->name);
69
11.5k
      context.subIDs[subObject->name] = subAssemblyAndID.second;
70
11.5k
      subObject->subId = subAssemblyAndID.second;
71
11.5k
      compile(*subObject, *subAssemblyAndID.first, _optimize, _viaSSACFG);
72
11.5k
    }
73
11.7k
    else
74
11.7k
    {
75
11.7k
      Data const& data = dynamic_cast<Data const&>(*subNode);
76
      // Special handling of metadata.
77
11.7k
      if (data.name == Object::metadataName())
78
4.42k
        m_assembly.appendToAuxiliaryData(data.data);
79
7.30k
      else
80
7.30k
        context.subIDs[data.name] = m_assembly.appendData(data.data);
81
11.7k
    }
82
83
48.3k
  yulAssert(_object.analysisInfo, "No analysis info.");
84
48.3k
  yulAssert(_object.hasCode(), "No code.");
85
48.3k
  if (_optimize && evmDialect->evmVersion().canOverchargeGasForCall())
86
43.5k
  {
87
43.5k
    if (_viaSSACFG)
88
0
    {
89
0
      std::unique_ptr<ssa::ControlFlowGraphs> controlFlowGraphs = ssa::SSACFGBuilder::build(
90
0
        *_object.analysisInfo,
91
0
        *evmDialect,
92
0
        _object.code()->root(),
93
0
        false
94
0
      );
95
0
      ssa::transform::optimize(*controlFlowGraphs);
96
0
      ssa::ControlFlowGraphsLiveness const liveness(*controlFlowGraphs);
97
0
      ssa::CodeTransform::run(
98
0
        m_assembly,
99
0
        *controlFlowGraphs,
100
0
        liveness,
101
0
        context
102
0
      );
103
0
    }
104
43.5k
    else
105
43.5k
    {
106
43.5k
      auto stackErrors = OptimizedEVMCodeTransform::run(
107
43.5k
        m_assembly,
108
43.5k
        *_object.analysisInfo,
109
43.5k
        _object.code()->root(),
110
43.5k
        *evmDialect,
111
43.5k
        context,
112
43.5k
        OptimizedEVMCodeTransform::UseNamedLabels::ForFirstFunctionOfEachName
113
43.5k
      );
114
43.5k
      if (!stackErrors.empty())
115
1.15k
      {
116
1.15k
        yulAssert(evmDialect->providesObjectAccess());
117
1.15k
        auto const memoryGuardHandle = evmDialect->findBuiltin("memoryguard");
118
1.15k
        yulAssert(memoryGuardHandle, "Compiling with object access, memoryguard should be available as builtin.");
119
1.15k
        std::vector<FunctionCall const*> memoryGuardCalls = findFunctionCalls(
120
1.15k
          _object.code()->root(),
121
1.15k
          *memoryGuardHandle
122
1.15k
        );
123
1.15k
        auto stackError = stackErrors.front();
124
1.15k
        std::string msg = stackError.comment() ? *stackError.comment() : "";
125
1.15k
        if (memoryGuardCalls.empty())
126
1.11k
          msg += "\nNo memoryguard was present. "
127
1.11k
            "Consider using memory-safe assembly only and annotating it via "
128
1.11k
            "'assembly (\"memory-safe\") { ... }'.";
129
36
        else
130
36
          msg += "\nmemoryguard was present.";
131
1.15k
        stackError << util::errinfo_comment(msg);
132
1.15k
        BOOST_THROW_EXCEPTION(stackError);
133
1.15k
      }
134
43.5k
    }
135
43.5k
  }
136
4.77k
  else
137
4.77k
  {
138
    // We do not catch and re-throw the stack too deep exception here because it is a YulException,
139
    // which should be native to this part of the code.
140
4.77k
    CodeTransform transform{
141
4.77k
      m_assembly,
142
4.77k
      *_object.analysisInfo,
143
4.77k
      _object.code()->root(),
144
4.77k
      *evmDialect,
145
4.77k
      context,
146
4.77k
      _optimize,
147
4.77k
      {},
148
4.77k
      CodeTransform::UseNamedLabels::ForFirstFunctionOfEachName
149
4.77k
    };
150
4.77k
    transform(_object.code()->root());
151
4.77k
    if (!transform.stackErrors().empty())
152
      BOOST_THROW_EXCEPTION(transform.stackErrors().front());
153
4.77k
  }
154
48.3k
}