Coverage Report

Created: 2026-08-14 07:35

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