Coverage Report

Created: 2022-08-24 06:43

/src/solidity/libsolidity/codegen/CompilerContext.cpp
Line
Count
Source (jump to first uncovered line)
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
 * @author Christian <c@ethdev.com>
20
 * @date 2014
21
 * Utilities for the solidity compiler.
22
 */
23
24
#include <libsolidity/codegen/CompilerContext.h>
25
26
#include <libsolidity/ast/AST.h>
27
#include <libsolidity/codegen/Compiler.h>
28
#include <libsolidity/codegen/CompilerUtils.h>
29
#include <libsolidity/interface/Version.h>
30
31
#include <libyul/AST.h>
32
#include <libyul/AsmParser.h>
33
#include <libyul/AsmPrinter.h>
34
#include <libyul/AsmAnalysis.h>
35
#include <libyul/AsmAnalysisInfo.h>
36
#include <libyul/backends/evm/AsmCodeGen.h>
37
#include <libyul/backends/evm/EVMDialect.h>
38
#include <libyul/backends/evm/EVMMetrics.h>
39
#include <libyul/optimiser/Suite.h>
40
#include <libyul/Object.h>
41
#include <libyul/YulString.h>
42
#include <libyul/Utilities.h>
43
44
#include <libsolutil/Whiskers.h>
45
#include <libsolutil/FunctionSelector.h>
46
#include <libsolutil/StackTooDeepString.h>
47
48
#include <liblangutil/ErrorReporter.h>
49
#include <liblangutil/Scanner.h>
50
#include <liblangutil/SourceReferenceFormatter.h>
51
52
#include <utility>
53
54
// Change to "define" to output all intermediate code
55
#undef SOL_OUTPUT_ASM
56
57
58
using namespace std;
59
using namespace solidity;
60
using namespace solidity::util;
61
using namespace solidity::evmasm;
62
using namespace solidity::frontend;
63
using namespace solidity::langutil;
64
65
void CompilerContext::addStateVariable(
66
  VariableDeclaration const& _declaration,
67
  u256 const& _storageOffset,
68
  unsigned _byteOffset
69
)
70
8.19k
{
71
8.19k
  m_stateVariables[&_declaration] = make_pair(_storageOffset, _byteOffset);
72
8.19k
}
73
74
void CompilerContext::addImmutable(VariableDeclaration const& _variable)
75
374
{
76
374
  solAssert(_variable.immutable(), "Attempted to register a non-immutable variable as immutable.");
77
374
  solUnimplementedAssert(_variable.annotation().type->isValueType(), "Only immutable variables of value type are supported.");
78
374
  solAssert(m_runtimeContext, "Attempted to register an immutable variable for runtime code generation.");
79
374
  m_immutableVariables[&_variable] = CompilerUtils::generalPurposeMemoryStart + *m_reservedMemory;
80
374
  solAssert(_variable.annotation().type->memoryHeadSize() == 32, "Memory writes might overlap.");
81
374
  *m_reservedMemory += _variable.annotation().type->memoryHeadSize();
82
374
}
83
84
size_t CompilerContext::immutableMemoryOffset(VariableDeclaration const& _variable) const
85
764
{
86
764
  solAssert(m_immutableVariables.count(&_variable), "Memory offset of unknown immutable queried.");
87
764
  solAssert(m_runtimeContext, "Attempted to fetch the memory offset of an immutable variable during runtime code generation.");
88
764
  return m_immutableVariables.at(&_variable);
89
764
}
90
91
vector<string> CompilerContext::immutableVariableSlotNames(VariableDeclaration const& _variable)
92
454
{
93
454
  string baseName = to_string(_variable.id());
94
454
  solAssert(_variable.annotation().type->sizeOnStack() > 0, "");
95
454
  if (_variable.annotation().type->sizeOnStack() == 1)
96
454
    return {baseName};
97
0
  vector<string> names;
98
0
  auto collectSlotNames = [&](string const& _baseName, Type const* type, auto const& _recurse) -> void {
99
0
    for (auto const& [slot, type]: type->stackItems())
100
0
      if (type)
101
0
        _recurse(_baseName + " " + slot, type, _recurse);
102
0
      else
103
0
        names.emplace_back(_baseName);
104
0
  };
105
0
  collectSlotNames(baseName, _variable.annotation().type, collectSlotNames);
106
0
  return names;
107
454
}
108
109
size_t CompilerContext::reservedMemory()
110
19.7k
{
111
19.7k
  solAssert(m_reservedMemory.has_value(), "Reserved memory was used before ");
112
19.7k
  size_t reservedMemory = *m_reservedMemory;
113
19.7k
  m_reservedMemory = std::nullopt;
114
19.7k
  return reservedMemory;
115
19.7k
}
116
117
void CompilerContext::startFunction(Declaration const& _function)
118
12.5k
{
119
12.5k
  m_functionCompilationQueue.startFunction(_function);
120
12.5k
  *this << functionEntryLabel(_function);
121
12.5k
}
122
123
void CompilerContext::callLowLevelFunction(
124
  string const& _name,
125
  unsigned _inArgs,
126
  unsigned _outArgs,
127
  function<void(CompilerContext&)> const& _generator
128
)
129
805
{
130
805
  evmasm::AssemblyItem retTag = pushNewTag();
131
805
  CompilerUtils(*this).moveIntoStack(_inArgs);
132
133
805
  *this << lowLevelFunctionTag(_name, _inArgs, _outArgs, _generator);
134
135
805
  appendJump(evmasm::AssemblyItem::JumpType::IntoFunction);
136
805
  adjustStackOffset(static_cast<int>(_outArgs) - 1 - static_cast<int>(_inArgs));
137
805
  *this << retTag.tag();
138
805
}
139
140
void CompilerContext::callYulFunction(
141
  string const& _name,
142
  unsigned _inArgs,
143
  unsigned _outArgs
144
)
145
37.0k
{
146
37.0k
  m_externallyUsedYulFunctions.insert(_name);
147
37.0k
  auto const retTag = pushNewTag();
148
37.0k
  CompilerUtils(*this).moveIntoStack(_inArgs);
149
37.0k
  appendJumpTo(namedTag(_name, _inArgs, _outArgs, {}), evmasm::AssemblyItem::JumpType::IntoFunction);
150
37.0k
  adjustStackOffset(static_cast<int>(_outArgs) - 1 - static_cast<int>(_inArgs));
151
37.0k
  *this << retTag.tag();
152
37.0k
}
153
154
evmasm::AssemblyItem CompilerContext::lowLevelFunctionTag(
155
  string const& _name,
156
  unsigned _inArgs,
157
  unsigned _outArgs,
158
  function<void(CompilerContext&)> const& _generator
159
)
160
873
{
161
873
  auto it = m_lowLevelFunctions.find(_name);
162
873
  if (it == m_lowLevelFunctions.end())
163
762
  {
164
762
    evmasm::AssemblyItem tag = newTag().pushTag();
165
762
    m_lowLevelFunctions.insert(make_pair(_name, tag));
166
762
    m_lowLevelFunctionGenerationQueue.push(make_tuple(_name, _inArgs, _outArgs, _generator));
167
762
    return tag;
168
762
  }
169
111
  else
170
111
    return it->second;
171
873
}
172
173
void CompilerContext::appendMissingLowLevelFunctions()
174
19.8k
{
175
20.6k
  while (!m_lowLevelFunctionGenerationQueue.empty())
176
761
  {
177
761
    string name;
178
761
    unsigned inArgs;
179
761
    unsigned outArgs;
180
761
    function<void(CompilerContext&)> generator;
181
761
    tie(name, inArgs, outArgs, generator) = m_lowLevelFunctionGenerationQueue.front();
182
761
    m_lowLevelFunctionGenerationQueue.pop();
183
184
761
    setStackOffset(static_cast<int>(inArgs) + 1);
185
761
    *this << m_lowLevelFunctions.at(name).tag();
186
761
    generator(*this);
187
761
    CompilerUtils(*this).moveToStackTop(outArgs);
188
761
    appendJump(evmasm::AssemblyItem::JumpType::OutOfFunction);
189
761
    solAssert(stackHeight() == outArgs, "Invalid stack height in low-level function " + name + ".");
190
761
  }
191
19.8k
}
192
193
void CompilerContext::appendYulUtilityFunctions(OptimiserSettings const& _optimiserSettings)
194
19.8k
{
195
19.8k
  solAssert(!m_appendYulUtilityFunctionsRan, "requestedYulFunctions called more than once.");
196
19.8k
  m_appendYulUtilityFunctionsRan = true;
197
198
19.8k
  string code = m_yulFunctionCollector.requestedFunctions();
199
19.8k
  if (!code.empty())
200
6.66k
  {
201
6.66k
    appendInlineAssembly(
202
6.66k
      yul::reindent("{\n" + move(code) + "\n}"),
203
6.66k
      {},
204
6.66k
      m_externallyUsedYulFunctions,
205
6.66k
      true,
206
6.66k
      _optimiserSettings,
207
6.66k
      yulUtilityFileName()
208
6.66k
    );
209
6.66k
    solAssert(!m_generatedYulUtilityCode.empty(), "");
210
6.66k
  }
211
19.8k
}
212
213
void CompilerContext::addVariable(
214
  VariableDeclaration const& _declaration,
215
  unsigned _offsetToCurrent
216
)
217
20.8k
{
218
20.8k
  solAssert(m_asm->deposit() >= 0 && unsigned(m_asm->deposit()) >= _offsetToCurrent, "");
219
20.8k
  unsigned sizeOnStack = _declaration.annotation().type->sizeOnStack();
220
  // Variables should not have stack size other than [1, 2],
221
  // but that might change when new types are introduced.
222
20.8k
  solAssert(sizeOnStack == 1 || sizeOnStack == 2, "");
223
20.8k
  m_localVariables[&_declaration].push_back(unsigned(m_asm->deposit()) - _offsetToCurrent);
224
20.8k
}
225
226
void CompilerContext::removeVariable(Declaration const& _declaration)
227
20.7k
{
228
20.7k
  solAssert(m_localVariables.count(&_declaration) && !m_localVariables[&_declaration].empty(), "");
229
20.7k
  m_localVariables[&_declaration].pop_back();
230
20.7k
  if (m_localVariables[&_declaration].empty())
231
20.7k
    m_localVariables.erase(&_declaration);
232
20.7k
}
233
234
void CompilerContext::removeVariablesAboveStackHeight(unsigned _stackHeight)
235
13.8k
{
236
13.8k
  vector<Declaration const*> toRemove;
237
13.8k
  for (auto _var: m_localVariables)
238
27.7k
  {
239
27.7k
    solAssert(!_var.second.empty(), "");
240
27.7k
    solAssert(_var.second.back() <= stackHeight(), "");
241
27.7k
    if (_var.second.back() >= _stackHeight)
242
3.30k
      toRemove.push_back(_var.first);
243
27.7k
  }
244
13.8k
  for (auto _var: toRemove)
245
3.30k
    removeVariable(*_var);
246
13.8k
}
247
248
unsigned CompilerContext::numberOfLocalVariables() const
249
9.89k
{
250
9.89k
  return static_cast<unsigned>(m_localVariables.size());
251
9.89k
}
252
253
shared_ptr<evmasm::Assembly> CompilerContext::compiledContract(ContractDefinition const& _contract) const
254
139
{
255
139
  auto ret = m_otherCompilers.find(&_contract);
256
139
  solAssert(ret != m_otherCompilers.end(), "Compiled contract not found.");
257
139
  return ret->second->assemblyPtr();
258
139
}
259
260
shared_ptr<evmasm::Assembly> CompilerContext::compiledContractRuntime(ContractDefinition const& _contract) const
261
4
{
262
4
  auto ret = m_otherCompilers.find(&_contract);
263
4
  solAssert(ret != m_otherCompilers.end(), "Compiled contract not found.");
264
4
  return ret->second->runtimeAssemblyPtr();
265
4
}
266
267
bool CompilerContext::isLocalVariable(Declaration const* _declaration) const
268
21.8k
{
269
21.8k
  return !!m_localVariables.count(_declaration);
270
21.8k
}
271
272
evmasm::AssemblyItem CompilerContext::functionEntryLabel(Declaration const& _declaration)
273
23.8k
{
274
23.8k
  return m_functionCompilationQueue.entryLabel(_declaration, *this);
275
23.8k
}
276
277
evmasm::AssemblyItem CompilerContext::functionEntryLabelIfExists(Declaration const& _declaration) const
278
0
{
279
0
  return m_functionCompilationQueue.entryLabelIfExists(_declaration);
280
0
}
281
282
FunctionDefinition const& CompilerContext::superFunction(FunctionDefinition const& _function, ContractDefinition const& _base)
283
43
{
284
43
  solAssert(m_mostDerivedContract, "No most derived contract set.");
285
43
  ContractDefinition const* super = _base.superContract(mostDerivedContract());
286
43
  solAssert(super, "Super contract not available.");
287
288
43
  FunctionDefinition const& resolvedFunction = _function.resolveVirtual(mostDerivedContract(), super);
289
43
  solAssert(resolvedFunction.isImplemented(), "");
290
291
43
  return resolvedFunction;
292
43
}
293
294
ContractDefinition const& CompilerContext::mostDerivedContract() const
295
11.2k
{
296
11.2k
  solAssert(m_mostDerivedContract, "Most derived contract not set.");
297
11.2k
  return *m_mostDerivedContract;
298
11.2k
}
299
300
Declaration const* CompilerContext::nextFunctionToCompile() const
301
41.3k
{
302
41.3k
  return m_functionCompilationQueue.nextFunctionToCompile();
303
41.3k
}
304
305
unsigned CompilerContext::baseStackOffsetOfVariable(Declaration const& _declaration) const
306
22.6k
{
307
22.6k
  auto res = m_localVariables.find(&_declaration);
308
22.6k
  solAssert(res != m_localVariables.end(), "Variable not found on stack.");
309
22.6k
  solAssert(!res->second.empty(), "");
310
22.6k
  return res->second.back();
311
22.6k
}
312
313
unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const
314
25.7k
{
315
25.7k
  return static_cast<unsigned>(m_asm->deposit()) - _baseOffset - 1;
316
25.7k
}
317
318
unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const
319
3.71k
{
320
3.71k
  return static_cast<unsigned>(m_asm->deposit()) - _offset - 1;
321
3.71k
}
322
323
pair<u256, unsigned> CompilerContext::storageLocationOfVariable(Declaration const& _declaration) const
324
6.79k
{
325
6.79k
  auto it = m_stateVariables.find(&_declaration);
326
6.79k
  solAssert(it != m_stateVariables.end(), "Variable not found in storage.");
327
6.79k
  return it->second;
328
6.79k
}
329
330
CompilerContext& CompilerContext::appendJump(evmasm::AssemblyItem::JumpType _jumpType)
331
71.0k
{
332
71.0k
  evmasm::AssemblyItem item(Instruction::JUMP);
333
71.0k
  item.setJumpType(_jumpType);
334
71.0k
  return *this << item;
335
71.0k
}
336
337
CompilerContext& CompilerContext::appendPanic(util::PanicCode _code)
338
12.5k
{
339
12.5k
  callYulFunction(utilFunctions().panicFunction(_code), 0, 0);
340
12.5k
  return *this;
341
12.5k
}
342
343
CompilerContext& CompilerContext::appendConditionalPanic(util::PanicCode _code)
344
11.3k
{
345
11.3k
  *this << Instruction::ISZERO;
346
11.3k
  evmasm::AssemblyItem afterTag = appendConditionalJump();
347
11.3k
  appendPanic(_code);
348
11.3k
  *this << afterTag;
349
11.3k
  return *this;
350
11.3k
}
351
352
CompilerContext& CompilerContext::appendRevert(string const& _message)
353
9.96k
{
354
9.96k
  appendInlineAssembly("{ " + revertReasonIfDebug(_message) + " }");
355
9.96k
  return *this;
356
9.96k
}
357
358
CompilerContext& CompilerContext::appendConditionalRevert(bool _forwardReturnData, string const& _message)
359
18.5k
{
360
18.5k
  if (_forwardReturnData && m_evmVersion.supportsReturndata())
361
816
    appendInlineAssembly(R"({
362
816
      if condition {
363
816
        returndatacopy(0, 0, returndatasize())
364
816
        revert(0, returndatasize())
365
816
      }
366
816
    })", {"condition"});
367
17.7k
  else
368
17.7k
    appendInlineAssembly("{ if condition { " + revertReasonIfDebug(_message) + " } }", {"condition"});
369
18.5k
  *this << Instruction::POP;
370
18.5k
  return *this;
371
18.5k
}
372
373
void CompilerContext::resetVisitedNodes(ASTNode const* _node)
374
19.7k
{
375
19.7k
  stack<ASTNode const*> newStack;
376
19.7k
  newStack.push(_node);
377
19.7k
  std::swap(m_visitedNodes, newStack);
378
19.7k
  updateSourceLocation();
379
19.7k
}
380
381
void CompilerContext::appendInlineAssembly(
382
  string const& _assembly,
383
  vector<string> const& _localVariables,
384
  set<string> const& _externallyUsedFunctions,
385
  bool _system,
386
  OptimiserSettings const& _optimiserSettings,
387
  string _sourceName
388
)
389
38.6k
{
390
38.6k
  unsigned startStackHeight = stackHeight();
391
392
38.6k
  set<yul::YulString> externallyUsedIdentifiers;
393
38.6k
  for (auto const& fun: _externallyUsedFunctions)
394
20.0k
    externallyUsedIdentifiers.insert(yul::YulString(fun));
395
38.6k
  for (auto const& var: _localVariables)
396
25.4k
    externallyUsedIdentifiers.insert(yul::YulString(var));
397
398
38.6k
  yul::ExternalIdentifierAccess identifierAccess;
399
38.6k
  identifierAccess.resolve = [&](
400
38.6k
    yul::Identifier const& _identifier,
401
38.6k
    yul::IdentifierContext,
402
38.6k
    bool _insideFunction
403
38.6k
  ) -> bool
404
572k
  {
405
572k
    if (_insideFunction)
406
535k
      return false;
407
36.8k
    return util::contains(_localVariables, _identifier.name.str());
408
572k
  };
409
38.6k
  identifierAccess.generateCode = [&](
410
38.6k
    yul::Identifier const& _identifier,
411
38.6k
    yul::IdentifierContext _context,
412
38.6k
    yul::AbstractAssembly& _assembly
413
38.6k
  )
414
38.6k
  {
415
29.2k
    solAssert(_context == yul::IdentifierContext::RValue || _context == yul::IdentifierContext::LValue, "");
416
29.2k
    auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
417
29.2k
    solAssert(it != _localVariables.end(), "");
418
29.2k
    auto stackDepth = static_cast<size_t>(distance(it, _localVariables.end()));
419
29.2k
    size_t stackDiff = static_cast<size_t>(_assembly.stackHeight()) - startStackHeight + stackDepth;
420
29.2k
    if (_context == yul::IdentifierContext::LValue)
421
1.57k
      stackDiff -= 1;
422
29.2k
    if (stackDiff < 1 || stackDiff > 16)
423
0
      BOOST_THROW_EXCEPTION(
424
29.2k
        StackTooDeepError() <<
425
29.2k
        errinfo_sourceLocation(nativeLocationOf(_identifier)) <<
426
29.2k
        util::errinfo_comment(util::stackTooDeepString)
427
29.2k
      );
428
29.2k
    if (_context == yul::IdentifierContext::RValue)
429
27.7k
      _assembly.appendInstruction(dupInstruction(static_cast<unsigned>(stackDiff)));
430
1.57k
    else
431
1.57k
    {
432
1.57k
      _assembly.appendInstruction(swapInstruction(static_cast<unsigned>(stackDiff)));
433
1.57k
      _assembly.appendInstruction(Instruction::POP);
434
1.57k
    }
435
29.2k
  };
436
437
38.6k
  ErrorList errors;
438
38.6k
  ErrorReporter errorReporter(errors);
439
38.6k
  langutil::CharStream charStream(_assembly, _sourceName);
440
38.6k
  yul::EVMDialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(m_evmVersion);
441
38.6k
  optional<langutil::SourceLocation> locationOverride;
442
38.6k
  if (!_system)
443
31.9k
    locationOverride = m_asm->currentSourceLocation();
444
38.6k
  shared_ptr<yul::Block> parserResult =
445
38.6k
    yul::Parser(errorReporter, dialect, std::move(locationOverride))
446
38.6k
    .parse(charStream);
447
#ifdef SOL_OUTPUT_ASM
448
  cout << yul::AsmPrinter(&dialect)(*parserResult) << endl;
449
#endif
450
451
38.6k
  auto reportError = [&](string const& _context)
452
38.6k
  {
453
0
    string message =
454
0
      "Error parsing/analyzing inline assembly block:\n" +
455
0
      _context + "\n"
456
0
      "------------------ Input: -----------------\n" +
457
0
      _assembly + "\n"
458
0
      "------------------ Errors: ----------------\n";
459
0
    for (auto const& error: errorReporter.errors())
460
      // TODO if we have "locationOverride", it will be the wrong char stream,
461
      // but we do not have access to the solidity scanner.
462
0
      message += SourceReferenceFormatter::formatErrorInformation(*error, charStream);
463
0
    message += "-------------------------------------------\n";
464
465
0
    solAssert(false, message);
466
0
  };
467
468
38.6k
  yul::AsmAnalysisInfo analysisInfo;
469
38.6k
  bool analyzerResult = false;
470
38.6k
  if (parserResult)
471
38.6k
    analyzerResult = yul::AsmAnalyzer(
472
38.6k
      analysisInfo,
473
38.6k
      errorReporter,
474
38.6k
      dialect,
475
38.6k
      identifierAccess.resolve
476
38.6k
    ).analyze(*parserResult);
477
38.6k
  if (!parserResult || !errorReporter.errors().empty() || !analyzerResult)
478
0
    reportError("Invalid assembly generated by code generator.");
479
480
  // Several optimizer steps cannot handle externally supplied stack variables,
481
  // so we essentially only optimize the ABI functions.
482
38.6k
  if (_optimiserSettings.runYulOptimiser && _localVariables.empty())
483
1.80k
  {
484
1.80k
    yul::Object obj;
485
1.80k
    obj.code = parserResult;
486
1.80k
    obj.analysisInfo = make_shared<yul::AsmAnalysisInfo>(analysisInfo);
487
488
1.80k
    solAssert(!dialect.providesObjectAccess());
489
1.80k
    optimizeYul(obj, dialect, _optimiserSettings, externallyUsedIdentifiers);
490
491
1.80k
    if (_system)
492
1.80k
    {
493
      // Store as generated sources, but first re-parse to update the source references.
494
1.80k
      solAssert(m_generatedYulUtilityCode.empty(), "");
495
1.80k
      m_generatedYulUtilityCode = yul::AsmPrinter(dialect)(*obj.code);
496
1.80k
      string code = yul::AsmPrinter{dialect}(*obj.code);
497
1.80k
      langutil::CharStream charStream(m_generatedYulUtilityCode, _sourceName);
498
1.80k
      obj.code = yul::Parser(errorReporter, dialect).parse(charStream);
499
1.80k
      *obj.analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(dialect, obj);
500
1.80k
    }
501
502
1.80k
    analysisInfo = std::move(*obj.analysisInfo);
503
1.80k
    parserResult = std::move(obj.code);
504
505
#ifdef SOL_OUTPUT_ASM
506
    cout << "After optimizer:" << endl;
507
    cout << yul::AsmPrinter(&dialect)(*parserResult) << endl;
508
#endif
509
1.80k
  }
510
36.8k
  else if (_system)
511
4.85k
  {
512
    // Store as generated source.
513
4.85k
    solAssert(m_generatedYulUtilityCode.empty(), "");
514
4.85k
    m_generatedYulUtilityCode = _assembly;
515
4.85k
  }
516
517
38.6k
  if (!errorReporter.errors().empty())
518
0
    reportError("Failed to analyze inline assembly block.");
519
520
38.6k
  solAssert(errorReporter.errors().empty(), "Failed to analyze inline assembly block.");
521
38.6k
  yul::CodeGenerator::assemble(
522
38.6k
    *parserResult,
523
38.6k
    analysisInfo,
524
38.6k
    *m_asm,
525
38.6k
    m_evmVersion,
526
38.6k
    identifierAccess.generateCode,
527
38.6k
    _system,
528
38.6k
    _optimiserSettings.optimizeStackAllocation
529
38.6k
  );
530
531
  // Reset the source location to the one of the node (instead of the CODEGEN source location)
532
38.6k
  updateSourceLocation();
533
38.6k
}
534
535
536
void CompilerContext::optimizeYul(yul::Object& _object, yul::EVMDialect const& _dialect, OptimiserSettings const& _optimiserSettings, std::set<yul::YulString> const& _externalIdentifiers)
537
2.19k
{
538
#ifdef SOL_OUTPUT_ASM
539
  cout << yul::AsmPrinter(*dialect)(*_object.code) << endl;
540
#endif
541
542
2.19k
  bool const isCreation = runtimeContext() != nullptr;
543
2.19k
  yul::GasMeter meter(_dialect, isCreation, _optimiserSettings.expectedExecutionsPerDeployment);
544
2.19k
  yul::OptimiserSuite::run(
545
2.19k
    _dialect,
546
2.19k
    &meter,
547
2.19k
    _object,
548
2.19k
    _optimiserSettings.optimizeStackAllocation,
549
2.19k
    _optimiserSettings.yulOptimiserSteps,
550
2.19k
    isCreation? nullopt : make_optional(_optimiserSettings.expectedExecutionsPerDeployment),
551
2.19k
    _externalIdentifiers
552
2.19k
  );
553
554
#ifdef SOL_OUTPUT_ASM
555
  cout << "After optimizer:" << endl;
556
  cout << yul::AsmPrinter(*dialect)(*object.code) << endl;
557
#endif
558
2.19k
}
559
560
string CompilerContext::revertReasonIfDebug(string const& _message)
561
28.5k
{
562
28.5k
  return YulUtilFunctions::revertReasonIfDebugBody(
563
28.5k
    m_revertStrings,
564
28.5k
    "mload(" + to_string(CompilerUtils::freeMemoryPointer) + ")",
565
28.5k
    _message
566
28.5k
  );
567
28.5k
}
568
569
void CompilerContext::updateSourceLocation()
570
484k
{
571
484k
  m_asm->setSourceLocation(m_visitedNodes.empty() ? SourceLocation() : m_visitedNodes.top()->location());
572
484k
}
573
574
evmasm::Assembly::OptimiserSettings CompilerContext::translateOptimiserSettings(OptimiserSettings const& _settings)
575
9.89k
{
576
  // Constructing it this way so that we notice changes in the fields.
577
9.89k
  evmasm::Assembly::OptimiserSettings asmSettings{false,  false, false, false, false, false, m_evmVersion, 0};
578
9.89k
  asmSettings.runInliner = _settings.runInliner;
579
9.89k
  asmSettings.runJumpdestRemover = _settings.runJumpdestRemover;
580
9.89k
  asmSettings.runPeephole = _settings.runPeephole;
581
9.89k
  asmSettings.runDeduplicate = _settings.runDeduplicate;
582
9.89k
  asmSettings.runCSE = _settings.runCSE;
583
9.89k
  asmSettings.runConstantOptimiser = _settings.runConstantOptimiser;
584
9.89k
  asmSettings.expectedExecutionsPerDeployment = _settings.expectedExecutionsPerDeployment;
585
9.89k
  asmSettings.evmVersion = m_evmVersion;
586
9.89k
  return asmSettings;
587
9.89k
}
588
589
evmasm::AssemblyItem CompilerContext::FunctionCompilationQueue::entryLabel(
590
  Declaration const& _declaration,
591
  CompilerContext& _context
592
)
593
23.8k
{
594
23.8k
  auto res = m_entryLabels.find(&_declaration);
595
23.8k
  if (res == m_entryLabels.end())
596
12.5k
  {
597
12.5k
    size_t params = 0;
598
12.5k
    size_t returns = 0;
599
12.5k
    if (auto const* function = dynamic_cast<FunctionDefinition const*>(&_declaration))
600
11.2k
    {
601
11.2k
      FunctionType functionType(*function, FunctionType::Kind::Internal);
602
11.2k
      params = CompilerUtils::sizeOnStack(functionType.parameterTypes());
603
11.2k
      returns = CompilerUtils::sizeOnStack(functionType.returnParameterTypes());
604
11.2k
    }
605
606
    // some name that cannot clash with yul function names.
607
12.5k
    string labelName = "@" + _declaration.name() + "_" + to_string(_declaration.id());
608
12.5k
    evmasm::AssemblyItem tag = _context.namedTag(
609
12.5k
      labelName,
610
12.5k
      params,
611
12.5k
      returns,
612
12.5k
      _declaration.id()
613
12.5k
    );
614
12.5k
    m_entryLabels.insert(make_pair(&_declaration, tag));
615
12.5k
    m_functionsToCompile.push(&_declaration);
616
12.5k
    return tag.tag();
617
12.5k
  }
618
11.3k
  else
619
11.3k
    return res->second.tag();
620
621
23.8k
}
622
623
evmasm::AssemblyItem CompilerContext::FunctionCompilationQueue::entryLabelIfExists(Declaration const& _declaration) const
624
0
{
625
0
  auto res = m_entryLabels.find(&_declaration);
626
0
  return res == m_entryLabels.end() ? evmasm::AssemblyItem(evmasm::UndefinedItem) : res->second.tag();
627
0
}
628
629
Declaration const* CompilerContext::FunctionCompilationQueue::nextFunctionToCompile() const
630
41.3k
{
631
43.1k
  while (!m_functionsToCompile.empty())
632
16.0k
  {
633
16.0k
    if (m_alreadyCompiledFunctions.count(m_functionsToCompile.front()))
634
1.71k
      m_functionsToCompile.pop();
635
14.3k
    else
636
14.3k
      return m_functionsToCompile.front();
637
16.0k
  }
638
27.0k
  return nullptr;
639
41.3k
}
640
641
void CompilerContext::FunctionCompilationQueue::startFunction(Declaration const& _function)
642
12.5k
{
643
12.5k
  if (!m_functionsToCompile.empty() && m_functionsToCompile.front() == &_function)
644
10.7k
    m_functionsToCompile.pop();
645
12.5k
  m_alreadyCompiledFunctions.insert(&_function);
646
12.5k
}