Coverage Report

Created: 2026-09-14 06:38

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
46.4k
{
50
46.4k
  EVMObjectCompiler compiler(_assembly);
51
46.4k
  compiler.run(_object, _optimize, _viaSSACFG);
52
46.4k
}
53
54
void EVMObjectCompiler::run(Object const& _object, bool _optimize, bool _viaSSACFG)
55
46.4k
{
56
46.4k
  yulAssert(_object.dialect());
57
46.4k
  auto const* evmDialect = dynamic_cast<EVMDialect const*>(_object.dialect());
58
46.4k
  yulAssert(evmDialect);
59
60
46.4k
  BuiltinContext context;
61
46.4k
  context.currentObject = &_object;
62
63
64
46.4k
  for (auto const& subNode: _object.subObjects)
65
16.4k
    if (auto* subObject = dynamic_cast<Object*>(subNode.get()))
66
8.03k
    {
67
8.03k
      bool isCreation = !boost::ends_with(subObject->name, "_deployed");
68
8.03k
      auto subAssemblyAndID = m_assembly.createSubAssembly(isCreation, subObject->name);
69
8.03k
      context.subIDs[subObject->name] = subAssemblyAndID.second;
70
8.03k
      subObject->subId = subAssemblyAndID.second;
71
8.03k
      compile(*subObject, *subAssemblyAndID.first, _optimize, _viaSSACFG);
72
8.03k
    }
73
8.40k
    else
74
8.40k
    {
75
8.40k
      Data const& data = dynamic_cast<Data const&>(*subNode);
76
      // Special handling of metadata.
77
8.40k
      if (data.name == Object::metadataName())
78
4.50k
        m_assembly.appendToAuxiliaryData(data.data);
79
3.90k
      else
80
3.90k
        context.subIDs[data.name] = m_assembly.appendData(data.data);
81
8.40k
    }
82
83
46.4k
  yulAssert(_object.analysisInfo, "No analysis info.");
84
46.4k
  yulAssert(_object.hasCode(), "No code.");
85
46.4k
  if (_optimize && evmDialect->evmVersion().canOverchargeGasForCall())
86
41.7k
  {
87
41.7k
    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
41.7k
    else
105
41.7k
    {
106
41.7k
      auto stackErrors = OptimizedEVMCodeTransform::run(
107
41.7k
        m_assembly,
108
41.7k
        *_object.analysisInfo,
109
41.7k
        _object.code()->root(),
110
41.7k
        *evmDialect,
111
41.7k
        context,
112
41.7k
        OptimizedEVMCodeTransform::UseNamedLabels::ForFirstFunctionOfEachName
113
41.7k
      );
114
41.7k
      if (!stackErrors.empty())
115
956
      {
116
956
        yulAssert(evmDialect->providesObjectAccess());
117
956
        auto const memoryGuardHandle = evmDialect->findBuiltin("memoryguard");
118
956
        yulAssert(memoryGuardHandle, "Compiling with object access, memoryguard should be available as builtin.");
119
956
        std::vector<FunctionCall const*> memoryGuardCalls = findFunctionCalls(
120
956
          _object.code()->root(),
121
956
          *memoryGuardHandle
122
956
        );
123
956
        auto stackError = stackErrors.front();
124
956
        std::string msg = stackError.comment() ? *stackError.comment() : "";
125
956
        if (memoryGuardCalls.empty())
126
920
          msg += "\nNo memoryguard was present. "
127
920
            "Consider using memory-safe assembly only and annotating it via "
128
920
            "'assembly (\"memory-safe\") { ... }'.";
129
36
        else
130
36
          msg += "\nmemoryguard was present.";
131
956
        stackError << util::errinfo_comment(msg);
132
956
        BOOST_THROW_EXCEPTION(stackError);
133
956
      }
134
41.7k
    }
135
41.7k
  }
136
4.64k
  else
137
4.64k
  {
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.64k
    CodeTransform transform{
141
4.64k
      m_assembly,
142
4.64k
      *_object.analysisInfo,
143
4.64k
      _object.code()->root(),
144
4.64k
      *evmDialect,
145
4.64k
      context,
146
4.64k
      _optimize,
147
4.64k
      {},
148
4.64k
      CodeTransform::UseNamedLabels::ForFirstFunctionOfEachName
149
4.64k
    };
150
4.64k
    transform(_object.code()->root());
151
4.64k
    if (!transform.stackErrors().empty())
152
      BOOST_THROW_EXCEPTION(transform.stackErrors().front());
153
4.64k
  }
154
46.4k
}