mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into breaking
This commit is contained in:
commit
6b88e470ff
@ -9,16 +9,16 @@ version: 2.1
|
|||||||
parameters:
|
parameters:
|
||||||
ubuntu-2004-docker-image:
|
ubuntu-2004-docker-image:
|
||||||
type: string
|
type: string
|
||||||
# solbuildpackpusher/solidity-buildpack-deps:ubuntu2004-10
|
# solbuildpackpusher/solidity-buildpack-deps:ubuntu2004-11
|
||||||
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:e61939751ff9777307857361f712b581bfc8a8aaae75fab7b50febc764710587"
|
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:9928dc357829e475e8729c62a1c2d495dbb41cb9fe4c4b115a5568be8e1ed69e"
|
||||||
ubuntu-2004-clang-docker-image:
|
ubuntu-2004-clang-docker-image:
|
||||||
type: string
|
type: string
|
||||||
# solbuildpackpusher/solidity-buildpack-deps:ubuntu2004.clang-10
|
# solbuildpackpusher/solidity-buildpack-deps:ubuntu2004.clang-11
|
||||||
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:0de8c68f084120b2a165406e3a0c2aab58b32f5b7182c2322245245f1d243b8d"
|
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:72fb9574c90e8ef908dce4c9dd9788ff4de708b504d970cd9146eed8911c313e"
|
||||||
ubuntu-1604-clang-ossfuzz-docker-image:
|
ubuntu-1604-clang-ossfuzz-docker-image:
|
||||||
type: string
|
type: string
|
||||||
# solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-15
|
# solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-16
|
||||||
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:87f1a57586eec194a6217ab624efc69d3d9af2f7ac8ca36497ad57488c2f08ae"
|
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:fe54d8e5409827d43edb0dc8ad0d9e4232a675050ceb271c873b73e5ee267938"
|
||||||
emscripten-docker-image:
|
emscripten-docker-image:
|
||||||
type: string
|
type: string
|
||||||
# solbuildpackpusher/solidity-buildpack-deps:emscripten-9
|
# solbuildpackpusher/solidity-buildpack-deps:emscripten-9
|
||||||
|
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/docs/style-guide.rst @fulldecent
|
@ -13,15 +13,15 @@ Breaking changes:
|
|||||||
### 0.8.13 (unreleased)
|
### 0.8.13 (unreleased)
|
||||||
|
|
||||||
Language Features:
|
Language Features:
|
||||||
|
* General: Allow annotating inline assembly as memory-safe to allow optimizations and stack limit evasion that rely on respecting Solidity's memory model.
|
||||||
|
|
||||||
|
|
||||||
Compiler Features:
|
Compiler Features:
|
||||||
|
* JSON-AST: Added selector field for errors and events.
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 0.8.12 (2022-02-16)
|
### 0.8.12 (2022-02-16)
|
||||||
|
|
||||||
Language Features:
|
Language Features:
|
||||||
|
@ -26,7 +26,11 @@
|
|||||||
- [ ] Click the `PUBLISH RELEASE` button on the release page, creating the tag.
|
- [ ] Click the `PUBLISH RELEASE` button on the release page, creating the tag.
|
||||||
- [ ] Wait for the CI runs on the tag itself.
|
- [ ] Wait for the CI runs on the tag itself.
|
||||||
|
|
||||||
### Download Binaries
|
### Upload Release Artifacts
|
||||||
|
- [ ] Switch to the tag that archives have to be created for.
|
||||||
|
- [ ] Create the ``prerelease.txt`` file: (``echo -n > prerelease.txt``).
|
||||||
|
- [ ] Run ``scripts/create_source_tarball.sh`` while being on the tag to create the source tarball. This will create the tarball in a directory called ``upload``.
|
||||||
|
- [ ] Take the tarball from the upload directory (its name should be ``solidity_x.x.x.tar.gz``, otherwise ``prerelease.txt`` was missing in the step before) and upload the source tarball to the release page.
|
||||||
- [ ] Take the ``solc.exe`` binary from the ``b_win_release`` run of the released commit in circle-ci and add it to the release page as ``solc-windows.exe``.
|
- [ ] Take the ``solc.exe`` binary from the ``b_win_release`` run of the released commit in circle-ci and add it to the release page as ``solc-windows.exe``.
|
||||||
- [ ] Take the ``solc`` binary from the ``b_osx`` run of the released commit in circle-ci and add it to the release page as ``solc-macos``.
|
- [ ] Take the ``solc`` binary from the ``b_osx`` run of the released commit in circle-ci and add it to the release page as ``solc-macos``.
|
||||||
- [ ] Take the ``solc`` binary from the ``b_ubu_static`` run of the released commit in circle-ci and add it to the release page as ``solc-static-linux``.
|
- [ ] Take the ``solc`` binary from the ``b_ubu_static`` run of the released commit in circle-ci and add it to the release page as ``solc-static-linux``.
|
||||||
|
@ -89,8 +89,8 @@ For most of the topics the compiler will provide suggestions.
|
|||||||
|
|
||||||
* Explicit data location for all variables of struct, array or mapping types is
|
* Explicit data location for all variables of struct, array or mapping types is
|
||||||
now mandatory. This is also applied to function parameters and return
|
now mandatory. This is also applied to function parameters and return
|
||||||
variables. For example, change ``uint[] x = m_x`` to ``uint[] storage x =
|
variables. For example, change ``uint[] x = z`` to ``uint[] storage x =
|
||||||
m_x``, and ``function f(uint[][] x)`` to ``function f(uint[][] memory x)``
|
z``, and ``function f(uint[][] x)`` to ``function f(uint[][] memory x)``
|
||||||
where ``memory`` is the data location and might be replaced by ``storage`` or
|
where ``memory`` is the data location and might be replaced by ``storage`` or
|
||||||
``calldata`` accordingly. Note that ``external`` functions require
|
``calldata`` accordingly. Note that ``external`` functions require
|
||||||
parameters with a data location of ``calldata``.
|
parameters with a data location of ``calldata``.
|
||||||
@ -483,7 +483,7 @@ New version:
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
using address_make_payable for address;
|
using AddressMakePayable for address;
|
||||||
// Data location for 'arr' must be specified
|
// Data location for 'arr' must be specified
|
||||||
function g(uint[] memory /* arr */, bytes8 x, OtherContract otherContract, address unknownContract) public payable {
|
function g(uint[] memory /* arr */, bytes8 x, OtherContract otherContract, address unknownContract) public payable {
|
||||||
// 'otherContract.transfer' is not provided.
|
// 'otherContract.transfer' is not provided.
|
||||||
@ -500,7 +500,7 @@ New version:
|
|||||||
// 'address payable' should be used whenever possible.
|
// 'address payable' should be used whenever possible.
|
||||||
// To increase clarity, we suggest the use of a library for
|
// To increase clarity, we suggest the use of a library for
|
||||||
// the conversion (provided after the contract in this example).
|
// the conversion (provided after the contract in this example).
|
||||||
address payable addr = unknownContract.make_payable();
|
address payable addr = unknownContract.makePayable();
|
||||||
require(addr.send(1 ether));
|
require(addr.send(1 ether));
|
||||||
|
|
||||||
// Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
|
// Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
|
||||||
@ -516,8 +516,8 @@ New version:
|
|||||||
|
|
||||||
// We can define a library for explicitly converting ``address``
|
// We can define a library for explicitly converting ``address``
|
||||||
// to ``address payable`` as a workaround.
|
// to ``address payable`` as a workaround.
|
||||||
library address_make_payable {
|
library AddressMakePayable {
|
||||||
function make_payable(address x) internal pure returns (address payable) {
|
function makePayable(address x) internal pure returns (address payable) {
|
||||||
return address(uint160(x));
|
return address(uint160(x));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,19 +45,19 @@ Solidity language without a compiler change.
|
|||||||
pragma solidity >=0.4.16 <0.9.0;
|
pragma solidity >=0.4.16 <0.9.0;
|
||||||
|
|
||||||
library GetCode {
|
library GetCode {
|
||||||
function at(address _addr) public view returns (bytes memory o_code) {
|
function at(address _addr) public view returns (bytes memory code) {
|
||||||
assembly {
|
assembly {
|
||||||
// retrieve the size of the code, this needs assembly
|
// retrieve the size of the code, this needs assembly
|
||||||
let size := extcodesize(_addr)
|
let size := extcodesize(_addr)
|
||||||
// allocate output byte array - this could also be done without assembly
|
// allocate output byte array - this could also be done without assembly
|
||||||
// by using o_code = new bytes(size)
|
// by using code = new bytes(size)
|
||||||
o_code := mload(0x40)
|
code := mload(0x40)
|
||||||
// new "memory end" including padding
|
// new "memory end" including padding
|
||||||
mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
|
mstore(0x40, add(code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
|
||||||
// store length in memory
|
// store length in memory
|
||||||
mstore(o_code, size)
|
mstore(code, size)
|
||||||
// actually retrieve the code, this needs assembly
|
// actually retrieve the code, this needs assembly
|
||||||
extcodecopy(_addr, add(o_code, 0x20), 0, size)
|
extcodecopy(_addr, add(code, 0x20), 0, size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,7 +139,7 @@ the variable will not point beyond ``calldatasize()`` is performed.
|
|||||||
For external function pointers the address and the function selector can be
|
For external function pointers the address and the function selector can be
|
||||||
accessed using ``x.address`` and ``x.selector``.
|
accessed using ``x.address`` and ``x.selector``.
|
||||||
The selector consists of four right-aligned bytes.
|
The selector consists of four right-aligned bytes.
|
||||||
Both values are can be assigned to. For example:
|
Both values can be assigned to. For example:
|
||||||
|
|
||||||
.. code-block:: solidity
|
.. code-block:: solidity
|
||||||
:force:
|
:force:
|
||||||
@ -228,6 +228,11 @@ of their block is reached.
|
|||||||
Conventions in Solidity
|
Conventions in Solidity
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
|
.. _assembly-typed-variables:
|
||||||
|
|
||||||
|
Values of Typed Variables
|
||||||
|
=========================
|
||||||
|
|
||||||
In contrast to EVM assembly, Solidity has types which are narrower than 256 bits,
|
In contrast to EVM assembly, Solidity has types which are narrower than 256 bits,
|
||||||
e.g. ``uint24``. For efficiency, most arithmetic operations ignore the fact that
|
e.g. ``uint24``. For efficiency, most arithmetic operations ignore the fact that
|
||||||
types can be shorter than 256
|
types can be shorter than 256
|
||||||
@ -237,6 +242,11 @@ This means that if you access such a variable
|
|||||||
from within inline assembly, you might have to manually clean the higher-order bits
|
from within inline assembly, you might have to manually clean the higher-order bits
|
||||||
first.
|
first.
|
||||||
|
|
||||||
|
.. _assembly-memory-management:
|
||||||
|
|
||||||
|
Memory Management
|
||||||
|
=================
|
||||||
|
|
||||||
Solidity manages memory in the following way. There is a "free memory pointer"
|
Solidity manages memory in the following way. There is a "free memory pointer"
|
||||||
at position ``0x40`` in memory. If you want to allocate memory, use the memory
|
at position ``0x40`` in memory. If you want to allocate memory, use the memory
|
||||||
starting from where this pointer points at and update it.
|
starting from where this pointer points at and update it.
|
||||||
@ -268,3 +278,99 @@ first slot of the array and followed by the array elements.
|
|||||||
Statically-sized memory arrays do not have a length field, but it might be added later
|
Statically-sized memory arrays do not have a length field, but it might be added later
|
||||||
to allow better convertibility between statically- and dynamically-sized arrays, so
|
to allow better convertibility between statically- and dynamically-sized arrays, so
|
||||||
do not rely on this.
|
do not rely on this.
|
||||||
|
|
||||||
|
Memory Safety
|
||||||
|
=============
|
||||||
|
|
||||||
|
Without the use of inline assembly, the compiler can rely on memory to remain in a well-defined
|
||||||
|
state at all times. This is especially relevant for :ref:`the new code generation pipeline via Yul IR <ir-breaking-changes>`:
|
||||||
|
this code generation path can move local variables from stack to memory to avoid stack-too-deep errors and
|
||||||
|
perform additional memory optimizations, if it can rely on certain assumptions about memory use.
|
||||||
|
|
||||||
|
While we recommend to always respect Solidity's memory model, inline assembly allows you to use memory
|
||||||
|
in an incompatible way. Therefore, moving stack variables to memory and additional memory optimizations are,
|
||||||
|
by default, disabled in the presence of any inline assembly block that contains a memory operation or assigns
|
||||||
|
to solidity variables in memory.
|
||||||
|
|
||||||
|
However, you can specifically annotate an assembly block to indicate that it in fact respects Solidity's memory
|
||||||
|
model as follows:
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
|
||||||
|
assembly ("memory-safe") {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
In particular, a memory-safe assembly block may only access the following memory ranges:
|
||||||
|
|
||||||
|
- Memory allocated by yourself using a mechanism like the ``allocate`` function described above.
|
||||||
|
- Memory allocated by Solidity, e.g. memory within the bounds of a memory array you reference.
|
||||||
|
- The scratch space between memory offset 0 and 64 mentioned above.
|
||||||
|
- Temporary memory that is located *after* the value of the free memory pointer at the beginning of the assembly block,
|
||||||
|
i.e. memory that is "allocated" at the free memory pointer without updating the free memory pointer.
|
||||||
|
|
||||||
|
Furthermore, if the assembly block assigns to Solidity variables in memory, you need to assure that accesses to
|
||||||
|
the Solidity variables only access these memory ranges.
|
||||||
|
|
||||||
|
Since this is mainly about the optimizer, these restrictions still need to be followed, even if the assembly block
|
||||||
|
reverts or terminates. As an example, the following assembly snippet is not memory safe:
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
|
||||||
|
assembly {
|
||||||
|
returndatacopy(0, 0, returndatasize())
|
||||||
|
revert(0, returndatasize())
|
||||||
|
}
|
||||||
|
|
||||||
|
But the following is:
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
|
||||||
|
assembly ("memory-safe") {
|
||||||
|
let p := mload(0x40)
|
||||||
|
returndatacopy(p, 0, returndatasize())
|
||||||
|
revert(p, returndatasize())
|
||||||
|
}
|
||||||
|
|
||||||
|
Note that you do not need to update the free memory pointer if there is no following allocation,
|
||||||
|
but you can only use memory starting from the current offset given by the free memory pointer.
|
||||||
|
|
||||||
|
If the memory operations use a length of zero, it is also fine to just use any offset (not only if it falls into the scratch space):
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
|
||||||
|
assembly ("memory-safe") {
|
||||||
|
revert(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
Note that not only memory operations in inline assembly itself can be memory-unsafe, but also assignments to
|
||||||
|
solidity variables of reference type in memory. For example the following is not memory-safe:
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
|
||||||
|
bytes memory x;
|
||||||
|
assembly {
|
||||||
|
x := 0x40
|
||||||
|
}
|
||||||
|
x[0x20] = 0x42;
|
||||||
|
|
||||||
|
Inline assembly that neither involves any operations that access memory nor assigns to any solidity variables
|
||||||
|
in memory is automatically considered memory-safe and does not need to be annotated.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
It is your responsibility to make sure that the assembly actually satisfies the memory model. If you annotate
|
||||||
|
an assembly block as memory-safe, but violate one of the memory assumptions, this **will** lead to incorrect and
|
||||||
|
undefined behaviour that cannot easily be discovered by testing.
|
||||||
|
|
||||||
|
In case you are developing a library that is meant to be compatible across multiple versions
|
||||||
|
of solidity, you can use a special comment to annotate an assembly block as memory-safe:
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
|
||||||
|
/// @solidity memory-safe-assembly
|
||||||
|
assembly {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
Note that we will disallow the annotation via comment in a future breaking release, so if you are not concerned with
|
||||||
|
backwards-compatibility with older compiler versions, prefer using the dialect string.
|
||||||
|
@ -102,10 +102,10 @@ two integers passed as function parameters, then you use something like:
|
|||||||
function arithmetic(uint _a, uint _b)
|
function arithmetic(uint _a, uint _b)
|
||||||
public
|
public
|
||||||
pure
|
pure
|
||||||
returns (uint o_sum, uint o_product)
|
returns (uint sum, uint product)
|
||||||
{
|
{
|
||||||
o_sum = _a + _b;
|
sum = _a + _b;
|
||||||
o_product = _a * _b;
|
product = _a * _b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +129,7 @@ statement:
|
|||||||
function arithmetic(uint _a, uint _b)
|
function arithmetic(uint _a, uint _b)
|
||||||
public
|
public
|
||||||
pure
|
pure
|
||||||
returns (uint o_sum, uint o_product)
|
returns (uint sum, uint product)
|
||||||
{
|
{
|
||||||
return (_a + _b, _a * _b);
|
return (_a + _b, _a * _b);
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ It is also possible to extend elementary types in that way:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Note that all external library calls are actual EVM function calls. This means that
|
Note that all external library calls are actual EVM function calls. This means that
|
||||||
if you pass memory or value types, a copy will be performed, even of the
|
if you pass memory or value types, a copy will be performed, even in case of the
|
||||||
``self`` variable. The only situation where no copy will be performed
|
``self`` variable. The only situation where no copy will be performed
|
||||||
is when storage reference variables are used or when internal library
|
is when storage reference variables are used or when internal library
|
||||||
functions are called.
|
functions are called.
|
||||||
|
@ -251,6 +251,12 @@ mode AssemblyBlockMode;
|
|||||||
AssemblyDialect: '"evmasm"';
|
AssemblyDialect: '"evmasm"';
|
||||||
AssemblyLBrace: '{' -> popMode, pushMode(YulMode);
|
AssemblyLBrace: '{' -> popMode, pushMode(YulMode);
|
||||||
|
|
||||||
|
AssemblyFlagString: '"' DoubleQuotedStringCharacter+ '"';
|
||||||
|
|
||||||
|
AssemblyBlockLParen: '(';
|
||||||
|
AssemblyBlockRParen: ')';
|
||||||
|
AssemblyBlockComma: ',';
|
||||||
|
|
||||||
AssemblyBlockWS: [ \t\r\n\u000C]+ -> skip ;
|
AssemblyBlockWS: [ \t\r\n\u000C]+ -> skip ;
|
||||||
AssemblyBlockCOMMENT: '/*' .*? '*/' -> channel(HIDDEN) ;
|
AssemblyBlockCOMMENT: '/*' .*? '*/' -> channel(HIDDEN) ;
|
||||||
AssemblyBlockLINE_COMMENT: '//' ~[\r\n]* -> channel(HIDDEN) ;
|
AssemblyBlockLINE_COMMENT: '//' ~[\r\n]* -> channel(HIDDEN) ;
|
||||||
|
@ -476,7 +476,13 @@ revertStatement: Revert expression callArgumentList Semicolon;
|
|||||||
* The contents of an inline assembly block use a separate scanner/lexer, i.e. the set of keywords and
|
* The contents of an inline assembly block use a separate scanner/lexer, i.e. the set of keywords and
|
||||||
* allowed identifiers is different inside an inline assembly block.
|
* allowed identifiers is different inside an inline assembly block.
|
||||||
*/
|
*/
|
||||||
assemblyStatement: Assembly AssemblyDialect? AssemblyLBrace yulStatement* YulRBrace;
|
assemblyStatement: Assembly AssemblyDialect? assemblyFlags? AssemblyLBrace yulStatement* YulRBrace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assembly flags.
|
||||||
|
* Comma-separated list of double-quoted strings as flags.
|
||||||
|
*/
|
||||||
|
assemblyFlags: AssemblyBlockLParen AssemblyFlagString (AssemblyBlockComma AssemblyFlagString)* AssemblyBlockRParen;
|
||||||
|
|
||||||
//@doc:inline
|
//@doc:inline
|
||||||
variableDeclarationList: variableDeclarations+=variableDeclaration (Comma variableDeclarations+=variableDeclaration)*;
|
variableDeclarationList: variableDeclarations+=variableDeclaration (Comma variableDeclarations+=variableDeclaration)*;
|
||||||
|
@ -10,7 +10,7 @@ A Simple Smart Contract
|
|||||||
|
|
||||||
Let us begin with a basic example that sets the value of a variable and exposes
|
Let us begin with a basic example that sets the value of a variable and exposes
|
||||||
it for other contracts to access. It is fine if you do not understand
|
it for other contracts to access. It is fine if you do not understand
|
||||||
everything right now, we will go into more detail later.
|
everything right now, we will go into more details later.
|
||||||
|
|
||||||
Storage Example
|
Storage Example
|
||||||
===============
|
===============
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
.. index: ir breaking changes
|
.. index: ir breaking changes
|
||||||
|
|
||||||
|
.. _ir-breaking-changes:
|
||||||
|
|
||||||
*********************************
|
*********************************
|
||||||
Solidity IR-based Codegen Changes
|
Solidity IR-based Codegen Changes
|
||||||
*********************************
|
*********************************
|
||||||
|
@ -204,7 +204,7 @@ Yes:
|
|||||||
|
|
||||||
.. code-block:: solidity
|
.. code-block:: solidity
|
||||||
|
|
||||||
thisIsALongNestedMapping[being][set][to_some_value] = someFunction(
|
thisIsALongNestedMapping[being][set][toSomeValue] = someFunction(
|
||||||
argument1,
|
argument1,
|
||||||
argument2,
|
argument2,
|
||||||
argument3,
|
argument3,
|
||||||
@ -215,7 +215,7 @@ No:
|
|||||||
|
|
||||||
.. code-block:: solidity
|
.. code-block:: solidity
|
||||||
|
|
||||||
thisIsALongNestedMapping[being][set][to_some_value] = someFunction(argument1,
|
thisIsALongNestedMapping[being][set][toSomeValue] = someFunction(argument1,
|
||||||
argument2,
|
argument2,
|
||||||
argument3,
|
argument3,
|
||||||
argument4);
|
argument4);
|
||||||
@ -439,15 +439,15 @@ Yes:
|
|||||||
|
|
||||||
x = 1;
|
x = 1;
|
||||||
y = 2;
|
y = 2;
|
||||||
long_variable = 3;
|
longVariable = 3;
|
||||||
|
|
||||||
No:
|
No:
|
||||||
|
|
||||||
.. code-block:: solidity
|
.. code-block:: solidity
|
||||||
|
|
||||||
x = 1;
|
x = 1;
|
||||||
y = 2;
|
y = 2;
|
||||||
long_variable = 3;
|
longVariable = 3;
|
||||||
|
|
||||||
Don't include a whitespace in the receive and fallback functions:
|
Don't include a whitespace in the receive and fallback functions:
|
||||||
|
|
||||||
@ -1092,12 +1092,10 @@ naming styles.
|
|||||||
* ``b`` (single lowercase letter)
|
* ``b`` (single lowercase letter)
|
||||||
* ``B`` (single uppercase letter)
|
* ``B`` (single uppercase letter)
|
||||||
* ``lowercase``
|
* ``lowercase``
|
||||||
* ``lower_case_with_underscores``
|
|
||||||
* ``UPPERCASE``
|
* ``UPPERCASE``
|
||||||
* ``UPPER_CASE_WITH_UNDERSCORES``
|
* ``UPPER_CASE_WITH_UNDERSCORES``
|
||||||
* ``CapitalizedWords`` (or CapWords)
|
* ``CapitalizedWords`` (or CapWords)
|
||||||
* ``mixedCase`` (differs from CapitalizedWords by initial lowercase character!)
|
* ``mixedCase`` (differs from CapitalizedWords by initial lowercase character!)
|
||||||
* ``Capitalized_Words_With_Underscores``
|
|
||||||
|
|
||||||
.. note:: When using initialisms in CapWords, capitalize all the letters of the initialisms. Thus HTTPServerError is better than HttpServerError. When using initialisms in mixedCase, capitalize all the letters of the initialisms, except keep the first one lower case if it is the beginning of the name. Thus xmlHTTPRequest is better than XMLHTTPRequest.
|
.. note:: When using initialisms in CapWords, capitalize all the letters of the initialisms. Thus HTTPServerError is better than HttpServerError. When using initialisms in mixedCase, capitalize all the letters of the initialisms, except keep the first one lower case if it is the beginning of the name. Thus xmlHTTPRequest is better than XMLHTTPRequest.
|
||||||
|
|
||||||
@ -1256,7 +1254,7 @@ Enums, in the style of simple type declarations, should be named using the CapWo
|
|||||||
Avoiding Naming Collisions
|
Avoiding Naming Collisions
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
* ``single_trailing_underscore_``
|
* ``singleTrailingUnderscore_``
|
||||||
|
|
||||||
This convention is suggested when the desired name collides with that of a
|
This convention is suggested when the desired name collides with that of a
|
||||||
built-in or otherwise reserved name.
|
built-in or otherwise reserved name.
|
||||||
|
@ -126,7 +126,7 @@ the ``sum`` function iterates over to sum all the values.
|
|||||||
:force:
|
:force:
|
||||||
|
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
pragma solidity >=0.6.8 <0.9.0;
|
pragma solidity ^0.8.8;
|
||||||
|
|
||||||
struct IndexValue { uint keyIndex; uint value; }
|
struct IndexValue { uint keyIndex; uint value; }
|
||||||
struct KeyFlag { uint key; bool deleted; }
|
struct KeyFlag { uint key; bool deleted; }
|
||||||
@ -137,6 +137,8 @@ the ``sum`` function iterates over to sum all the values.
|
|||||||
uint size;
|
uint size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Iterator is uint;
|
||||||
|
|
||||||
library IterableMapping {
|
library IterableMapping {
|
||||||
function insert(itmap storage self, uint key, uint value) internal returns (bool replaced) {
|
function insert(itmap storage self, uint key, uint value) internal returns (bool replaced) {
|
||||||
uint keyIndex = self.data[key].keyIndex;
|
uint keyIndex = self.data[key].keyIndex;
|
||||||
@ -166,25 +168,29 @@ the ``sum`` function iterates over to sum all the values.
|
|||||||
return self.data[key].keyIndex > 0;
|
return self.data[key].keyIndex > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function iterate_start(itmap storage self) internal view returns (uint keyIndex) {
|
function iterateStart(itmap storage self) internal view returns (Iterator) {
|
||||||
return iterate_next(self, type(uint).max);
|
return iteratorSkipDeleted(self, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function iterate_valid(itmap storage self, uint keyIndex) internal view returns (bool) {
|
function iterateValid(itmap storage self, Iterator iterator) internal view returns (bool) {
|
||||||
return keyIndex < self.keys.length;
|
return Iterator.unwrap(iterator) < self.keys.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
function iterate_next(itmap storage self, uint keyIndex) internal view returns (uint r_keyIndex) {
|
function iterateNext(itmap storage self, Iterator iterator) internal view returns (Iterator) {
|
||||||
keyIndex++;
|
return iteratorSkipDeleted(self, Iterator.unwrap(iterator) + 1);
|
||||||
while (keyIndex < self.keys.length && self.keys[keyIndex].deleted)
|
|
||||||
keyIndex++;
|
|
||||||
return keyIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function iterate_get(itmap storage self, uint keyIndex) internal view returns (uint key, uint value) {
|
function iterateGet(itmap storage self, Iterator iterator) internal view returns (uint key, uint value) {
|
||||||
|
uint keyIndex = Iterator.unwrap(iterator);
|
||||||
key = self.keys[keyIndex].key;
|
key = self.keys[keyIndex].key;
|
||||||
value = self.data[key].value;
|
value = self.data[key].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function iteratorSkipDeleted(itmap storage self, uint keyIndex) private view returns (Iterator) {
|
||||||
|
while (keyIndex < self.keys.length && self.keys[keyIndex].deleted)
|
||||||
|
keyIndex++;
|
||||||
|
return Iterator.wrap(keyIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// How to use it
|
// How to use it
|
||||||
@ -206,11 +212,11 @@ the ``sum`` function iterates over to sum all the values.
|
|||||||
// Computes the sum of all stored data.
|
// Computes the sum of all stored data.
|
||||||
function sum() public view returns (uint s) {
|
function sum() public view returns (uint s) {
|
||||||
for (
|
for (
|
||||||
uint i = data.iterate_start();
|
Iterator i = data.iterateStart();
|
||||||
data.iterate_valid(i);
|
data.iterateValid(i);
|
||||||
i = data.iterate_next(i)
|
i = data.iterateNext(i)
|
||||||
) {
|
) {
|
||||||
(, uint value) = data.iterate_get(i);
|
(, uint value) = data.iterateGet(i);
|
||||||
s += value;
|
s += value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,11 +190,11 @@ If you want to use string parameters or other types that are not implicitly conv
|
|||||||
contract C {
|
contract C {
|
||||||
string s = "Storage";
|
string s = "Storage";
|
||||||
function f(bytes calldata bc, string memory sm, bytes16 b) public view {
|
function f(bytes calldata bc, string memory sm, bytes16 b) public view {
|
||||||
string memory concat_string = string.concat(s, string(bc), "Literal", sm);
|
string memory concatString = string.concat(s, string(bc), "Literal", sm);
|
||||||
assert((bytes(s).length + bc.length + 7 + bytes(sm).length) == bytes(concat_string).length);
|
assert((bytes(s).length + bc.length + 7 + bytes(sm).length) == bytes(concatString).length);
|
||||||
|
|
||||||
bytes memory concat_bytes = bytes.concat(bytes(s), bc, bc[:2], "Literal", bytes(sm), b);
|
bytes memory concatBytes = bytes.concat(bytes(s), bc, bc[:2], "Literal", bytes(sm), b);
|
||||||
assert((bytes(s).length + bc.length + 2 + 7 + bytes(sm).length + b.length) == concat_bytes.length);
|
assert((bytes(s).length + bc.length + 2 + 7 + bytes(sm).length + b.length) == concatBytes.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,20 +376,20 @@ Array Members
|
|||||||
pragma solidity >=0.6.0 <0.9.0;
|
pragma solidity >=0.6.0 <0.9.0;
|
||||||
|
|
||||||
contract ArrayContract {
|
contract ArrayContract {
|
||||||
uint[2**20] m_aLotOfIntegers;
|
uint[2**20] aLotOfIntegers;
|
||||||
// Note that the following is not a pair of dynamic arrays but a
|
// Note that the following is not a pair of dynamic arrays but a
|
||||||
// dynamic array of pairs (i.e. of fixed size arrays of length two).
|
// dynamic array of pairs (i.e. of fixed size arrays of length two).
|
||||||
// Because of that, T[] is always a dynamic array of T, even if T
|
// Because of that, T[] is always a dynamic array of T, even if T
|
||||||
// itself is an array.
|
// itself is an array.
|
||||||
// Data location for all state variables is storage.
|
// Data location for all state variables is storage.
|
||||||
bool[2][] m_pairsOfFlags;
|
bool[2][] pairsOfFlags;
|
||||||
|
|
||||||
// newPairs is stored in memory - the only possibility
|
// newPairs is stored in memory - the only possibility
|
||||||
// for public contract function arguments
|
// for public contract function arguments
|
||||||
function setAllFlagPairs(bool[2][] memory newPairs) public {
|
function setAllFlagPairs(bool[2][] memory newPairs) public {
|
||||||
// assignment to a storage array performs a copy of ``newPairs`` and
|
// assignment to a storage array performs a copy of ``newPairs`` and
|
||||||
// replaces the complete array ``m_pairsOfFlags``.
|
// replaces the complete array ``pairsOfFlags``.
|
||||||
m_pairsOfFlags = newPairs;
|
pairsOfFlags = newPairs;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StructType {
|
struct StructType {
|
||||||
@ -411,45 +411,45 @@ Array Members
|
|||||||
|
|
||||||
function setFlagPair(uint index, bool flagA, bool flagB) public {
|
function setFlagPair(uint index, bool flagA, bool flagB) public {
|
||||||
// access to a non-existing index will throw an exception
|
// access to a non-existing index will throw an exception
|
||||||
m_pairsOfFlags[index][0] = flagA;
|
pairsOfFlags[index][0] = flagA;
|
||||||
m_pairsOfFlags[index][1] = flagB;
|
pairsOfFlags[index][1] = flagB;
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeFlagArraySize(uint newSize) public {
|
function changeFlagArraySize(uint newSize) public {
|
||||||
// using push and pop is the only way to change the
|
// using push and pop is the only way to change the
|
||||||
// length of an array
|
// length of an array
|
||||||
if (newSize < m_pairsOfFlags.length) {
|
if (newSize < pairsOfFlags.length) {
|
||||||
while (m_pairsOfFlags.length > newSize)
|
while (pairsOfFlags.length > newSize)
|
||||||
m_pairsOfFlags.pop();
|
pairsOfFlags.pop();
|
||||||
} else if (newSize > m_pairsOfFlags.length) {
|
} else if (newSize > pairsOfFlags.length) {
|
||||||
while (m_pairsOfFlags.length < newSize)
|
while (pairsOfFlags.length < newSize)
|
||||||
m_pairsOfFlags.push();
|
pairsOfFlags.push();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function clear() public {
|
function clear() public {
|
||||||
// these clear the arrays completely
|
// these clear the arrays completely
|
||||||
delete m_pairsOfFlags;
|
delete pairsOfFlags;
|
||||||
delete m_aLotOfIntegers;
|
delete aLotOfIntegers;
|
||||||
// identical effect here
|
// identical effect here
|
||||||
m_pairsOfFlags = new bool[2][](0);
|
pairsOfFlags = new bool[2][](0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes m_byteData;
|
bytes byteData;
|
||||||
|
|
||||||
function byteArrays(bytes memory data) public {
|
function byteArrays(bytes memory data) public {
|
||||||
// byte arrays ("bytes") are different as they are stored without padding,
|
// byte arrays ("bytes") are different as they are stored without padding,
|
||||||
// but can be treated identical to "uint8[]"
|
// but can be treated identical to "uint8[]"
|
||||||
m_byteData = data;
|
byteData = data;
|
||||||
for (uint i = 0; i < 7; i++)
|
for (uint i = 0; i < 7; i++)
|
||||||
m_byteData.push();
|
byteData.push();
|
||||||
m_byteData[3] = 0x08;
|
byteData[3] = 0x08;
|
||||||
delete m_byteData[2];
|
delete byteData[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
function addFlag(bool[2] memory flag) public returns (uint) {
|
function addFlag(bool[2] memory flag) public returns (uint) {
|
||||||
m_pairsOfFlags.push(flag);
|
pairsOfFlags.push(flag);
|
||||||
return m_pairsOfFlags.length;
|
return pairsOfFlags.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMemoryArray(uint size) public pure returns (bytes memory) {
|
function createMemoryArray(uint size) public pure returns (bytes memory) {
|
||||||
|
@ -409,12 +409,13 @@ Input Description
|
|||||||
"source1.sol": ["contract1"],
|
"source1.sol": ["contract1"],
|
||||||
"source2.sol": ["contract2", "contract3"]
|
"source2.sol": ["contract2", "contract3"]
|
||||||
},
|
},
|
||||||
// Choose whether division and modulo operations should be replaced by
|
// Choose how division and modulo operations should be encoded.
|
||||||
// multiplication with slack variables. Default is `true`.
|
// When using `false` they are replaced by multiplication with slack
|
||||||
// Using `false` here is recommended if you are using the CHC engine
|
// variables. This is the default.
|
||||||
|
// Using `true` here is recommended if you are using the CHC engine
|
||||||
// and not using Spacer as the Horn solver (using Eldarica, for example).
|
// and not using Spacer as the Horn solver (using Eldarica, for example).
|
||||||
// See the Formal Verification section for a more detailed explanation of this option.
|
// See the Formal Verification section for a more detailed explanation of this option.
|
||||||
"divModWithSlacks": true,
|
"divModNoSlacks": false,
|
||||||
// Choose which model checker engine to use: all (default), bmc, chc, none.
|
// Choose which model checker engine to use: all (default), bmc, chc, none.
|
||||||
"engine": "chc",
|
"engine": "chc",
|
||||||
// Choose which types of invariants should be reported to the user: contract, reentrancy.
|
// Choose which types of invariants should be reported to the user: contract, reentrancy.
|
||||||
|
@ -768,7 +768,7 @@ the ``dup`` and ``swap`` instructions as well as ``jump`` instructions, labels a
|
|||||||
+-------------------------+-----+---+-----------------------------------------------------------------+
|
+-------------------------+-----+---+-----------------------------------------------------------------+
|
||||||
| Instruction | | | Explanation |
|
| Instruction | | | Explanation |
|
||||||
+=========================+=====+===+=================================================================+
|
+=========================+=====+===+=================================================================+
|
||||||
| stop() + `-` | F | stop execution, identical to return(0, 0) |
|
| stop() | `-` | F | stop execution, identical to return(0, 0) |
|
||||||
+-------------------------+-----+---+-----------------------------------------------------------------+
|
+-------------------------+-----+---+-----------------------------------------------------------------+
|
||||||
| add(x, y) | | F | x + y |
|
| add(x, y) | | F | x + y |
|
||||||
+-------------------------+-----+---+-----------------------------------------------------------------+
|
+-------------------------+-----+---+-----------------------------------------------------------------+
|
||||||
|
@ -397,26 +397,6 @@ AssemblyItem Assembly::newImmutableAssignment(string const& _identifier)
|
|||||||
return AssemblyItem{AssignImmutable, h};
|
return AssemblyItem{AssignImmutable, h};
|
||||||
}
|
}
|
||||||
|
|
||||||
Assembly& Assembly::optimise(bool _enable, EVMVersion _evmVersion, bool _isCreation, size_t _runs)
|
|
||||||
{
|
|
||||||
OptimiserSettings settings;
|
|
||||||
settings.isCreation = _isCreation;
|
|
||||||
settings.runInliner = true;
|
|
||||||
settings.runJumpdestRemover = true;
|
|
||||||
settings.runPeephole = true;
|
|
||||||
if (_enable)
|
|
||||||
{
|
|
||||||
settings.runDeduplicate = true;
|
|
||||||
settings.runCSE = true;
|
|
||||||
settings.runConstantOptimiser = true;
|
|
||||||
}
|
|
||||||
settings.evmVersion = _evmVersion;
|
|
||||||
settings.expectedExecutionsPerDeployment = _runs;
|
|
||||||
optimise(settings);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Assembly& Assembly::optimise(OptimiserSettings const& _settings)
|
Assembly& Assembly::optimise(OptimiserSettings const& _settings)
|
||||||
{
|
{
|
||||||
optimiseInternal(_settings, {});
|
optimiseInternal(_settings, {});
|
||||||
|
@ -134,13 +134,6 @@ public:
|
|||||||
/// is optimised according to the settings in @a _settings.
|
/// is optimised according to the settings in @a _settings.
|
||||||
Assembly& optimise(OptimiserSettings const& _settings);
|
Assembly& optimise(OptimiserSettings const& _settings);
|
||||||
|
|
||||||
/// Modify (if @a _enable is set) and return the current assembly such that creation and
|
|
||||||
/// execution gas usage is optimised. @a _isCreation should be true for the top-level assembly.
|
|
||||||
/// @a _runs specifes an estimate on how often each opcode in this assembly will be executed,
|
|
||||||
/// i.e. use a small value to optimise for size and a large value to optimise for runtime.
|
|
||||||
/// If @a _enable is not set, will perform some simple peephole optimizations.
|
|
||||||
Assembly& optimise(bool _enable, langutil::EVMVersion _evmVersion, bool _isCreation, size_t _runs);
|
|
||||||
|
|
||||||
/// Create a text representation of the assembly.
|
/// Create a text representation of the assembly.
|
||||||
std::string assemblyString(
|
std::string assemblyString(
|
||||||
langutil::DebugInfoSelection const& _debugInfoSelection = langutil::DebugInfoSelection::Default(),
|
langutil::DebugInfoSelection const& _debugInfoSelection = langutil::DebugInfoSelection::Default(),
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <libevmasm/Exceptions.h>
|
#include <libevmasm/Exceptions.h>
|
||||||
#include <liblangutil/SourceLocation.h>
|
#include <liblangutil/SourceLocation.h>
|
||||||
#include <libsolutil/Common.h>
|
#include <libsolutil/Common.h>
|
||||||
|
#include <libsolutil/Numeric.h>
|
||||||
#include <libsolutil/Assertions.h>
|
#include <libsolutil/Assertions.h>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -11,6 +11,8 @@ set(sources
|
|||||||
ConstantOptimiser.h
|
ConstantOptimiser.h
|
||||||
ControlFlowGraph.cpp
|
ControlFlowGraph.cpp
|
||||||
ControlFlowGraph.h
|
ControlFlowGraph.h
|
||||||
|
Disassemble.cpp
|
||||||
|
Disassemble.h
|
||||||
Exceptions.h
|
Exceptions.h
|
||||||
ExpressionClasses.cpp
|
ExpressionClasses.cpp
|
||||||
ExpressionClasses.h
|
ExpressionClasses.h
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include <liblangutil/EVMVersion.h>
|
#include <liblangutil/EVMVersion.h>
|
||||||
|
|
||||||
|
#include <libsolutil/Numeric.h>
|
||||||
#include <libsolutil/Assertions.h>
|
#include <libsolutil/Assertions.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
76
libevmasm/Disassemble.cpp
Normal file
76
libevmasm/Disassemble.cpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
solidity is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
|
||||||
|
#include <libevmasm/Disassemble.h>
|
||||||
|
|
||||||
|
#include <libsolutil/Common.h>
|
||||||
|
#include <libsolutil/CommonIO.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace solidity;
|
||||||
|
using namespace solidity::util;
|
||||||
|
using namespace solidity::evmasm;
|
||||||
|
|
||||||
|
|
||||||
|
void solidity::evmasm::eachInstruction(
|
||||||
|
bytes const& _mem,
|
||||||
|
function<void(Instruction,u256 const&)> const& _onInstruction
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (auto it = _mem.begin(); it < _mem.end(); ++it)
|
||||||
|
{
|
||||||
|
Instruction const instr{*it};
|
||||||
|
int additional = 0;
|
||||||
|
if (isValidInstruction(instr))
|
||||||
|
additional = instructionInfo(instr).additional;
|
||||||
|
|
||||||
|
u256 data{};
|
||||||
|
|
||||||
|
// fill the data with the additional data bytes from the instruction stream
|
||||||
|
while (additional > 0 && std::next(it) < _mem.end())
|
||||||
|
{
|
||||||
|
data <<= 8;
|
||||||
|
data |= *++it;
|
||||||
|
--additional;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pad the remaining number of additional octets with zeros
|
||||||
|
data <<= 8 * additional;
|
||||||
|
|
||||||
|
_onInstruction(instr, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string solidity::evmasm::disassemble(bytes const& _mem, string const& _delimiter)
|
||||||
|
{
|
||||||
|
stringstream ret;
|
||||||
|
eachInstruction(_mem, [&](Instruction _instr, u256 const& _data) {
|
||||||
|
if (!isValidInstruction(_instr))
|
||||||
|
ret << "0x" << std::uppercase << std::hex << static_cast<int>(_instr) << _delimiter;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InstructionInfo info = instructionInfo(_instr);
|
||||||
|
ret << info.name;
|
||||||
|
if (info.additional)
|
||||||
|
ret << " 0x" << std::uppercase << std::hex << _data;
|
||||||
|
ret << _delimiter;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return ret.str();
|
||||||
|
}
|
38
libevmasm/Disassemble.h
Normal file
38
libevmasm/Disassemble.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
solidity is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <libsolutil/Common.h>
|
||||||
|
#include <libsolutil/Numeric.h>
|
||||||
|
|
||||||
|
#include <libevmasm/Instruction.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace solidity::evmasm
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Iterate through EVM code and call a function on each instruction.
|
||||||
|
void eachInstruction(bytes const& _mem, std::function<void(Instruction, u256 const&)> const& _onInstruction);
|
||||||
|
|
||||||
|
/// Convert from EVM code to simple EVM assembly language.
|
||||||
|
std::string disassemble(bytes const& _mem, std::string const& _delimiter = " ");
|
||||||
|
|
||||||
|
}
|
@ -22,10 +22,6 @@
|
|||||||
|
|
||||||
#include <libevmasm/Instruction.h>
|
#include <libevmasm/Instruction.h>
|
||||||
|
|
||||||
#include <libsolutil/Common.h>
|
|
||||||
#include <libsolutil/CommonIO.h>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::util;
|
using namespace solidity::util;
|
||||||
@ -325,53 +321,6 @@ static std::map<Instruction, InstructionInfo> const c_instructionInfo =
|
|||||||
{ Instruction::SELFDESTRUCT, { "SELFDESTRUCT", 0, 1, 0, true, Tier::Special } }
|
{ Instruction::SELFDESTRUCT, { "SELFDESTRUCT", 0, 1, 0, true, Tier::Special } }
|
||||||
};
|
};
|
||||||
|
|
||||||
void solidity::evmasm::eachInstruction(
|
|
||||||
bytes const& _mem,
|
|
||||||
function<void(Instruction,u256 const&)> const& _onInstruction
|
|
||||||
)
|
|
||||||
{
|
|
||||||
for (auto it = _mem.begin(); it < _mem.end(); ++it)
|
|
||||||
{
|
|
||||||
auto instr = Instruction(*it);
|
|
||||||
int additional = 0;
|
|
||||||
if (isValidInstruction(instr))
|
|
||||||
additional = instructionInfo(instr).additional;
|
|
||||||
|
|
||||||
u256 data;
|
|
||||||
|
|
||||||
// fill the data with the additional data bytes from the instruction stream
|
|
||||||
while (additional > 0 && std::next(it) < _mem.end())
|
|
||||||
{
|
|
||||||
data <<= 8;
|
|
||||||
data |= *++it;
|
|
||||||
--additional;
|
|
||||||
}
|
|
||||||
|
|
||||||
// pad the remaining number of additional octets with zeros
|
|
||||||
data <<= 8 * additional;
|
|
||||||
|
|
||||||
_onInstruction(instr, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string solidity::evmasm::disassemble(bytes const& _mem, string const& _delimiter)
|
|
||||||
{
|
|
||||||
stringstream ret;
|
|
||||||
eachInstruction(_mem, [&](Instruction _instr, u256 const& _data) {
|
|
||||||
if (!isValidInstruction(_instr))
|
|
||||||
ret << "0x" << std::uppercase << std::hex << static_cast<int>(_instr) << _delimiter;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
InstructionInfo info = instructionInfo(_instr);
|
|
||||||
ret << info.name;
|
|
||||||
if (info.additional)
|
|
||||||
ret << " 0x" << std::uppercase << std::hex << _data;
|
|
||||||
ret << _delimiter;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return ret.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
InstructionInfo solidity::evmasm::instructionInfo(Instruction _inst)
|
InstructionInfo solidity::evmasm::instructionInfo(Instruction _inst)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -380,7 +329,7 @@ InstructionInfo solidity::evmasm::instructionInfo(Instruction _inst)
|
|||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
return InstructionInfo({"<INVALID_INSTRUCTION: " + toString((unsigned)_inst) + ">", 0, 0, 0, false, Tier::Invalid});
|
return InstructionInfo({"<INVALID_INSTRUCTION: " + to_string(static_cast<unsigned>(_inst)) + ">", 0, 0, 0, false, Tier::Invalid});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,8 +25,6 @@
|
|||||||
#include <libevmasm/Exceptions.h>
|
#include <libevmasm/Exceptions.h>
|
||||||
#include <libsolutil/Common.h>
|
#include <libsolutil/Common.h>
|
||||||
#include <libsolutil/Assertions.h>
|
#include <libsolutil/Assertions.h>
|
||||||
#include <libsolutil/Numeric.h>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
namespace solidity::evmasm
|
namespace solidity::evmasm
|
||||||
{
|
{
|
||||||
@ -217,25 +215,25 @@ inline bool isLogInstruction(Instruction _inst)
|
|||||||
/// @returns the number of PUSH Instruction _inst
|
/// @returns the number of PUSH Instruction _inst
|
||||||
inline unsigned getPushNumber(Instruction _inst)
|
inline unsigned getPushNumber(Instruction _inst)
|
||||||
{
|
{
|
||||||
return (uint8_t)_inst - unsigned(Instruction::PUSH1) + 1;
|
return static_cast<uint8_t>(_inst) - unsigned(Instruction::PUSH1) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns the number of DUP Instruction _inst
|
/// @returns the number of DUP Instruction _inst
|
||||||
inline unsigned getDupNumber(Instruction _inst)
|
inline unsigned getDupNumber(Instruction _inst)
|
||||||
{
|
{
|
||||||
return (uint8_t)_inst - unsigned(Instruction::DUP1) + 1;
|
return static_cast<uint8_t>(_inst) - unsigned(Instruction::DUP1) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns the number of SWAP Instruction _inst
|
/// @returns the number of SWAP Instruction _inst
|
||||||
inline unsigned getSwapNumber(Instruction _inst)
|
inline unsigned getSwapNumber(Instruction _inst)
|
||||||
{
|
{
|
||||||
return (uint8_t)_inst - unsigned(Instruction::SWAP1) + 1;
|
return static_cast<uint8_t>(_inst) - unsigned(Instruction::SWAP1) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns the number of LOG Instruction _inst
|
/// @returns the number of LOG Instruction _inst
|
||||||
inline unsigned getLogNumber(Instruction _inst)
|
inline unsigned getLogNumber(Instruction _inst)
|
||||||
{
|
{
|
||||||
return (uint8_t)_inst - unsigned(Instruction::LOG0);
|
return static_cast<uint8_t>(_inst) - unsigned(Instruction::LOG0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns the PUSH<_number> instruction
|
/// @returns the PUSH<_number> instruction
|
||||||
@ -266,7 +264,7 @@ inline Instruction logInstruction(unsigned _number)
|
|||||||
return Instruction(unsigned(Instruction::LOG0) + _number);
|
return Instruction(unsigned(Instruction::LOG0) + _number);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Tier : unsigned
|
enum class Tier
|
||||||
{
|
{
|
||||||
Zero = 0, // 0, Zero
|
Zero = 0, // 0, Zero
|
||||||
Base, // 2, Quick
|
Base, // 2, Quick
|
||||||
@ -301,10 +299,4 @@ bool isValidInstruction(Instruction _inst);
|
|||||||
/// Convert from string mnemonic to Instruction type.
|
/// Convert from string mnemonic to Instruction type.
|
||||||
extern const std::map<std::string, Instruction> c_instructions;
|
extern const std::map<std::string, Instruction> c_instructions;
|
||||||
|
|
||||||
/// Iterate through EVM code and call a function on each instruction.
|
|
||||||
void eachInstruction(bytes const& _mem, std::function<void(Instruction, u256 const&)> const& _onInstruction);
|
|
||||||
|
|
||||||
/// Convert from EVM code to simple EVM assembly language.
|
|
||||||
std::string disassemble(bytes const& _mem, std::string const& _delimiter = " ");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,125 @@ using namespace std;
|
|||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::evmasm;
|
using namespace solidity::evmasm;
|
||||||
|
|
||||||
|
vector<SemanticInformation::Operation> SemanticInformation::readWriteOperations(Instruction _instruction)
|
||||||
|
{
|
||||||
|
switch (_instruction)
|
||||||
|
{
|
||||||
|
case Instruction::SSTORE:
|
||||||
|
case Instruction::SLOAD:
|
||||||
|
{
|
||||||
|
assertThrow(memory(_instruction) == Effect::None, OptimizerException, "");
|
||||||
|
assertThrow(storage(_instruction) != Effect::None, OptimizerException, "");
|
||||||
|
Operation op;
|
||||||
|
op.effect = storage(_instruction);
|
||||||
|
op.location = Location::Storage;
|
||||||
|
op.startParameter = 0;
|
||||||
|
// We know that exactly one slot is affected.
|
||||||
|
op.lengthConstant = 1;
|
||||||
|
return {op};
|
||||||
|
}
|
||||||
|
case Instruction::MSTORE:
|
||||||
|
case Instruction::MSTORE8:
|
||||||
|
case Instruction::MLOAD:
|
||||||
|
{
|
||||||
|
assertThrow(memory(_instruction) != Effect::None, OptimizerException, "");
|
||||||
|
assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
|
||||||
|
Operation op;
|
||||||
|
op.effect = memory(_instruction);
|
||||||
|
op.location = Location::Memory;
|
||||||
|
op.startParameter = 0;
|
||||||
|
if (_instruction == Instruction::MSTORE || _instruction == Instruction::MLOAD)
|
||||||
|
op.lengthConstant = 32;
|
||||||
|
else if (_instruction == Instruction::MSTORE8)
|
||||||
|
op.lengthConstant = 1;
|
||||||
|
|
||||||
|
return {op};
|
||||||
|
}
|
||||||
|
case Instruction::REVERT:
|
||||||
|
case Instruction::RETURN:
|
||||||
|
case Instruction::KECCAK256:
|
||||||
|
case Instruction::LOG0:
|
||||||
|
case Instruction::LOG1:
|
||||||
|
case Instruction::LOG2:
|
||||||
|
case Instruction::LOG3:
|
||||||
|
case Instruction::LOG4:
|
||||||
|
{
|
||||||
|
assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
|
||||||
|
assertThrow(memory(_instruction) == Effect::Read, OptimizerException, "");
|
||||||
|
Operation op;
|
||||||
|
op.effect = memory(_instruction);
|
||||||
|
op.location = Location::Memory;
|
||||||
|
op.startParameter = 0;
|
||||||
|
op.lengthParameter = 1;
|
||||||
|
return {op};
|
||||||
|
}
|
||||||
|
case Instruction::EXTCODECOPY:
|
||||||
|
{
|
||||||
|
assertThrow(memory(_instruction) == Effect::Write, OptimizerException, "");
|
||||||
|
assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
|
||||||
|
Operation op;
|
||||||
|
op.effect = memory(_instruction);
|
||||||
|
op.location = Location::Memory;
|
||||||
|
op.startParameter = 1;
|
||||||
|
op.lengthParameter = 3;
|
||||||
|
return {op};
|
||||||
|
}
|
||||||
|
case Instruction::CODECOPY:
|
||||||
|
case Instruction::CALLDATACOPY:
|
||||||
|
case Instruction::RETURNDATACOPY:
|
||||||
|
{
|
||||||
|
assertThrow(memory(_instruction) == Effect::Write, OptimizerException, "");
|
||||||
|
assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
|
||||||
|
Operation op;
|
||||||
|
op.effect = memory(_instruction);
|
||||||
|
op.location = Location::Memory;
|
||||||
|
op.startParameter = 0;
|
||||||
|
op.lengthParameter = 2;
|
||||||
|
return {op};
|
||||||
|
}
|
||||||
|
case Instruction::STATICCALL:
|
||||||
|
case Instruction::CALL:
|
||||||
|
case Instruction::CALLCODE:
|
||||||
|
case Instruction::DELEGATECALL:
|
||||||
|
{
|
||||||
|
size_t paramCount = static_cast<size_t>(instructionInfo(_instruction).args);
|
||||||
|
vector<Operation> operations{
|
||||||
|
Operation{Location::Memory, Effect::Read, paramCount - 4, paramCount - 3, {}},
|
||||||
|
Operation{Location::Storage, Effect::Read, {}, {}, {}}
|
||||||
|
};
|
||||||
|
if (_instruction != Instruction::STATICCALL)
|
||||||
|
operations.emplace_back(Operation{Location::Storage, Effect::Write, {}, {}, {}});
|
||||||
|
operations.emplace_back(Operation{
|
||||||
|
Location::Memory,
|
||||||
|
Effect::Write,
|
||||||
|
paramCount - 2,
|
||||||
|
paramCount - 1,
|
||||||
|
{}
|
||||||
|
});
|
||||||
|
return operations;
|
||||||
|
}
|
||||||
|
case Instruction::CREATE:
|
||||||
|
case Instruction::CREATE2:
|
||||||
|
return vector<Operation>{
|
||||||
|
Operation{
|
||||||
|
Location::Memory,
|
||||||
|
Effect::Read,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
{}
|
||||||
|
},
|
||||||
|
Operation{Location::Storage, Effect::Read, {}, {}, {}},
|
||||||
|
Operation{Location::Storage, Effect::Write, {}, {}, {}}
|
||||||
|
};
|
||||||
|
case Instruction::MSIZE:
|
||||||
|
// This is just to satisfy the assert below.
|
||||||
|
return vector<Operation>{};
|
||||||
|
default:
|
||||||
|
assertThrow(storage(_instruction) == None && memory(_instruction) == None, AssemblyException, "");
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item, bool _msizeImportant)
|
bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item, bool _msizeImportant)
|
||||||
{
|
{
|
||||||
switch (_item.type())
|
switch (_item.type())
|
||||||
@ -49,7 +168,7 @@ bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item, bool
|
|||||||
case PushLibraryAddress:
|
case PushLibraryAddress:
|
||||||
case PushImmutable:
|
case PushImmutable:
|
||||||
return false;
|
return false;
|
||||||
case Operation:
|
case evmasm::Operation:
|
||||||
{
|
{
|
||||||
if (isSwapInstruction(_item) || isDupInstruction(_item))
|
if (isSwapInstruction(_item) || isDupInstruction(_item))
|
||||||
return false;
|
return false;
|
||||||
@ -79,7 +198,7 @@ bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item, bool
|
|||||||
|
|
||||||
bool SemanticInformation::isCommutativeOperation(AssemblyItem const& _item)
|
bool SemanticInformation::isCommutativeOperation(AssemblyItem const& _item)
|
||||||
{
|
{
|
||||||
if (_item.type() != Operation)
|
if (_item.type() != evmasm::Operation)
|
||||||
return false;
|
return false;
|
||||||
switch (_item.instruction())
|
switch (_item.instruction())
|
||||||
{
|
{
|
||||||
@ -97,14 +216,14 @@ bool SemanticInformation::isCommutativeOperation(AssemblyItem const& _item)
|
|||||||
|
|
||||||
bool SemanticInformation::isDupInstruction(AssemblyItem const& _item)
|
bool SemanticInformation::isDupInstruction(AssemblyItem const& _item)
|
||||||
{
|
{
|
||||||
if (_item.type() != Operation)
|
if (_item.type() != evmasm::Operation)
|
||||||
return false;
|
return false;
|
||||||
return evmasm::isDupInstruction(_item.instruction());
|
return evmasm::isDupInstruction(_item.instruction());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item)
|
bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item)
|
||||||
{
|
{
|
||||||
if (_item.type() != Operation)
|
if (_item.type() != evmasm::Operation)
|
||||||
return false;
|
return false;
|
||||||
return evmasm::isSwapInstruction(_item.instruction());
|
return evmasm::isSwapInstruction(_item.instruction());
|
||||||
}
|
}
|
||||||
@ -116,7 +235,7 @@ bool SemanticInformation::isJumpInstruction(AssemblyItem const& _item)
|
|||||||
|
|
||||||
bool SemanticInformation::altersControlFlow(AssemblyItem const& _item)
|
bool SemanticInformation::altersControlFlow(AssemblyItem const& _item)
|
||||||
{
|
{
|
||||||
if (_item.type() != Operation)
|
if (_item.type() != evmasm::Operation)
|
||||||
return false;
|
return false;
|
||||||
switch (_item.instruction())
|
switch (_item.instruction())
|
||||||
{
|
{
|
||||||
@ -166,7 +285,7 @@ bool SemanticInformation::isDeterministic(AssemblyItem const& _item)
|
|||||||
{
|
{
|
||||||
assertThrow(_item.type() != VerbatimBytecode, AssemblyException, "");
|
assertThrow(_item.type() != VerbatimBytecode, AssemblyException, "");
|
||||||
|
|
||||||
if (_item.type() != Operation)
|
if (_item.type() != evmasm::Operation)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
switch (_item.instruction())
|
switch (_item.instruction())
|
||||||
|
@ -26,6 +26,9 @@
|
|||||||
|
|
||||||
#include <libevmasm/Instruction.h>
|
#include <libevmasm/Instruction.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace solidity::evmasm
|
namespace solidity::evmasm
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -45,6 +48,32 @@ struct SemanticInformation
|
|||||||
Write
|
Write
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class Location { Storage, Memory };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a read or write operation from or to one of the data locations.
|
||||||
|
*/
|
||||||
|
struct Operation
|
||||||
|
{
|
||||||
|
Location location;
|
||||||
|
Effect effect;
|
||||||
|
/// Start of affected area as an index into the parameters.
|
||||||
|
/// Unknown if not provided.
|
||||||
|
std::optional<size_t> startParameter;
|
||||||
|
/// Length of the affected area as an index into the parameters (if this is an opcode).
|
||||||
|
/// Unknown if neither this nor lengthConstant is provided.
|
||||||
|
std::optional<size_t> lengthParameter;
|
||||||
|
/// Length as a constant.
|
||||||
|
/// Unknown if neither this nor lengthArgument is provided.
|
||||||
|
std::optional<size_t> lengthConstant;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @returns the sequence of read write operations performed by the instruction.
|
||||||
|
/// Order matters.
|
||||||
|
/// For external calls, there is just one unknown read and one unknown write operation,
|
||||||
|
/// event though there might be multiple.
|
||||||
|
static std::vector<Operation> readWriteOperations(Instruction _instruction);
|
||||||
|
|
||||||
/// @returns true if the given items starts a new block for common subexpression analysis.
|
/// @returns true if the given items starts a new block for common subexpression analysis.
|
||||||
/// @param _msizeImportant if false, consider an operation non-breaking if its only side-effect is that it modifies msize.
|
/// @param _msizeImportant if false, consider an operation non-breaking if its only side-effect is that it modifies msize.
|
||||||
static bool breaksCSEAnalysisBlock(AssemblyItem const& _item, bool _msizeImportant);
|
static bool breaksCSEAnalysisBlock(AssemblyItem const& _item, bool _msizeImportant);
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include <liblangutil/Common.h>
|
#include <liblangutil/Common.h>
|
||||||
|
|
||||||
#include <range/v3/algorithm/any_of.hpp>
|
#include <range/v3/algorithm/any_of.hpp>
|
||||||
|
#include <range/v3/view/filter.hpp>
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
@ -162,6 +163,81 @@ bool DocStringTagParser::visit(ErrorDefinition const& _error)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DocStringTagParser::visit(InlineAssembly const& _assembly)
|
||||||
|
{
|
||||||
|
if (!_assembly.documentation())
|
||||||
|
return true;
|
||||||
|
StructuredDocumentation documentation{-1, _assembly.location(), _assembly.documentation()};
|
||||||
|
ErrorList errors;
|
||||||
|
ErrorReporter errorReporter{errors};
|
||||||
|
auto docTags = DocStringParser{documentation, errorReporter}.parse();
|
||||||
|
|
||||||
|
if (!errors.empty())
|
||||||
|
{
|
||||||
|
SecondarySourceLocation ssl;
|
||||||
|
for (auto const& error: errors)
|
||||||
|
if (error->comment())
|
||||||
|
ssl.append(
|
||||||
|
*error->comment(),
|
||||||
|
_assembly.location()
|
||||||
|
);
|
||||||
|
m_errorReporter.warning(
|
||||||
|
7828_error,
|
||||||
|
_assembly.location(),
|
||||||
|
"Inline assembly has invalid NatSpec documentation.",
|
||||||
|
ssl
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& [tagName, tagValue]: docTags)
|
||||||
|
{
|
||||||
|
if (tagName == "solidity")
|
||||||
|
{
|
||||||
|
vector<string> values;
|
||||||
|
boost::split(values, tagValue.content, isWhiteSpace);
|
||||||
|
|
||||||
|
set<string> valuesSeen;
|
||||||
|
set<string> duplicates;
|
||||||
|
for (auto const& value: values | ranges::views::filter(not_fn(&string::empty)))
|
||||||
|
if (valuesSeen.insert(value).second)
|
||||||
|
{
|
||||||
|
if (value == "memory-safe-assembly")
|
||||||
|
{
|
||||||
|
if (_assembly.annotation().markedMemorySafe)
|
||||||
|
m_errorReporter.warning(
|
||||||
|
8544_error,
|
||||||
|
_assembly.location(),
|
||||||
|
"Inline assembly marked as memory safe using both a NatSpec tag and an assembly flag. "
|
||||||
|
"If you are not concerned with backwards compatibility, only use the assembly flag, "
|
||||||
|
"otherwise only use the NatSpec tag."
|
||||||
|
);
|
||||||
|
_assembly.annotation().markedMemorySafe = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_errorReporter.warning(
|
||||||
|
8787_error,
|
||||||
|
_assembly.location(),
|
||||||
|
"Unexpected value for @solidity tag in inline assembly: " + value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (duplicates.insert(value).second)
|
||||||
|
m_errorReporter.warning(
|
||||||
|
4377_error,
|
||||||
|
_assembly.location(),
|
||||||
|
"Value for @solidity tag in inline assembly specified multiple times: " + value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_errorReporter.warning(
|
||||||
|
6269_error,
|
||||||
|
_assembly.location(),
|
||||||
|
"Unexpected NatSpec tag \"" + tagName + "\" with value \"" + tagValue.content + "\" in inline assembly."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void DocStringTagParser::checkParameters(
|
void DocStringTagParser::checkParameters(
|
||||||
CallableDeclaration const& _callable,
|
CallableDeclaration const& _callable,
|
||||||
StructurallyDocumented const& _node,
|
StructurallyDocumented const& _node,
|
||||||
|
@ -48,6 +48,7 @@ private:
|
|||||||
bool visit(ModifierDefinition const& _modifier) override;
|
bool visit(ModifierDefinition const& _modifier) override;
|
||||||
bool visit(EventDefinition const& _event) override;
|
bool visit(EventDefinition const& _event) override;
|
||||||
bool visit(ErrorDefinition const& _error) override;
|
bool visit(ErrorDefinition const& _error) override;
|
||||||
|
bool visit(InlineAssembly const& _assembly) override;
|
||||||
|
|
||||||
void checkParameters(
|
void checkParameters(
|
||||||
CallableDeclaration const& _callable,
|
CallableDeclaration const& _callable,
|
||||||
|
@ -334,6 +334,27 @@ bool SyntaxChecker::visit(UnaryOperation const& _operation)
|
|||||||
|
|
||||||
bool SyntaxChecker::visit(InlineAssembly const& _inlineAssembly)
|
bool SyntaxChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||||
{
|
{
|
||||||
|
if (_inlineAssembly.flags())
|
||||||
|
for (auto flag: *_inlineAssembly.flags())
|
||||||
|
{
|
||||||
|
if (*flag == "memory-safe")
|
||||||
|
{
|
||||||
|
if (_inlineAssembly.annotation().markedMemorySafe)
|
||||||
|
m_errorReporter.syntaxError(
|
||||||
|
7026_error,
|
||||||
|
_inlineAssembly.location(),
|
||||||
|
"Inline assembly marked memory-safe multiple times."
|
||||||
|
);
|
||||||
|
_inlineAssembly.annotation().markedMemorySafe = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_errorReporter.warning(
|
||||||
|
4430_error,
|
||||||
|
_inlineAssembly.location(),
|
||||||
|
"Unknown inline assembly flag: \"" + *flag + "\""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_useYulOptimizer)
|
if (!m_useYulOptimizer)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -763,6 +763,7 @@ void TypeChecker::endVisit(FunctionTypeName const& _funType)
|
|||||||
|
|
||||||
bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||||
{
|
{
|
||||||
|
bool lvalueAccessToMemoryVariable = false;
|
||||||
// External references have already been resolved in a prior stage and stored in the annotation.
|
// External references have already been resolved in a prior stage and stored in the annotation.
|
||||||
// We run the resolve step again regardless.
|
// We run the resolve step again regardless.
|
||||||
yul::ExternalIdentifierAccess::Resolver identifierAccess = [&](
|
yul::ExternalIdentifierAccess::Resolver identifierAccess = [&](
|
||||||
@ -780,6 +781,8 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
if (auto var = dynamic_cast<VariableDeclaration const*>(declaration))
|
if (auto var = dynamic_cast<VariableDeclaration const*>(declaration))
|
||||||
{
|
{
|
||||||
solAssert(var->type(), "Expected variable type!");
|
solAssert(var->type(), "Expected variable type!");
|
||||||
|
if (_context == yul::IdentifierContext::LValue && var->type()->dataStoredIn(DataLocation::Memory))
|
||||||
|
lvalueAccessToMemoryVariable = true;
|
||||||
if (var->immutable())
|
if (var->immutable())
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(3773_error, nativeLocationOf(_identifier), "Assembly access to immutable variables is not supported.");
|
m_errorReporter.typeError(3773_error, nativeLocationOf(_identifier), "Assembly access to immutable variables is not supported.");
|
||||||
@ -967,8 +970,11 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
identifierAccess
|
identifierAccess
|
||||||
);
|
);
|
||||||
if (!analyzer.analyze(_inlineAssembly.operations()))
|
if (!analyzer.analyze(_inlineAssembly.operations()))
|
||||||
return false;
|
solAssert(m_errorReporter.hasErrors());
|
||||||
return true;
|
_inlineAssembly.annotation().hasMemoryEffects =
|
||||||
|
lvalueAccessToMemoryVariable ||
|
||||||
|
(analyzer.sideEffects().memory != yul::SideEffects::None);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeChecker::visit(IfStatement const& _ifStatement)
|
bool TypeChecker::visit(IfStatement const& _ifStatement)
|
||||||
|
@ -256,10 +256,9 @@ void ViewPureChecker::reportMutability(
|
|||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
8961_error,
|
8961_error,
|
||||||
_location,
|
_location,
|
||||||
"Function declared as " +
|
"Function cannot be declared as " +
|
||||||
stateMutabilityToString(m_currentFunction->stateMutability()) +
|
stateMutabilityToString(m_currentFunction->stateMutability()) +
|
||||||
", but this expression (potentially) modifies the state and thus "
|
" because this expression (potentially) modifies the state."
|
||||||
"requires non-payable (the default) or payable."
|
|
||||||
);
|
);
|
||||||
m_errors = true;
|
m_errors = true;
|
||||||
}
|
}
|
||||||
|
@ -1463,19 +1463,26 @@ public:
|
|||||||
SourceLocation const& _location,
|
SourceLocation const& _location,
|
||||||
ASTPointer<ASTString> const& _docString,
|
ASTPointer<ASTString> const& _docString,
|
||||||
yul::Dialect const& _dialect,
|
yul::Dialect const& _dialect,
|
||||||
|
ASTPointer<std::vector<ASTPointer<ASTString>>> _flags,
|
||||||
std::shared_ptr<yul::Block> _operations
|
std::shared_ptr<yul::Block> _operations
|
||||||
):
|
):
|
||||||
Statement(_id, _location, _docString), m_dialect(_dialect), m_operations(std::move(_operations)) {}
|
Statement(_id, _location, _docString),
|
||||||
|
m_dialect(_dialect),
|
||||||
|
m_flags(move(_flags)),
|
||||||
|
m_operations(std::move(_operations))
|
||||||
|
{}
|
||||||
void accept(ASTVisitor& _visitor) override;
|
void accept(ASTVisitor& _visitor) override;
|
||||||
void accept(ASTConstVisitor& _visitor) const override;
|
void accept(ASTConstVisitor& _visitor) const override;
|
||||||
|
|
||||||
yul::Dialect const& dialect() const { return m_dialect; }
|
yul::Dialect const& dialect() const { return m_dialect; }
|
||||||
yul::Block const& operations() const { return *m_operations; }
|
yul::Block const& operations() const { return *m_operations; }
|
||||||
|
ASTPointer<std::vector<ASTPointer<ASTString>>> const& flags() const { return m_flags; }
|
||||||
|
|
||||||
InlineAssemblyAnnotation& annotation() const override;
|
InlineAssemblyAnnotation& annotation() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
yul::Dialect const& m_dialect;
|
yul::Dialect const& m_dialect;
|
||||||
|
ASTPointer<std::vector<ASTPointer<ASTString>>> m_flags;
|
||||||
std::shared_ptr<yul::Block> m_operations;
|
std::shared_ptr<yul::Block> m_operations;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -220,6 +220,10 @@ struct InlineAssemblyAnnotation: StatementAnnotation
|
|||||||
std::map<yul::Identifier const*, ExternalIdentifierInfo> externalReferences;
|
std::map<yul::Identifier const*, ExternalIdentifierInfo> externalReferences;
|
||||||
/// Information generated during analysis phase.
|
/// Information generated during analysis phase.
|
||||||
std::shared_ptr<yul::AsmAnalysisInfo> analysisInfo;
|
std::shared_ptr<yul::AsmAnalysisInfo> analysisInfo;
|
||||||
|
/// True, if the assembly block was annotated to be memory-safe.
|
||||||
|
bool markedMemorySafe = false;
|
||||||
|
/// True, if the assembly block involves any memory opcode or assigns to variables in memory.
|
||||||
|
SetOnce<bool> hasMemoryEffects;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BlockAnnotation: StatementAnnotation, ScopableAnnotation
|
struct BlockAnnotation: StatementAnnotation, ScopableAnnotation
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <libsolutil/JSON.h>
|
#include <libsolutil/JSON.h>
|
||||||
#include <libsolutil/UTF8.h>
|
#include <libsolutil/UTF8.h>
|
||||||
#include <libsolutil/CommonData.h>
|
#include <libsolutil/CommonData.h>
|
||||||
|
#include <libsolutil/Keccak256.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/join.hpp>
|
#include <boost/algorithm/string/join.hpp>
|
||||||
|
|
||||||
@ -493,24 +494,36 @@ bool ASTJsonConverter::visit(ModifierInvocation const& _node)
|
|||||||
bool ASTJsonConverter::visit(EventDefinition const& _node)
|
bool ASTJsonConverter::visit(EventDefinition const& _node)
|
||||||
{
|
{
|
||||||
m_inEvent = true;
|
m_inEvent = true;
|
||||||
setJsonNode(_node, "EventDefinition", {
|
std::vector<pair<string, Json::Value>> _attributes = {
|
||||||
make_pair("name", _node.name()),
|
make_pair("name", _node.name()),
|
||||||
make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
||||||
make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
||||||
make_pair("parameters", toJson(_node.parameterList())),
|
make_pair("parameters", toJson(_node.parameterList())),
|
||||||
make_pair("anonymous", _node.isAnonymous())
|
make_pair("anonymous", _node.isAnonymous())
|
||||||
});
|
};
|
||||||
|
if (m_stackState >= CompilerStack::State::AnalysisPerformed)
|
||||||
|
_attributes.emplace_back(
|
||||||
|
make_pair(
|
||||||
|
"eventSelector",
|
||||||
|
toHex(u256(h256::Arith(util::keccak256(_node.functionType(true)->externalSignature()))))
|
||||||
|
));
|
||||||
|
|
||||||
|
setJsonNode(_node, "EventDefinition", std::move(_attributes));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(ErrorDefinition const& _node)
|
bool ASTJsonConverter::visit(ErrorDefinition const& _node)
|
||||||
{
|
{
|
||||||
setJsonNode(_node, "ErrorDefinition", {
|
std::vector<pair<string, Json::Value>> _attributes = {
|
||||||
make_pair("name", _node.name()),
|
make_pair("name", _node.name()),
|
||||||
make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
||||||
make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
||||||
make_pair("parameters", toJson(_node.parameterList()))
|
make_pair("parameters", toJson(_node.parameterList()))
|
||||||
});
|
};
|
||||||
|
if (m_stackState >= CompilerStack::State::AnalysisPerformed)
|
||||||
|
_attributes.emplace_back(make_pair("errorSelector", _node.functionType(true)->externalIdentifierHex()));
|
||||||
|
|
||||||
|
setJsonNode(_node, "ErrorDefinition", std::move(_attributes));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,11 +600,23 @@ bool ASTJsonConverter::visit(InlineAssembly const& _node)
|
|||||||
for (Json::Value& it: externalReferences | ranges::views::values)
|
for (Json::Value& it: externalReferences | ranges::views::values)
|
||||||
externalReferencesJson.append(std::move(it));
|
externalReferencesJson.append(std::move(it));
|
||||||
|
|
||||||
setJsonNode(_node, "InlineAssembly", {
|
std::vector<pair<string, Json::Value>> attributes = {
|
||||||
make_pair("AST", Json::Value(yul::AsmJsonConverter(sourceIndexFromLocation(_node.location()))(_node.operations()))),
|
make_pair("AST", Json::Value(yul::AsmJsonConverter(sourceIndexFromLocation(_node.location()))(_node.operations()))),
|
||||||
make_pair("externalReferences", std::move(externalReferencesJson)),
|
make_pair("externalReferences", std::move(externalReferencesJson)),
|
||||||
make_pair("evmVersion", dynamic_cast<solidity::yul::EVMDialect const&>(_node.dialect()).evmVersion().name())
|
make_pair("evmVersion", dynamic_cast<solidity::yul::EVMDialect const&>(_node.dialect()).evmVersion().name())
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (_node.flags())
|
||||||
|
{
|
||||||
|
Json::Value flags(Json::arrayValue);
|
||||||
|
for (auto const& flag: *_node.flags())
|
||||||
|
if (flag)
|
||||||
|
flags.append(*flag);
|
||||||
|
else
|
||||||
|
flags.append(Json::nullValue);
|
||||||
|
attributes.emplace_back(make_pair("flags", move(flags)));
|
||||||
|
}
|
||||||
|
setJsonNode(_node, "InlineAssembly", move(attributes));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -626,11 +626,24 @@ ASTPointer<InlineAssembly> ASTJsonImporter::createInlineAssembly(Json::Value con
|
|||||||
astAssert(m_evmVersion == evmVersion, "Imported tree evm version differs from configured evm version!");
|
astAssert(m_evmVersion == evmVersion, "Imported tree evm version differs from configured evm version!");
|
||||||
|
|
||||||
yul::Dialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(evmVersion.value());
|
yul::Dialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(evmVersion.value());
|
||||||
|
ASTPointer<vector<ASTPointer<ASTString>>> flags;
|
||||||
|
if (_node.isMember("flags"))
|
||||||
|
{
|
||||||
|
flags = make_shared<vector<ASTPointer<ASTString>>>();
|
||||||
|
Json::Value const& flagsNode = _node["flags"];
|
||||||
|
astAssert(flagsNode.isArray(), "Assembly flags must be an array.");
|
||||||
|
for (Json::ArrayIndex i = 0; i < flagsNode.size(); ++i)
|
||||||
|
{
|
||||||
|
astAssert(flagsNode[i].isString(), "Assembly flag must be a string.");
|
||||||
|
flags->emplace_back(make_shared<ASTString>(flagsNode[i].asString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
shared_ptr<yul::Block> operations = make_shared<yul::Block>(yul::AsmJsonImporter(m_sourceNames).createBlock(member(_node, "AST")));
|
shared_ptr<yul::Block> operations = make_shared<yul::Block>(yul::AsmJsonImporter(m_sourceNames).createBlock(member(_node, "AST")));
|
||||||
return createASTNode<InlineAssembly>(
|
return createASTNode<InlineAssembly>(
|
||||||
_node,
|
_node,
|
||||||
nullOrASTString(_node, "documentation"),
|
nullOrASTString(_node, "documentation"),
|
||||||
dialect,
|
dialect,
|
||||||
|
move(flags),
|
||||||
operations
|
operations
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -54,4 +54,6 @@ ReturnInfo::ReturnInfo(EVMVersion const& _evmVersion, FunctionType const& _funct
|
|||||||
estimatedReturnSize += retType->decodingType()->calldataEncodedSize();
|
estimatedReturnSize += retType->decodingType()->calldataEncodedSize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (dynamicReturnSize)
|
||||||
|
solAssert(estimatedReturnSize == 0);
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,14 @@ YulArity YulArity::fromType(FunctionType const& _functionType)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string IRNames::externalFunctionABIWrapper(Declaration const& _functionOrVarDecl)
|
||||||
|
{
|
||||||
|
if (auto const* function = dynamic_cast<FunctionDefinition const*>(&_functionOrVarDecl))
|
||||||
|
solAssert(!function->isConstructor());
|
||||||
|
|
||||||
|
return "external_fun_" + _functionOrVarDecl.name() + "_" + to_string(_functionOrVarDecl.id());
|
||||||
|
}
|
||||||
|
|
||||||
string IRNames::function(FunctionDefinition const& _function)
|
string IRNames::function(FunctionDefinition const& _function)
|
||||||
{
|
{
|
||||||
if (_function.isConstructor())
|
if (_function.isConstructor())
|
||||||
|
@ -49,6 +49,7 @@ struct YulArity
|
|||||||
|
|
||||||
struct IRNames
|
struct IRNames
|
||||||
{
|
{
|
||||||
|
static std::string externalFunctionABIWrapper(Declaration const& _functionOrVardecl);
|
||||||
static std::string function(FunctionDefinition const& _function);
|
static std::string function(FunctionDefinition const& _function);
|
||||||
static std::string function(VariableDeclaration const& _varDecl);
|
static std::string function(VariableDeclaration const& _varDecl);
|
||||||
static std::string modifierInvocation(ModifierInvocation const& _modifierInvocation);
|
static std::string modifierInvocation(ModifierInvocation const& _modifierInvocation);
|
||||||
|
@ -160,8 +160,8 @@ public:
|
|||||||
|
|
||||||
std::set<ContractDefinition const*, ASTNode::CompareByID>& subObjectsCreated() { return m_subObjects; }
|
std::set<ContractDefinition const*, ASTNode::CompareByID>& subObjectsCreated() { return m_subObjects; }
|
||||||
|
|
||||||
bool inlineAssemblySeen() const { return m_inlineAssemblySeen; }
|
bool memoryUnsafeInlineAssemblySeen() const { return m_memoryUnsafeInlineAssemblySeen; }
|
||||||
void setInlineAssemblySeen() { m_inlineAssemblySeen = true; }
|
void setMemoryUnsafeInlineAssemblySeen() { m_memoryUnsafeInlineAssemblySeen = true; }
|
||||||
|
|
||||||
/// @returns the runtime ID to be used for the function in the dispatch routine
|
/// @returns the runtime ID to be used for the function in the dispatch routine
|
||||||
/// and for internal function pointers.
|
/// and for internal function pointers.
|
||||||
@ -202,8 +202,8 @@ private:
|
|||||||
/// Whether to use checked or wrapping arithmetic.
|
/// Whether to use checked or wrapping arithmetic.
|
||||||
Arithmetic m_arithmetic = Arithmetic::Checked;
|
Arithmetic m_arithmetic = Arithmetic::Checked;
|
||||||
|
|
||||||
/// Flag indicating whether any inline assembly block was seen.
|
/// Flag indicating whether any memory-unsafe inline assembly block was seen.
|
||||||
bool m_inlineAssemblySeen = false;
|
bool m_memoryUnsafeInlineAssemblySeen = false;
|
||||||
|
|
||||||
/// Function definitions queued for code generation. They're the Solidity functions whose calls
|
/// Function definitions queued for code generation. They're the Solidity functions whose calls
|
||||||
/// were discovered by the IR generator during AST traversal.
|
/// were discovered by the IR generator during AST traversal.
|
||||||
|
@ -213,8 +213,8 @@ string IRGenerator::generate(
|
|||||||
t("subObjects", subObjectSources(m_context.subObjectsCreated()));
|
t("subObjects", subObjectSources(m_context.subObjectsCreated()));
|
||||||
|
|
||||||
// This has to be called only after all other code generation for the creation object is complete.
|
// This has to be called only after all other code generation for the creation object is complete.
|
||||||
bool creationInvolvesAssembly = m_context.inlineAssemblySeen();
|
bool creationInvolvesMemoryUnsafeAssembly = m_context.memoryUnsafeInlineAssemblySeen();
|
||||||
t("memoryInitCreation", memoryInit(!creationInvolvesAssembly));
|
t("memoryInitCreation", memoryInit(!creationInvolvesMemoryUnsafeAssembly));
|
||||||
t("useSrcMapCreation", formatUseSrcMap(m_context));
|
t("useSrcMapCreation", formatUseSrcMap(m_context));
|
||||||
|
|
||||||
resetContext(_contract, ExecutionContext::Deployed);
|
resetContext(_contract, ExecutionContext::Deployed);
|
||||||
@ -239,8 +239,8 @@ string IRGenerator::generate(
|
|||||||
t("useSrcMapDeployed", formatUseSrcMap(m_context));
|
t("useSrcMapDeployed", formatUseSrcMap(m_context));
|
||||||
|
|
||||||
// This has to be called only after all other code generation for the deployed object is complete.
|
// This has to be called only after all other code generation for the deployed object is complete.
|
||||||
bool deployedInvolvesAssembly = m_context.inlineAssemblySeen();
|
bool deployedInvolvesMemoryUnsafeAssembly = m_context.memoryUnsafeInlineAssemblySeen();
|
||||||
t("memoryInitDeployed", memoryInit(!deployedInvolvesAssembly));
|
t("memoryInitDeployed", memoryInit(!deployedInvolvesMemoryUnsafeAssembly));
|
||||||
|
|
||||||
solAssert(_contract.annotation().creationCallGraph->get() != nullptr, "");
|
solAssert(_contract.annotation().creationCallGraph->get() != nullptr, "");
|
||||||
solAssert(_contract.annotation().deployedCallGraph->get() != nullptr, "");
|
solAssert(_contract.annotation().deployedCallGraph->get() != nullptr, "");
|
||||||
@ -735,6 +735,44 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string IRGenerator::generateExternalFunction(ContractDefinition const& _contract, FunctionType const& _functionType)
|
||||||
|
{
|
||||||
|
string functionName = IRNames::externalFunctionABIWrapper(_functionType.declaration());
|
||||||
|
return m_context.functionCollector().createFunction(functionName, [&](vector<string>&, vector<string>&) -> string {
|
||||||
|
Whiskers t(R"X(
|
||||||
|
<callValueCheck>
|
||||||
|
<?+params>let <params> := </+params> <abiDecode>(4, calldatasize())
|
||||||
|
<?+retParams>let <retParams> := </+retParams> <function>(<params>)
|
||||||
|
let memPos := <allocateUnbounded>()
|
||||||
|
let memEnd := <abiEncode>(memPos <?+retParams>,</+retParams> <retParams>)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
)X");
|
||||||
|
t("callValueCheck", (_functionType.isPayable() || _contract.isLibrary()) ? "" : callValueCheck());
|
||||||
|
|
||||||
|
unsigned paramVars = make_shared<TupleType>(_functionType.parameterTypes())->sizeOnStack();
|
||||||
|
unsigned retVars = make_shared<TupleType>(_functionType.returnParameterTypes())->sizeOnStack();
|
||||||
|
|
||||||
|
ABIFunctions abiFunctions(m_evmVersion, m_context.revertStrings(), m_context.functionCollector());
|
||||||
|
t("abiDecode", abiFunctions.tupleDecoder(_functionType.parameterTypes()));
|
||||||
|
t("params", suffixedVariableNameList("param_", 0, paramVars));
|
||||||
|
t("retParams", suffixedVariableNameList("ret_", 0, retVars));
|
||||||
|
|
||||||
|
if (FunctionDefinition const* funDef = dynamic_cast<FunctionDefinition const*>(&_functionType.declaration()))
|
||||||
|
{
|
||||||
|
solAssert(!funDef->isConstructor());
|
||||||
|
t("function", m_context.enqueueFunctionForCodeGeneration(*funDef));
|
||||||
|
}
|
||||||
|
else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(&_functionType.declaration()))
|
||||||
|
t("function", generateGetter(*varDecl));
|
||||||
|
else
|
||||||
|
solAssert(false, "Unexpected declaration for function!");
|
||||||
|
|
||||||
|
t("allocateUnbounded", m_utils.allocateUnboundedFunction());
|
||||||
|
t("abiEncode", abiFunctions.tupleEncoder(_functionType.returnParameterTypes(), _functionType.returnParameterTypes(), _contract.isLibrary()));
|
||||||
|
return t.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDecl)
|
string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDecl)
|
||||||
{
|
{
|
||||||
IRGeneratorForStatements generator(m_context, m_utils);
|
IRGeneratorForStatements generator(m_context, m_utils);
|
||||||
@ -976,12 +1014,7 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
|||||||
{
|
{
|
||||||
// <functionName>
|
// <functionName>
|
||||||
<delegatecallCheck>
|
<delegatecallCheck>
|
||||||
<callValueCheck>
|
<externalFunction>()
|
||||||
<?+params>let <params> := </+params> <abiDecode>(4, calldatasize())
|
|
||||||
<?+retParams>let <retParams> := </+retParams> <function>(<params>)
|
|
||||||
let memPos := <allocateUnbounded>()
|
|
||||||
let memEnd := <abiEncode>(memPos <?+retParams>,</+retParams> <retParams>)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
</cases>
|
</cases>
|
||||||
default {}
|
default {}
|
||||||
@ -1011,25 +1044,8 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
|||||||
"() }";
|
"() }";
|
||||||
}
|
}
|
||||||
templ["delegatecallCheck"] = delegatecallCheck;
|
templ["delegatecallCheck"] = delegatecallCheck;
|
||||||
templ["callValueCheck"] = (type->isPayable() || _contract.isLibrary()) ? "" : callValueCheck();
|
|
||||||
|
|
||||||
unsigned paramVars = make_shared<TupleType>(type->parameterTypes())->sizeOnStack();
|
templ["externalFunction"] = generateExternalFunction(_contract, *type);
|
||||||
unsigned retVars = make_shared<TupleType>(type->returnParameterTypes())->sizeOnStack();
|
|
||||||
|
|
||||||
ABIFunctions abiFunctions(m_evmVersion, m_context.revertStrings(), m_context.functionCollector());
|
|
||||||
templ["abiDecode"] = abiFunctions.tupleDecoder(type->parameterTypes());
|
|
||||||
templ["params"] = suffixedVariableNameList("param_", 0, paramVars);
|
|
||||||
templ["retParams"] = suffixedVariableNameList("ret_", 0, retVars);
|
|
||||||
|
|
||||||
if (FunctionDefinition const* funDef = dynamic_cast<FunctionDefinition const*>(&type->declaration()))
|
|
||||||
templ["function"] = m_context.enqueueFunctionForCodeGeneration(*funDef);
|
|
||||||
else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(&type->declaration()))
|
|
||||||
templ["function"] = generateGetter(*varDecl);
|
|
||||||
else
|
|
||||||
solAssert(false, "Unexpected declaration for function!");
|
|
||||||
|
|
||||||
templ["allocateUnbounded"] = m_utils.allocateUnboundedFunction();
|
|
||||||
templ["abiEncode"] = abiFunctions.tupleEncoder(type->returnParameterTypes(), type->returnParameterTypes(), _contract.isLibrary());
|
|
||||||
}
|
}
|
||||||
t("cases", functions);
|
t("cases", functions);
|
||||||
FunctionDefinition const* etherReceiver = _contract.receiveFunction();
|
FunctionDefinition const* etherReceiver = _contract.receiveFunction();
|
||||||
|
@ -102,6 +102,9 @@ private:
|
|||||||
/// Generates a getter for the given declaration and returns its name
|
/// Generates a getter for the given declaration and returns its name
|
||||||
std::string generateGetter(VariableDeclaration const& _varDecl);
|
std::string generateGetter(VariableDeclaration const& _varDecl);
|
||||||
|
|
||||||
|
/// Generates the external part (ABI decoding and encoding) of a function or getter.
|
||||||
|
std::string generateExternalFunction(ContractDefinition const& _contract, FunctionType const& _functionType);
|
||||||
|
|
||||||
/// Generates code that assigns the initial value of the respective type.
|
/// Generates code that assigns the initial value of the respective type.
|
||||||
std::string generateInitialAssignment(VariableDeclaration const& _varDecl);
|
std::string generateInitialAssignment(VariableDeclaration const& _varDecl);
|
||||||
|
|
||||||
|
@ -2138,7 +2138,8 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
|
bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
|
||||||
{
|
{
|
||||||
setLocation(_inlineAsm);
|
setLocation(_inlineAsm);
|
||||||
m_context.setInlineAssemblySeen();
|
if (*_inlineAsm.annotation().hasMemoryEffects && !_inlineAsm.annotation().markedMemorySafe)
|
||||||
|
m_context.setMemoryUnsafeInlineAssemblySeen();
|
||||||
CopyTranslate bodyCopier{_inlineAsm.dialect(), m_context, _inlineAsm.annotation().externalReferences};
|
CopyTranslate bodyCopier{_inlineAsm.dialect(), m_context, _inlineAsm.annotation().externalReferences};
|
||||||
|
|
||||||
yul::Statement modified = bodyCopier(_inlineAsm.operations());
|
yul::Statement modified = bodyCopier(_inlineAsm.operations());
|
||||||
@ -2505,6 +2506,8 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
|
|||||||
appendCode() << "mstore(add(" << m_utils.allocateUnboundedFunction() << "() , " << to_string(returnInfo.estimatedReturnSize) << "), 0)\n";
|
appendCode() << "mstore(add(" << m_utils.allocateUnboundedFunction() << "() , " << to_string(returnInfo.estimatedReturnSize) << "), 0)\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: When the expected size of returndata is static, we pass that in to the call opcode and it gets copied automatically.
|
||||||
|
// When it's dynamic, we get zero from estimatedReturnSize() instead and then we need an explicit returndatacopy().
|
||||||
Whiskers templ(R"(
|
Whiskers templ(R"(
|
||||||
<?checkExtcodesize>
|
<?checkExtcodesize>
|
||||||
if iszero(extcodesize(<address>)) { <revertNoCode>() }
|
if iszero(extcodesize(<address>)) { <revertNoCode>() }
|
||||||
@ -2514,22 +2517,29 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
|
|||||||
mstore(<pos>, <shl28>(<funSel>))
|
mstore(<pos>, <shl28>(<funSel>))
|
||||||
let <end> := <encodeArgs>(add(<pos>, 4) <argumentString>)
|
let <end> := <encodeArgs>(add(<pos>, 4) <argumentString>)
|
||||||
|
|
||||||
let <success> := <call>(<gas>, <address>, <?hasValue> <value>, </hasValue> <pos>, sub(<end>, <pos>), <pos>, <reservedReturnSize>)
|
let <success> := <call>(<gas>, <address>, <?hasValue> <value>, </hasValue> <pos>, sub(<end>, <pos>), <pos>, <staticReturndataSize>)
|
||||||
<?noTryCall>
|
<?noTryCall>
|
||||||
if iszero(<success>) { <forwardingRevert>() }
|
if iszero(<success>) { <forwardingRevert>() }
|
||||||
</noTryCall>
|
</noTryCall>
|
||||||
<?+retVars> let <retVars> </+retVars>
|
<?+retVars> let <retVars> </+retVars>
|
||||||
if <success> {
|
if <success> {
|
||||||
<?dynamicReturnSize>
|
<?isReturndataSizeDynamic>
|
||||||
// copy dynamic return data out
|
let <returnDataSizeVar> := returndatasize()
|
||||||
returndatacopy(<pos>, 0, returndatasize())
|
returndatacopy(<pos>, 0, <returnDataSizeVar>)
|
||||||
</dynamicReturnSize>
|
<!isReturndataSizeDynamic>
|
||||||
|
let <returnDataSizeVar> := <staticReturndataSize>
|
||||||
|
<?supportsReturnData>
|
||||||
|
if gt(<returnDataSizeVar>, returndatasize()) {
|
||||||
|
<returnDataSizeVar> := returndatasize()
|
||||||
|
}
|
||||||
|
</supportsReturnData>
|
||||||
|
</isReturndataSizeDynamic>
|
||||||
|
|
||||||
// update freeMemoryPointer according to dynamic return size
|
// update freeMemoryPointer according to dynamic return size
|
||||||
<finalizeAllocation>(<pos>, <returnSize>)
|
<finalizeAllocation>(<pos>, <returnDataSizeVar>)
|
||||||
|
|
||||||
// decode return parameters from external try-call into retVars
|
// decode return parameters from external try-call into retVars
|
||||||
<?+retVars> <retVars> := </+retVars> <abiDecode>(<pos>, add(<pos>, <returnSize>))
|
<?+retVars> <retVars> := </+retVars> <abiDecode>(<pos>, add(<pos>, <returnDataSizeVar>))
|
||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
templ("revertNoCode", m_utils.revertReasonIfDebugFunction("Target contract does not contain code"));
|
templ("revertNoCode", m_utils.revertReasonIfDebugFunction("Target contract does not contain code"));
|
||||||
@ -2558,21 +2568,18 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
|
|||||||
templ("funSel", IRVariable(_functionCall.expression()).part("functionSelector").name());
|
templ("funSel", IRVariable(_functionCall.expression()).part("functionSelector").name());
|
||||||
templ("address", IRVariable(_functionCall.expression()).part("address").name());
|
templ("address", IRVariable(_functionCall.expression()).part("address").name());
|
||||||
|
|
||||||
// Always use the actual return length, and not our calculated expected length, if returndatacopy is supported.
|
if (returnInfo.dynamicReturnSize)
|
||||||
// This ensures it can catch badly formatted input from external calls.
|
solAssert(m_context.evmVersion().supportsReturndata());
|
||||||
if (m_context.evmVersion().supportsReturndata())
|
templ("returnDataSizeVar", m_context.newYulVariable());
|
||||||
templ("returnSize", "returndatasize()");
|
templ("staticReturndataSize", to_string(returnInfo.estimatedReturnSize));
|
||||||
else
|
templ("supportsReturnData", m_context.evmVersion().supportsReturndata());
|
||||||
templ("returnSize", to_string(returnInfo.estimatedReturnSize));
|
|
||||||
|
|
||||||
templ("reservedReturnSize", returnInfo.dynamicReturnSize ? "0" : to_string(returnInfo.estimatedReturnSize));
|
|
||||||
|
|
||||||
string const retVars = IRVariable(_functionCall).commaSeparatedList();
|
string const retVars = IRVariable(_functionCall).commaSeparatedList();
|
||||||
templ("retVars", retVars);
|
templ("retVars", retVars);
|
||||||
solAssert(retVars.empty() == returnInfo.returnTypes.empty());
|
solAssert(retVars.empty() == returnInfo.returnTypes.empty());
|
||||||
|
|
||||||
templ("abiDecode", m_context.abiFunctions().tupleDecoder(returnInfo.returnTypes, true));
|
templ("abiDecode", m_context.abiFunctions().tupleDecoder(returnInfo.returnTypes, true));
|
||||||
templ("dynamicReturnSize", returnInfo.dynamicReturnSize);
|
templ("isReturndataSizeDynamic", returnInfo.dynamicReturnSize);
|
||||||
|
|
||||||
templ("noTryCall", !_functionCall.annotation().tryCall);
|
templ("noTryCall", !_functionCall.annotation().tryCall);
|
||||||
|
|
||||||
|
@ -276,14 +276,8 @@ boost::filesystem::path FileReader::normalizeCLIPathForVFS(
|
|||||||
// If the path is on the same drive as the working dir, for portability we prefer not to
|
// If the path is on the same drive as the working dir, for portability we prefer not to
|
||||||
// include the root name. Do this only for non-UNC paths - my experiments show that on Windows
|
// include the root name. Do this only for non-UNC paths - my experiments show that on Windows
|
||||||
// when the working dir is an UNC path, / does not not actually refer to the root of the UNC path.
|
// when the working dir is an UNC path, / does not not actually refer to the root of the UNC path.
|
||||||
boost::filesystem::path normalizedRootPath = normalizedPath.root_path();
|
|
||||||
if (!isUNCPath(normalizedPath))
|
boost::filesystem::path normalizedRootPath = normalizeCLIRootPathForVFS(normalizedPath, canonicalWorkDir);
|
||||||
{
|
|
||||||
boost::filesystem::path workingDirRootPath = canonicalWorkDir.root_path();
|
|
||||||
// Ignore drive letter case on Windows (C:\ <=> c:\).
|
|
||||||
if (boost::filesystem::equivalent(normalizedRootPath, workingDirRootPath))
|
|
||||||
normalizedRootPath = "/";
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexically_normal() will not squash paths like "/../../" into "/". We have to do it manually.
|
// lexically_normal() will not squash paths like "/../../" into "/". We have to do it manually.
|
||||||
boost::filesystem::path dotDotPrefix = absoluteDotDotPrefix(normalizedPath);
|
boost::filesystem::path dotDotPrefix = absoluteDotDotPrefix(normalizedPath);
|
||||||
@ -308,6 +302,27 @@ boost::filesystem::path FileReader::normalizeCLIPathForVFS(
|
|||||||
return normalizedPathNoDotDot;
|
return normalizedPathNoDotDot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::filesystem::path FileReader::normalizeCLIRootPathForVFS(
|
||||||
|
boost::filesystem::path const& _path,
|
||||||
|
boost::filesystem::path const& _workDir
|
||||||
|
)
|
||||||
|
{
|
||||||
|
solAssert(_workDir.is_absolute(), "");
|
||||||
|
|
||||||
|
boost::filesystem::path absolutePath = boost::filesystem::absolute(_path, _workDir);
|
||||||
|
boost::filesystem::path rootPath = absolutePath.root_path();
|
||||||
|
boost::filesystem::path baseRootPath = _workDir.root_path();
|
||||||
|
|
||||||
|
if (isUNCPath(absolutePath))
|
||||||
|
return rootPath;
|
||||||
|
|
||||||
|
// Ignore drive letter case on Windows (C:\ <=> c:\).
|
||||||
|
if (boost::filesystem::equivalent(rootPath, baseRootPath))
|
||||||
|
return "/";
|
||||||
|
|
||||||
|
return rootPath;
|
||||||
|
}
|
||||||
|
|
||||||
bool FileReader::isPathPrefix(boost::filesystem::path const& _prefix, boost::filesystem::path const& _path)
|
bool FileReader::isPathPrefix(boost::filesystem::path const& _prefix, boost::filesystem::path const& _path)
|
||||||
{
|
{
|
||||||
solAssert(!_prefix.empty() && !_path.empty(), "");
|
solAssert(!_prefix.empty() && !_path.empty(), "");
|
||||||
|
@ -115,6 +115,17 @@ public:
|
|||||||
SymlinkResolution _symlinkResolution = SymlinkResolution::Disabled
|
SymlinkResolution _symlinkResolution = SymlinkResolution::Disabled
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Normalizes a root path by excluding, in some cases, its root name.
|
||||||
|
/// The function is used for better portability, and intended to omit root name
|
||||||
|
/// if the path can be used without it.
|
||||||
|
/// @param _path Path to normalize the root path.
|
||||||
|
/// @param _workDir Current working directory path, must be absolute.
|
||||||
|
/// @returns a normalized root path.
|
||||||
|
static boost::filesystem::path normalizeCLIRootPathForVFS(
|
||||||
|
boost::filesystem::path const& _path,
|
||||||
|
boost::filesystem::path const& _workDir = boost::filesystem::current_path()
|
||||||
|
);
|
||||||
|
|
||||||
/// @returns true if all the path components of @a _prefix are present at the beginning of @a _path.
|
/// @returns true if all the path components of @a _prefix are present at the beginning of @a _path.
|
||||||
/// Both paths must be absolute (or have slash as root) and normalized (no . or .. segments, no
|
/// Both paths must be absolute (or have slash as root) and normalized (no . or .. segments, no
|
||||||
/// multiple consecutive slashes).
|
/// multiple consecutive slashes).
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
#include <libyul/Exceptions.h>
|
#include <libyul/Exceptions.h>
|
||||||
#include <libyul/optimiser/Suite.h>
|
#include <libyul/optimiser/Suite.h>
|
||||||
|
|
||||||
#include <libevmasm/Instruction.h>
|
#include <libevmasm/Disassemble.h>
|
||||||
|
|
||||||
#include <libsmtutil/Exceptions.h>
|
#include <libsmtutil/Exceptions.h>
|
||||||
|
|
||||||
|
@ -1321,13 +1321,28 @@ ASTPointer<InlineAssembly> Parser::parseInlineAssembly(ASTPointer<ASTString> con
|
|||||||
advance();
|
advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASTPointer<vector<ASTPointer<ASTString>>> flags;
|
||||||
|
if (m_scanner->currentToken() == Token::LParen)
|
||||||
|
{
|
||||||
|
flags = make_shared<vector<ASTPointer<ASTString>>>();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
advance();
|
||||||
|
expectToken(Token::StringLiteral, false);
|
||||||
|
flags->emplace_back(make_shared<ASTString>(m_scanner->currentLiteral()));
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
while (m_scanner->currentToken() == Token::Comma);
|
||||||
|
expectToken(Token::RParen);
|
||||||
|
}
|
||||||
|
|
||||||
yul::Parser asmParser(m_errorReporter, dialect);
|
yul::Parser asmParser(m_errorReporter, dialect);
|
||||||
shared_ptr<yul::Block> block = asmParser.parseInline(m_scanner);
|
shared_ptr<yul::Block> block = asmParser.parseInline(m_scanner);
|
||||||
if (block == nullptr)
|
if (block == nullptr)
|
||||||
BOOST_THROW_EXCEPTION(FatalError());
|
BOOST_THROW_EXCEPTION(FatalError());
|
||||||
|
|
||||||
location.end = nativeLocationOf(*block).end;
|
location.end = nativeLocationOf(*block).end;
|
||||||
return make_shared<InlineAssembly>(nextID(), location, _docString, dialect, block);
|
return make_shared<InlineAssembly>(nextID(), location, _docString, dialect, move(flags), block);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTPointer<IfStatement> Parser::parseIfStatement(ASTPointer<ASTString> const& _docString)
|
ASTPointer<IfStatement> Parser::parseIfStatement(ASTPointer<ASTString> const& _docString)
|
||||||
|
@ -309,6 +309,7 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
|
|||||||
literalArguments = &f->literalArguments;
|
literalArguments = &f->literalArguments;
|
||||||
|
|
||||||
validateInstructions(_funCall);
|
validateInstructions(_funCall);
|
||||||
|
m_sideEffects += f->sideEffects;
|
||||||
}
|
}
|
||||||
else if (!m_currentScope->lookup(_funCall.functionName.name, GenericVisitor{
|
else if (!m_currentScope->lookup(_funCall.functionName.name, GenericVisitor{
|
||||||
[&](Scope::Variable const&)
|
[&](Scope::Variable const&)
|
||||||
|
@ -94,6 +94,8 @@ public:
|
|||||||
void operator()(Leave const&) { }
|
void operator()(Leave const&) { }
|
||||||
void operator()(Block const& _block);
|
void operator()(Block const& _block);
|
||||||
|
|
||||||
|
/// @returns the worst side effects encountered during analysis (including within defined functions).
|
||||||
|
SideEffects const& sideEffects() const { return m_sideEffects; }
|
||||||
private:
|
private:
|
||||||
/// Visits the expression, expects that it evaluates to exactly one value and
|
/// Visits the expression, expects that it evaluates to exactly one value and
|
||||||
/// returns the type. Reports errors on errors and returns the default type.
|
/// returns the type. Reports errors on errors and returns the default type.
|
||||||
@ -128,6 +130,8 @@ private:
|
|||||||
/// Names of data objects to be referenced by builtin functions with literal arguments.
|
/// Names of data objects to be referenced by builtin functions with literal arguments.
|
||||||
std::set<YulString> m_dataNames;
|
std::set<YulString> m_dataNames;
|
||||||
ForLoop const* m_currentForLoop = nullptr;
|
ForLoop const* m_currentForLoop = nullptr;
|
||||||
|
/// Worst side effects encountered during analysis (including within defined functions).
|
||||||
|
SideEffects m_sideEffects;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
#include <liblangutil/EVMVersion.h>
|
#include <liblangutil/EVMVersion.h>
|
||||||
|
#include <libsolutil/Numeric.h>
|
||||||
#include <libevmasm/Instruction.h>
|
#include <libevmasm/Instruction.h>
|
||||||
|
|
||||||
namespace solidity::yul
|
namespace solidity::yul
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
#include <libyul/backends/evm/EVMDialect.h>
|
#include <libyul/backends/evm/EVMDialect.h>
|
||||||
#include <libyul/backends/evm/OptimizedEVMCodeTransform.h>
|
#include <libyul/backends/evm/OptimizedEVMCodeTransform.h>
|
||||||
|
|
||||||
|
#include <libyul/optimiser/FunctionCallFinder.h>
|
||||||
|
|
||||||
#include <libyul/Object.h>
|
#include <libyul/Object.h>
|
||||||
#include <libyul/Exceptions.h>
|
#include <libyul/Exceptions.h>
|
||||||
|
|
||||||
@ -74,7 +76,22 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize)
|
|||||||
OptimizedEVMCodeTransform::UseNamedLabels::ForFirstFunctionOfEachName
|
OptimizedEVMCodeTransform::UseNamedLabels::ForFirstFunctionOfEachName
|
||||||
);
|
);
|
||||||
if (!stackErrors.empty())
|
if (!stackErrors.empty())
|
||||||
BOOST_THROW_EXCEPTION(stackErrors.front());
|
{
|
||||||
|
vector<FunctionCall*> memoryGuardCalls = FunctionCallFinder::run(
|
||||||
|
*_object.code,
|
||||||
|
"memoryguard"_yulstring
|
||||||
|
);
|
||||||
|
auto stackError = stackErrors.front();
|
||||||
|
string msg = stackError.comment() ? *stackError.comment() : "";
|
||||||
|
if (memoryGuardCalls.empty())
|
||||||
|
msg += "\nNo memoryguard was present. "
|
||||||
|
"Consider using memory-safe assembly only and annotating it via "
|
||||||
|
"\"/// @solidity memory-safe-assembly\".";
|
||||||
|
else
|
||||||
|
msg += "\nmemoryguard was present.";
|
||||||
|
stackError << util::errinfo_comment(msg);
|
||||||
|
BOOST_THROW_EXCEPTION(stackError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include <libyul/YulString.h>
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <libsolutil/CommonData.h>
|
#include <libsolutil/CommonData.h>
|
||||||
|
#include <libsolutil/Numeric.h>
|
||||||
|
|
||||||
#include <liblangutil/EVMVersion.h>
|
#include <liblangutil/EVMVersion.h>
|
||||||
#include <liblangutil/SourceLocation.h>
|
#include <liblangutil/SourceLocation.h>
|
||||||
|
@ -73,6 +73,7 @@ void UnusedStoreBase::operator()(FunctionDefinition const& _functionDefinition)
|
|||||||
{
|
{
|
||||||
ScopedSaveAndRestore outerAssignments(m_stores, {});
|
ScopedSaveAndRestore outerAssignments(m_stores, {});
|
||||||
ScopedSaveAndRestore forLoopInfo(m_forLoopInfo, {});
|
ScopedSaveAndRestore forLoopInfo(m_forLoopInfo, {});
|
||||||
|
ScopedSaveAndRestore forLoopNestingDepth(m_forLoopNestingDepth, 0);
|
||||||
|
|
||||||
(*this)(_functionDefinition.body);
|
(*this)(_functionDefinition.body);
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# Script used for cross-platform comparison as part of the travis automation.
|
# Script used for cross-platform comparison of the bytecode generated by the compiler.
|
||||||
# Splits all test source code into multiple files, generates bytecode and
|
# Splits all test source code into multiple files, generates bytecode and metadata
|
||||||
# uploads the bytecode into github.com/ethereum/solidity-test-bytecode where
|
# for each file and combines it into a single report.txt file.
|
||||||
# another travis job is triggered to do the actual comparison.
|
#
|
||||||
|
# The script is meant to be executed in CI on all supported platforms. All generated
|
||||||
|
# reports must be identical for a given compiler version.
|
||||||
#
|
#
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# This file is part of solidity.
|
# This file is part of solidity.
|
||||||
|
@ -180,7 +180,7 @@ function diff_values
|
|||||||
shift
|
shift
|
||||||
shift
|
shift
|
||||||
|
|
||||||
diff --color=auto --unified=0 <(echo "$value1") <(echo "$value2") "$@"
|
diff --unified=0 <(echo "$value1") <(echo "$value2") "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
function safe_kill
|
function safe_kill
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
# (c) 2016-2021 solidity contributors.
|
# (c) 2016-2021 solidity contributors.
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
FROM gcr.io/oss-fuzz-base/base-clang:latest as base
|
FROM gcr.io/oss-fuzz-base/base-clang:latest as base
|
||||||
LABEL version="15"
|
LABEL version="16"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ RUN apt-get update; \
|
|||||||
software-properties-common \
|
software-properties-common \
|
||||||
ninja-build git wget \
|
ninja-build git wget \
|
||||||
libbz2-dev zlib1g-dev git curl uuid-dev \
|
libbz2-dev zlib1g-dev git curl uuid-dev \
|
||||||
pkg-config openjdk-8-jdk liblzma-dev unzip mlton m4; \
|
pkg-config openjdk-8-jdk liblzma-dev unzip mlton m4 jq; \
|
||||||
apt-get install -qy python3-pip;
|
apt-get install -qy python3-pip;
|
||||||
|
|
||||||
# Install cmake 3.21.2 (minimum requirement is cmake 3.10)
|
# Install cmake 3.21.2 (minimum requirement is cmake 3.10)
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
# (c) 2016-2019 solidity contributors.
|
# (c) 2016-2019 solidity contributors.
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
FROM buildpack-deps:focal AS base
|
FROM buildpack-deps:focal AS base
|
||||||
LABEL version="10"
|
LABEL version="11"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ RUN set -ex; \
|
|||||||
cmake ninja-build \
|
cmake ninja-build \
|
||||||
libboost-filesystem-dev libboost-test-dev libboost-system-dev \
|
libboost-filesystem-dev libboost-test-dev libboost-system-dev \
|
||||||
libboost-program-options-dev \
|
libboost-program-options-dev \
|
||||||
libcvc4-dev libz3-static-dev z3-static \
|
libcvc4-dev libz3-static-dev z3-static jq \
|
||||||
; \
|
; \
|
||||||
apt-get install -qy python3-pip python3-sphinx; \
|
apt-get install -qy python3-pip python3-sphinx; \
|
||||||
pip3 install codecov; \
|
pip3 install codecov; \
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
# (c) 2016-2019 solidity contributors.
|
# (c) 2016-2019 solidity contributors.
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
FROM buildpack-deps:focal AS base
|
FROM buildpack-deps:focal AS base
|
||||||
LABEL version="10"
|
LABEL version="11"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ RUN set -ex; \
|
|||||||
libboost-filesystem-dev libboost-test-dev libboost-system-dev \
|
libboost-filesystem-dev libboost-test-dev libboost-system-dev \
|
||||||
libboost-program-options-dev \
|
libboost-program-options-dev \
|
||||||
clang \
|
clang \
|
||||||
libz3-static-dev \
|
libz3-static-dev jq \
|
||||||
; \
|
; \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
# ------------------------------------------------------------------------------
|
|
||||||
# This Python script is used within the OS X release process, to ensure
|
|
||||||
# that the standalone OS X ZIP files which we make are actually
|
|
||||||
# standalone, and not implicitly dependent on Homebrew installs for
|
|
||||||
# external libraries which we use.
|
|
||||||
#
|
|
||||||
# This implicit dependencies seem to show up only where we have
|
|
||||||
# external dependencies which are dependent on each other, and the
|
|
||||||
# path from one to another is an absolute path to "/usr/local/opt",
|
|
||||||
# the Homebrew install location. External dependencies which only
|
|
||||||
# depend on system libraries are fine. Our main applications seem
|
|
||||||
# to be fine.
|
|
||||||
#
|
|
||||||
# An example of a dependency which requires this fix-up at the time
|
|
||||||
# of writing is the following dependency edge:
|
|
||||||
#
|
|
||||||
# libjsonrpccpp-client.0.dylib
|
|
||||||
# -> /usr/local/opt/jsoncpp/lib/libjsoncpp.0.dylib
|
|
||||||
#
|
|
||||||
# See https://blogs.oracle.com/dipol/entry/dynamic_libraries_rpath_and_mac
|
|
||||||
# for a little overview of "install_name_tool" and "otool".
|
|
||||||
#
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
# This file is part of solidity.
|
|
||||||
#
|
|
||||||
# solidity is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# solidity is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with solidity. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
#
|
|
||||||
# (c) 2016 solidity contributors.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
def readDependencies(fname):
|
|
||||||
with subprocess.Popen(['otool', '-L', fname], stdout=subprocess.PIPE) as o:
|
|
||||||
for line in o.stdout:
|
|
||||||
if line[0] == '\t':
|
|
||||||
library = line.split(' ', 1)[0][1:]
|
|
||||||
if (library.startswith("/usr/local/lib") or
|
|
||||||
library.startswith("/usr/local/opt") or
|
|
||||||
library.startswith("/Users/")
|
|
||||||
):
|
|
||||||
if os.path.basename(library) != os.path.basename(fname):
|
|
||||||
command = "install_name_tool -change " + \
|
|
||||||
library + " @executable_path/./" + \
|
|
||||||
os.path.basename(library) + " " + fname
|
|
||||||
print(command)
|
|
||||||
os.system("chmod +w " + fname)
|
|
||||||
os.system(command)
|
|
||||||
|
|
||||||
root = sys.argv[1]
|
|
||||||
for (dirpath, dirnames, filenames) in os.walk(root):
|
|
||||||
for filename in filenames:
|
|
||||||
readDependencies(os.path.join(root, filename))
|
|
@ -1,38 +0,0 @@
|
|||||||
@ECHO OFF
|
|
||||||
|
|
||||||
REM ---------------------------------------------------------------------------
|
|
||||||
REM Batch file for implementing release flow for solidity for Windows.
|
|
||||||
REM
|
|
||||||
REM The documentation for solidity is hosted at:
|
|
||||||
REM
|
|
||||||
REM https://docs.soliditylang.org
|
|
||||||
REM
|
|
||||||
REM ---------------------------------------------------------------------------
|
|
||||||
REM This file is part of solidity.
|
|
||||||
REM
|
|
||||||
REM solidity is free software: you can redistribute it and/or modify
|
|
||||||
REM it under the terms of the GNU General Public License as published by
|
|
||||||
REM the Free Software Foundation, either version 3 of the License, or
|
|
||||||
REM (at your option) any later version.
|
|
||||||
REM
|
|
||||||
REM solidity is distributed in the hope that it will be useful,
|
|
||||||
REM but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
REM GNU General Public License for more details.
|
|
||||||
REM
|
|
||||||
REM You should have received a copy of the GNU General Public License
|
|
||||||
REM along with solidity. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
REM
|
|
||||||
REM Copyright (c) 2016 solidity contributors.
|
|
||||||
REM ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
set CONFIGURATION=%1
|
|
||||||
set VERSION=%2
|
|
||||||
|
|
||||||
set "DLLS=MSVC_DLLS_NOT_FOUND"
|
|
||||||
FOR /d %%d IN ("C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Redist\MSVC\*"
|
|
||||||
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Redist\MSVC\*") DO set "DLLS=%%d\x86\Microsoft.VC141.CRT\msvc*.dll"
|
|
||||||
|
|
||||||
7z a solidity-windows.zip ^
|
|
||||||
.\build\solc\%CONFIGURATION%\solc.exe .\build\test\%CONFIGURATION%\soltest.exe ^
|
|
||||||
"%DLLS%"
|
|
@ -1,56 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
|
||||||
# Bash script implementing release flow for solidity for Linux and macOS.
|
|
||||||
#
|
|
||||||
# TODO - At the time of writing, we only have ZIPs working. Need to hook up
|
|
||||||
# support for Homebrew and PPAs.
|
|
||||||
#
|
|
||||||
# The documentation for solidity is hosted at:
|
|
||||||
#
|
|
||||||
# https://docs.soliditylang.org
|
|
||||||
#
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
# This file is part of solidity.
|
|
||||||
#
|
|
||||||
# solidity is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# solidity is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with solidity. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
#
|
|
||||||
# (c) 2016 solidity contributors.
|
|
||||||
#------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
ZIP_SUFFIX="$1"
|
|
||||||
ZIP_TEMP_DIR="$(pwd)/build/zip/"
|
|
||||||
|
|
||||||
# There is an implicit assumption here that we HAVE to run from root directory.
|
|
||||||
REPO_ROOT=$(pwd)
|
|
||||||
|
|
||||||
mkdir -p "$ZIP_TEMP_DIR"
|
|
||||||
|
|
||||||
# Copy all the solidity executables into a temporary directory prior to ZIP creation
|
|
||||||
|
|
||||||
cp "$REPO_ROOT/build/solc/solc" "$ZIP_TEMP_DIR"
|
|
||||||
|
|
||||||
# For macOS, we run a fix-up script which alters all of the symbolic links within
|
|
||||||
# the executables and dynamic libraries such that the ZIP becomes self-contained, by
|
|
||||||
# revectoring all the dylib references to be relative to the directory containing the
|
|
||||||
# application, so that the ZIPs are self-contained, with the only external references
|
|
||||||
# being for kernel-level dylibs.
|
|
||||||
|
|
||||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
||||||
python3 "$REPO_ROOT/scripts/fix_homebrew_paths_in_standalone_zip.py" "$ZIP_TEMP_DIR"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# And ZIP it all up, with a filename suffix passed in on the command-line.
|
|
||||||
mkdir -p "$REPO_ROOT/upload"
|
|
||||||
zip -j "$REPO_ROOT/upload/solidity-$ZIP_SUFFIX.zip" "$ZIP_TEMP_DIR/"*
|
|
@ -55,9 +55,9 @@ keyid=379F4801D622CDCF
|
|||||||
email=builds@ethereum.org
|
email=builds@ethereum.org
|
||||||
packagename=solc
|
packagename=solc
|
||||||
|
|
||||||
static_build_distribution=hirsute
|
static_build_distribution=impish
|
||||||
|
|
||||||
DISTRIBUTIONS="focal hirsute impish jammy"
|
DISTRIBUTIONS="focal impish jammy"
|
||||||
|
|
||||||
if is_release
|
if is_release
|
||||||
then
|
then
|
||||||
|
@ -45,7 +45,7 @@ set +e
|
|||||||
if [ -e scripts/ci/build_emscripten.sh ]; then
|
if [ -e scripts/ci/build_emscripten.sh ]; then
|
||||||
scripts/ci/build_emscripten.sh
|
scripts/ci/build_emscripten.sh
|
||||||
else
|
else
|
||||||
# The script used to be in scripts/ci/ in earlier versions.
|
# The script used to be in scripts/travis-emscripten/ in earlier versions.
|
||||||
scripts/travis-emscripten/build_emscripten.sh
|
scripts/travis-emscripten/build_emscripten.sh
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ done
|
|||||||
SOLIDITY_REPO_URL="https://github.com/ethereum/solidity"
|
SOLIDITY_REPO_URL="https://github.com/ethereum/solidity"
|
||||||
SOLC_JS_REPO_URL="https://github.com/ethereum/solc-js"
|
SOLC_JS_REPO_URL="https://github.com/ethereum/solc-js"
|
||||||
SOLC_JS_BRANCH=wasmRebuildTests
|
SOLC_JS_BRANCH=wasmRebuildTests
|
||||||
RELEASE_URL="https://raw.githubusercontent.com/ethereum/solc-bin/gh-pages/bin"
|
RELEASE_URL="https://binaries.soliditylang.org/bin"
|
||||||
RELEASE_COMMIT_LIST_URL="$RELEASE_URL/list.txt"
|
RELEASE_COMMIT_LIST_URL="$RELEASE_URL/list.txt"
|
||||||
|
|
||||||
SCRIPTDIR=$(dirname "$0")
|
SCRIPTDIR=$(dirname "$0")
|
||||||
@ -196,6 +196,7 @@ cp scripts/bytecodecompare/storebytecode.sh /tmp
|
|||||||
# shellcheck disable=SC2016
|
# shellcheck disable=SC2016
|
||||||
sed -i -e 's/rm -rf "\$TMPDIR"/cp "\$TMPDIR"\/report.txt \/tmp\/report.txt ; rm -rf "\$TMPDIR"/' /tmp/storebytecode.sh
|
sed -i -e 's/rm -rf "\$TMPDIR"/cp "\$TMPDIR"\/report.txt \/tmp\/report.txt ; rm -rf "\$TMPDIR"/' /tmp/storebytecode.sh
|
||||||
sed -i -e 's/REPO_ROOT=.*/REPO_ROOT=\/src/' /tmp/storebytecode.sh
|
sed -i -e 's/REPO_ROOT=.*/REPO_ROOT=\/src/' /tmp/storebytecode.sh
|
||||||
|
sed -i -e 's/git clone/git clone --branch '"${SOLC_JS_BRANCH}"'/' /tmp/storebytecode.sh
|
||||||
export SOLC_EMSCRIPTEN="On"
|
export SOLC_EMSCRIPTEN="On"
|
||||||
|
|
||||||
echo "Check out solc-js repository..."
|
echo "Check out solc-js repository..."
|
||||||
@ -213,7 +214,9 @@ ln -sf /emsdk_portable/emscripten/bin/* /usr/local/bin
|
|||||||
rm -rf /src
|
rm -rf /src
|
||||||
ln -sf /root/project /src
|
ln -sf /root/project /src
|
||||||
|
|
||||||
|
echo "Install dependencies and upgrade system packages."
|
||||||
apt-get -qq update >/dev/null 2>&1
|
apt-get -qq update >/dev/null 2>&1
|
||||||
|
apt-get -qq upgrade >/dev/null 2>&1
|
||||||
apt-get -qq install cmake >/dev/null 2>&1
|
apt-get -qq install cmake >/dev/null 2>&1
|
||||||
|
|
||||||
echo "Create output directories."
|
echo "Create output directories."
|
||||||
@ -228,7 +231,6 @@ mkdir -p "${OUTPUTDIR}"/bin
|
|||||||
echo "Prepare solc-js."
|
echo "Prepare solc-js."
|
||||||
cd /root/solc-js
|
cd /root/solc-js
|
||||||
npm install >/dev/null 2>&1
|
npm install >/dev/null 2>&1
|
||||||
npm run build >/dev/null 2>&1
|
|
||||||
|
|
||||||
echo "Install semver helper."
|
echo "Install semver helper."
|
||||||
npm install -g semver >/dev/null 2>&1
|
npm install -g semver >/dev/null 2>&1
|
||||||
@ -238,6 +240,7 @@ wget -q "${RELEASE_COMMIT_LIST_URL}" -O /tmp/release_commit_list.txt
|
|||||||
|
|
||||||
cd /src
|
cd /src
|
||||||
TAGS=$(git tag --list "${TAG_FILTER}" | tac)
|
TAGS=$(git tag --list "${TAG_FILTER}" | tac)
|
||||||
|
echo "Matching tags: ${TAGS}"
|
||||||
for TAG in ${TAGS}; do
|
for TAG in ${TAGS}; do
|
||||||
process_tag "${TAG}"
|
process_tag "${TAG}"
|
||||||
done
|
done
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
#include <libyul/AssemblyStack.h>
|
#include <libyul/AssemblyStack.h>
|
||||||
|
|
||||||
#include <libevmasm/Instruction.h>
|
#include <libevmasm/Instruction.h>
|
||||||
|
#include <libevmasm/Disassemble.h>
|
||||||
#include <libevmasm/GasMeter.h>
|
#include <libevmasm/GasMeter.h>
|
||||||
|
|
||||||
#include <liblangutil/Exceptions.h>
|
#include <liblangutil/Exceptions.h>
|
||||||
|
@ -83,6 +83,8 @@ set(libsolidity_sources
|
|||||||
libsolidity/InlineAssembly.cpp
|
libsolidity/InlineAssembly.cpp
|
||||||
libsolidity/LibSolc.cpp
|
libsolidity/LibSolc.cpp
|
||||||
libsolidity/Metadata.cpp
|
libsolidity/Metadata.cpp
|
||||||
|
libsolidity/MemoryGuardTest.cpp
|
||||||
|
libsolidity/MemoryGuardTest.h
|
||||||
libsolidity/SemanticTest.cpp
|
libsolidity/SemanticTest.cpp
|
||||||
libsolidity/SemanticTest.h
|
libsolidity/SemanticTest.h
|
||||||
libsolidity/SemVerMatcher.cpp
|
libsolidity/SemVerMatcher.cpp
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <libsolutil/Exceptions.h>
|
#include <libsolutil/Exceptions.h>
|
||||||
#include <liblangutil/EVMVersion.h>
|
#include <liblangutil/EVMVersion.h>
|
||||||
#include <liblangutil/Exceptions.h>
|
#include <liblangutil/Exceptions.h>
|
||||||
|
#include <libsolutil/Numeric.h>
|
||||||
|
|
||||||
#include <test/evmc/evmc.h>
|
#include <test/evmc/evmc.h>
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ static constexpr auto heraFilename = "libhera.so";
|
|||||||
static constexpr auto heraDownloadLink = "https://github.com/ewasm/hera/releases/download/v0.5.0/hera-0.5.0-linux-x86_64.tar.gz";
|
static constexpr auto heraDownloadLink = "https://github.com/ewasm/hera/releases/download/v0.5.0/hera-0.5.0-linux-x86_64.tar.gz";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct ConfigException : public util::Exception {};
|
struct ConfigException: public util::Exception {};
|
||||||
|
|
||||||
struct CommonOptions
|
struct CommonOptions
|
||||||
{
|
{
|
||||||
|
@ -266,7 +266,7 @@ h160 ExecutionFramework::logAddress(size_t _logIdx) const
|
|||||||
|
|
||||||
bytes ExecutionFramework::logData(size_t _logIdx) const
|
bytes ExecutionFramework::logData(size_t _logIdx) const
|
||||||
{
|
{
|
||||||
const auto& data = m_evmcHost->recorded_logs.at(_logIdx).data;
|
auto const& data = m_evmcHost->recorded_logs.at(_logIdx).data;
|
||||||
// TODO: Return a copy of log data, because this is expected from REQUIRE_LOG_DATA(),
|
// TODO: Return a copy of log data, because this is expected from REQUIRE_LOG_DATA(),
|
||||||
// but reference type like string_view would be preferable.
|
// but reference type like string_view would be preferable.
|
||||||
return {data.begin(), data.end()};
|
return {data.begin(), data.end()};
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <test/libsolidity/ABIJsonTest.h>
|
#include <test/libsolidity/ABIJsonTest.h>
|
||||||
#include <test/libsolidity/ASTJSONTest.h>
|
#include <test/libsolidity/ASTJSONTest.h>
|
||||||
#include <test/libsolidity/GasTest.h>
|
#include <test/libsolidity/GasTest.h>
|
||||||
|
#include <test/libsolidity/MemoryGuardTest.h>
|
||||||
#include <test/libsolidity/SyntaxTest.h>
|
#include <test/libsolidity/SyntaxTest.h>
|
||||||
#include <test/libsolidity/SemanticTest.h>
|
#include <test/libsolidity/SemanticTest.h>
|
||||||
#include <test/libsolidity/SMTCheckerTest.h>
|
#include <test/libsolidity/SMTCheckerTest.h>
|
||||||
@ -74,6 +75,7 @@ Testsuite const g_interactiveTestsuites[] = {
|
|||||||
{"JSON ABI", "libsolidity", "ABIJson", false, false, &ABIJsonTest::create},
|
{"JSON ABI", "libsolidity", "ABIJson", false, false, &ABIJsonTest::create},
|
||||||
{"SMT Checker", "libsolidity", "smtCheckerTests", true, false, &SMTCheckerTest::create},
|
{"SMT Checker", "libsolidity", "smtCheckerTests", true, false, &SMTCheckerTest::create},
|
||||||
{"Gas Estimates", "libsolidity", "gasTests", false, false, &GasTest::create},
|
{"Gas Estimates", "libsolidity", "gasTests", false, false, &GasTest::create},
|
||||||
|
{"Memory Guard Tests", "libsolidity", "memoryGuardTests", false, false, &MemoryGuardTest::create},
|
||||||
{"Ewasm Translation", "libyul", "ewasmTranslationTests", false, false, &yul::test::EwasmTranslationTest::create}
|
{"Ewasm Translation", "libyul", "ewasmTranslationTests", false, false, &yul::test::EwasmTranslationTest::create}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,14 +11,15 @@ object "C_12" {
|
|||||||
code {
|
code {
|
||||||
{
|
{
|
||||||
/// @src 0:61:418 "contract C {..."
|
/// @src 0:61:418 "contract C {..."
|
||||||
mstore(64, 128)
|
let _1 := memoryguard(0x80)
|
||||||
|
mstore(64, _1)
|
||||||
if callvalue() { revert(0, 0) }
|
if callvalue() { revert(0, 0) }
|
||||||
/// @src 0:103:238 "assembly {..."
|
/// @src 0:103:238 "assembly {..."
|
||||||
sstore(0, shl(180, 1))
|
sstore(0, shl(180, 1))
|
||||||
/// @src 0:61:418 "contract C {..."
|
/// @src 0:61:418 "contract C {..."
|
||||||
let _1 := datasize("C_12_deployed")
|
let _2 := datasize("C_12_deployed")
|
||||||
codecopy(128, dataoffset("C_12_deployed"), _1)
|
codecopy(_1, dataoffset("C_12_deployed"), _2)
|
||||||
return(128, _1)
|
return(_1, _2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// @use-src 0:"constant_optimizer_yul/input.sol"
|
/// @use-src 0:"constant_optimizer_yul/input.sol"
|
||||||
@ -26,7 +27,7 @@ object "C_12" {
|
|||||||
code {
|
code {
|
||||||
{
|
{
|
||||||
/// @src 0:61:418 "contract C {..."
|
/// @src 0:61:418 "contract C {..."
|
||||||
mstore(64, 128)
|
mstore(64, memoryguard(0x80))
|
||||||
if callvalue() { revert(0, 0) }
|
if callvalue() { revert(0, 0) }
|
||||||
/// @src 0:279:410 "assembly {..."
|
/// @src 0:279:410 "assembly {..."
|
||||||
sstore(0, 0x1000000000000000000000000000000000000000000000)
|
sstore(0, 0x1000000000000000000000000000000000000000000000)
|
||||||
|
@ -108,12 +108,7 @@ object "C_6" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_5()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
fun_f_5()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -150,6 +145,17 @@ object "C_6" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_5() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
fun_f_5()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
|
@ -108,12 +108,7 @@ object "C_6" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_5()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
fun_f_5()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -150,6 +145,17 @@ object "C_6" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_5() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
fun_f_5()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
|
@ -101,12 +101,7 @@ object "C_6" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_5()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
fun_f_5()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -143,6 +138,17 @@ object "C_6" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_5() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
fun_f_5()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
|
@ -158,12 +158,7 @@ object "D_27" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_26()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
let ret_0 := fun_f_26()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -238,6 +233,17 @@ object "D_27" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_26() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
let ret_0 := fun_f_26()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
@ -484,7 +490,7 @@ object "D_27" {
|
|||||||
revert(pos, returndatasize())
|
revert(pos, returndatasize())
|
||||||
}
|
}
|
||||||
mstore(add(allocate_memory_array_string(), 32), "/*")
|
mstore(add(allocate_memory_array_string(), 32), "/*")
|
||||||
let memPtr := allocate_memory_array_string_480()
|
let memPtr := allocate_memory_array_string_546()
|
||||||
mstore(add(memPtr, 32), 0x2f2a2a204073726320303a39363a313635202022636f6e74726163742044207b)
|
mstore(add(memPtr, 32), 0x2f2a2a204073726320303a39363a313635202022636f6e74726163742044207b)
|
||||||
mstore(add(memPtr, 64), shl(200, 0x2e2e2e22202a2f))
|
mstore(add(memPtr, 64), shl(200, 0x2e2e2e22202a2f))
|
||||||
let memPos := mload(64)
|
let memPos := mload(64)
|
||||||
@ -525,7 +531,7 @@ object "D_27" {
|
|||||||
memPtr := memPtr_1
|
memPtr := memPtr_1
|
||||||
mstore(memPtr_1, 2)
|
mstore(memPtr_1, 2)
|
||||||
}
|
}
|
||||||
function allocate_memory_array_string_480() -> memPtr
|
function allocate_memory_array_string_546() -> memPtr
|
||||||
{
|
{
|
||||||
let memPtr_1 := mload(64)
|
let memPtr_1 := mload(64)
|
||||||
let newFreePtr := add(memPtr_1, 96)
|
let newFreePtr := add(memPtr_1, 96)
|
||||||
|
@ -53,12 +53,7 @@ object "C_81" {
|
|||||||
{
|
{
|
||||||
// f(uint256,uint256,uint256,uint256)
|
// f(uint256,uint256,uint256,uint256)
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_80()
|
||||||
let param_0, param_1, param_2, param_3 := abi_decode_tuple_t_uint256t_uint256t_uint256t_uint256(4, calldatasize())
|
|
||||||
let ret_0, ret_1, ret_2, ret_3 := fun_f_80(param_0, param_1, param_2, param_3)
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple_t_uint256_t_int256_t_uint256_t_uint256__to_t_uint256_t_int256_t_uint256_t_uint256__fromStack(memPos , ret_0, ret_1, ret_2, ret_3)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -160,6 +155,17 @@ object "C_81" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_80() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
let param_0, param_1, param_2, param_3 := abi_decode_tuple_t_uint256t_uint256t_uint256t_uint256(4, calldatasize())
|
||||||
|
let ret_0, ret_1, ret_2, ret_3 := fun_f_80(param_0, param_1, param_2, param_3)
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple_t_uint256_t_int256_t_uint256_t_uint256__to_t_uint256_t_int256_t_uint256_t_uint256__fromStack(memPos , ret_0, ret_1, ret_2, ret_3)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,6 @@ pragma solidity >=0.0.0;
|
|||||||
pragma abicoder v2;
|
pragma abicoder v2;
|
||||||
|
|
||||||
contract D {
|
contract D {
|
||||||
constructor() { assembly {}}
|
constructor() { assembly { mstore(0,0) } }
|
||||||
function f() public pure {}
|
function f() public pure {}
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,12 @@ Optimized IR:
|
|||||||
object "D_12" {
|
object "D_12" {
|
||||||
code {
|
code {
|
||||||
{
|
{
|
||||||
/// @src 0:82:161 "contract D {..."
|
/// @src 0:82:175 "contract D {..."
|
||||||
mstore(64, 128)
|
mstore(64, 128)
|
||||||
if callvalue() { revert(0, 0) }
|
if callvalue() { revert(0, 0) }
|
||||||
|
/// @src 0:115:139 "assembly { mstore(0,0) }"
|
||||||
|
mstore(0, 0)
|
||||||
|
/// @src 0:82:175 "contract D {..."
|
||||||
let _1 := datasize("D_12_deployed")
|
let _1 := datasize("D_12_deployed")
|
||||||
codecopy(128, dataoffset("D_12_deployed"), _1)
|
codecopy(128, dataoffset("D_12_deployed"), _1)
|
||||||
return(128, _1)
|
return(128, _1)
|
||||||
@ -22,7 +25,7 @@ object "D_12" {
|
|||||||
object "D_12_deployed" {
|
object "D_12_deployed" {
|
||||||
code {
|
code {
|
||||||
{
|
{
|
||||||
/// @src 0:82:161 "contract D {..."
|
/// @src 0:82:175 "contract D {..."
|
||||||
let _1 := memoryguard(0x80)
|
let _1 := memoryguard(0x80)
|
||||||
mstore(64, _1)
|
mstore(64, _1)
|
||||||
if iszero(lt(calldatasize(), 4))
|
if iszero(lt(calldatasize(), 4))
|
||||||
|
@ -4,6 +4,6 @@ pragma abicoder v2;
|
|||||||
|
|
||||||
contract D {
|
contract D {
|
||||||
function f() public pure {
|
function f() public pure {
|
||||||
assembly {}
|
assembly { mstore(0,0) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ Optimized IR:
|
|||||||
object "D_8" {
|
object "D_8" {
|
||||||
code {
|
code {
|
||||||
{
|
{
|
||||||
/// @src 0:82:153 "contract D {..."
|
/// @src 0:82:166 "contract D {..."
|
||||||
let _1 := memoryguard(0x80)
|
let _1 := memoryguard(0x80)
|
||||||
mstore(64, _1)
|
mstore(64, _1)
|
||||||
if callvalue() { revert(0, 0) }
|
if callvalue() { revert(0, 0) }
|
||||||
@ -23,7 +23,7 @@ object "D_8" {
|
|||||||
object "D_8_deployed" {
|
object "D_8_deployed" {
|
||||||
code {
|
code {
|
||||||
{
|
{
|
||||||
/// @src 0:82:153 "contract D {..."
|
/// @src 0:82:166 "contract D {..."
|
||||||
mstore(64, 128)
|
mstore(64, 128)
|
||||||
if iszero(lt(calldatasize(), 4))
|
if iszero(lt(calldatasize(), 4))
|
||||||
{
|
{
|
||||||
@ -32,6 +32,8 @@ object "D_8" {
|
|||||||
{
|
{
|
||||||
if callvalue() { revert(_1, _1) }
|
if callvalue() { revert(_1, _1) }
|
||||||
if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) }
|
if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) }
|
||||||
|
/// @src 0:134:158 "assembly { mstore(0,0) }"
|
||||||
|
mstore(/** @src 0:82:166 "contract D {..." */ _1, _1)
|
||||||
return(128, _1)
|
return(128, _1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ object "C_59" {
|
|||||||
for { } lt(src, srcEnd) { src := add(src, _2) }
|
for { } lt(src, srcEnd) { src := add(src, _2) }
|
||||||
{
|
{
|
||||||
if slt(sub(calldatasize(), src), _2) { revert(_1, _1) }
|
if slt(sub(calldatasize(), src), _2) { revert(_1, _1) }
|
||||||
let value := allocate_memory_1172()
|
let value := allocate_memory_1307()
|
||||||
mstore(value, calldataload(src))
|
mstore(value, calldataload(src))
|
||||||
mstore(dst, value)
|
mstore(dst, value)
|
||||||
dst := add(dst, _2)
|
dst := add(dst, _2)
|
||||||
@ -68,7 +68,7 @@ object "C_59" {
|
|||||||
mstore(4, 0x41)
|
mstore(4, 0x41)
|
||||||
revert(0, 0x24)
|
revert(0, 0x24)
|
||||||
}
|
}
|
||||||
function allocate_memory_1172() -> memPtr
|
function allocate_memory_1307() -> memPtr
|
||||||
{
|
{
|
||||||
memPtr := mload(64)
|
memPtr := mload(64)
|
||||||
let newFreePtr := add(memPtr, 32)
|
let newFreePtr := add(memPtr, 32)
|
||||||
|
@ -68,12 +68,7 @@ object "C_15" {
|
|||||||
{
|
{
|
||||||
// f(uint256[][],uint8)
|
// f(uint256[][],uint8)
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_14()
|
||||||
let param_0, param_1 := abi_decode_tuple_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptrt_enum$_E_$3(4, calldatasize())
|
|
||||||
fun_f_14(param_0, param_1)
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -338,6 +333,17 @@ object "C_15" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_14() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
let param_0, param_1 := abi_decode_tuple_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptrt_enum$_E_$3(4, calldatasize())
|
||||||
|
fun_f_14(param_0, param_1)
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
|
|
||||||
let start := allocate_unbounded()
|
let start := allocate_unbounded()
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -114,12 +114,7 @@ object \"C_6\" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_5()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
fun_f_5()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -156,6 +151,17 @@ object \"C_6\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_5() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
fun_f_5()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
|
@ -114,12 +114,7 @@ object \"C_6\" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_5()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
fun_f_5()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -156,6 +151,17 @@ object \"C_6\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_5() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
fun_f_5()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
|
@ -107,12 +107,7 @@ object \"C_6\" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_5()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
fun_f_5()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -149,6 +144,17 @@ object \"C_6\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_5() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
fun_f_5()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
|
@ -172,48 +172,28 @@ object \"C_54\" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_30()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
let ret_0 := fun_f_30()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x793816ec
|
case 0x793816ec
|
||||||
{
|
{
|
||||||
// stateVar()
|
// stateVar()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_stateVar_10()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
let ret_0 := getter_fun_stateVar_10()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x9942ec6f
|
case 0x9942ec6f
|
||||||
{
|
{
|
||||||
// f2()
|
// f2()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f2_53()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
let ret_0 := fun_f2_53()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xa00b982b
|
case 0xa00b982b
|
||||||
{
|
{
|
||||||
// constVar()
|
// constVar()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_constVar_5()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
let ret_0 := getter_fun_constVar_5()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -260,6 +240,17 @@ object \"C_54\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_30() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
let ret_0 := fun_f_30()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function shift_right_unsigned_dynamic(bits, value) -> newValue {
|
function shift_right_unsigned_dynamic(bits, value) -> newValue {
|
||||||
newValue :=
|
newValue :=
|
||||||
|
|
||||||
@ -292,6 +283,28 @@ object \"C_54\" {
|
|||||||
}
|
}
|
||||||
/// @src 0:79:435 \"contract C...\"
|
/// @src 0:79:435 \"contract C...\"
|
||||||
|
|
||||||
|
function external_fun_stateVar_10() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
let ret_0 := getter_fun_stateVar_10()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function external_fun_f2_53() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
let ret_0 := fun_f2_53()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function cleanup_t_rational_41_by_1(value) -> cleaned {
|
function cleanup_t_rational_41_by_1(value) -> cleaned {
|
||||||
cleaned := value
|
cleaned := value
|
||||||
}
|
}
|
||||||
@ -320,6 +333,17 @@ object \"C_54\" {
|
|||||||
}
|
}
|
||||||
/// @src 0:79:435 \"contract C...\"
|
/// @src 0:79:435 \"contract C...\"
|
||||||
|
|
||||||
|
function external_fun_constVar_5() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
let ret_0 := getter_fun_constVar_5()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
@ -539,18 +563,24 @@ object \"C_54\" {
|
|||||||
let expr_47
|
let expr_47
|
||||||
if _12 {
|
if _12 {
|
||||||
|
|
||||||
|
let _13 := 32
|
||||||
|
|
||||||
|
if gt(_13, returndatasize()) {
|
||||||
|
_13 := returndatasize()
|
||||||
|
}
|
||||||
|
|
||||||
// update freeMemoryPointer according to dynamic return size
|
// update freeMemoryPointer according to dynamic return size
|
||||||
finalize_allocation(_10, returndatasize())
|
finalize_allocation(_10, _13)
|
||||||
|
|
||||||
// decode return parameters from external try-call into retVars
|
// decode return parameters from external try-call into retVars
|
||||||
expr_47 := abi_decode_tuple_t_int256_fromMemory(_10, add(_10, returndatasize()))
|
expr_47 := abi_decode_tuple_t_int256_fromMemory(_10, add(_10, _13))
|
||||||
}
|
}
|
||||||
/// @src 0:399:418 \"stateVar + this.f()\"
|
/// @src 0:399:418 \"stateVar + this.f()\"
|
||||||
let expr_48 := checked_add_t_int256(expr_44, expr_47)
|
let expr_48 := checked_add_t_int256(expr_44, expr_47)
|
||||||
|
|
||||||
/// @src 0:421:429 \"immutVar\"
|
/// @src 0:421:429 \"immutVar\"
|
||||||
let _13 := loadimmutable(\"8\")
|
let _14 := loadimmutable(\"8\")
|
||||||
let expr_49 := _13
|
let expr_49 := _14
|
||||||
/// @src 0:399:429 \"stateVar + this.f() + immutVar\"
|
/// @src 0:399:429 \"stateVar + this.f() + immutVar\"
|
||||||
let expr_50 := checked_add_t_int256(expr_48, expr_49)
|
let expr_50 := checked_add_t_int256(expr_48, expr_49)
|
||||||
|
|
||||||
@ -638,62 +668,99 @@ object \"C_54\" {
|
|||||||
switch shr(224, calldataload(_1))
|
switch shr(224, calldataload(_1))
|
||||||
case 0x26121ff0 {
|
case 0x26121ff0 {
|
||||||
if callvalue() { revert(_1, _1) }
|
if callvalue() { revert(_1, _1) }
|
||||||
abi_decode(calldatasize())
|
if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) }
|
||||||
let ret := /** @src 0:286:305 \"constVar + immutVar\" */ checked_add_int256_556(/** @src 0:297:305 \"immutVar\" */ loadimmutable(\"8\"))
|
/// @src 0:297:305 \"immutVar\"
|
||||||
|
let _2 := loadimmutable(\"8\")
|
||||||
/// @src 0:79:435 \"contract C...\"
|
/// @src 0:79:435 \"contract C...\"
|
||||||
|
if and(1, sgt(_2, sub(shl(255, 1), 42))) { panic_error_0x11() }
|
||||||
let memPos := mload(64)
|
let memPos := mload(64)
|
||||||
return(memPos, sub(abi_encode_int256(memPos, ret), memPos))
|
mstore(memPos, add(/** @src 0:124:126 \"41\" */ 0x29, /** @src 0:79:435 \"contract C...\" */ _2))
|
||||||
}
|
return(memPos, 32)
|
||||||
case 0x793816ec {
|
|
||||||
if callvalue() { revert(_1, _1) }
|
|
||||||
abi_decode(calldatasize())
|
|
||||||
let ret_1 := sload(_1)
|
|
||||||
let memPos_1 := mload(64)
|
|
||||||
return(memPos_1, sub(abi_encode_int256(memPos_1, ret_1), memPos_1))
|
|
||||||
}
|
|
||||||
case 0x9942ec6f {
|
|
||||||
if callvalue() { revert(_1, _1) }
|
|
||||||
abi_decode(calldatasize())
|
|
||||||
let ret_2 := /** @src 0:382:385 \"int\" */ modifier_m()
|
|
||||||
/// @src 0:79:435 \"contract C...\"
|
|
||||||
let memPos_2 := mload(64)
|
|
||||||
return(memPos_2, sub(abi_encode_int256(memPos_2, ret_2), memPos_2))
|
|
||||||
}
|
|
||||||
case 0xa00b982b {
|
|
||||||
if callvalue() { revert(_1, _1) }
|
|
||||||
abi_decode(calldatasize())
|
|
||||||
let memPos_3 := mload(64)
|
|
||||||
return(memPos_3, sub(abi_encode_int256_555(memPos_3), memPos_3))
|
|
||||||
}
|
}
|
||||||
|
case 0x793816ec { external_fun_stateVar() }
|
||||||
|
case 0x9942ec6f { external_fun_f2() }
|
||||||
|
case 0xa00b982b { external_fun_constVar() }
|
||||||
}
|
}
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
function abi_decode(dataEnd)
|
|
||||||
{
|
|
||||||
if slt(add(dataEnd, not(3)), 0) { revert(0, 0) }
|
|
||||||
}
|
|
||||||
function abi_encode_int256_555(headStart) -> tail
|
|
||||||
{
|
|
||||||
tail := add(headStart, 32)
|
|
||||||
mstore(headStart, /** @src 0:124:126 \"41\" */ 0x29)
|
|
||||||
}
|
|
||||||
/// @src 0:79:435 \"contract C...\"
|
|
||||||
function abi_encode_int256(headStart, value0) -> tail
|
function abi_encode_int256(headStart, value0) -> tail
|
||||||
{
|
{
|
||||||
tail := add(headStart, 32)
|
tail := add(headStart, 32)
|
||||||
mstore(headStart, value0)
|
mstore(headStart, value0)
|
||||||
}
|
}
|
||||||
|
function external_fun_stateVar()
|
||||||
|
{
|
||||||
|
if callvalue() { revert(0, 0) }
|
||||||
|
if slt(add(calldatasize(), not(3)), 0) { revert(0, 0) }
|
||||||
|
let _1 := sload(0)
|
||||||
|
let memPos := mload(64)
|
||||||
|
mstore(memPos, _1)
|
||||||
|
return(memPos, 32)
|
||||||
|
}
|
||||||
|
function external_fun_f2()
|
||||||
|
{
|
||||||
|
if callvalue() { revert(0, 0) }
|
||||||
|
let _1 := 0
|
||||||
|
if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) }
|
||||||
|
let _2 := sload(_1)
|
||||||
|
if eq(_2, sub(shl(255, 1), 1)) { panic_error_0x11() }
|
||||||
|
let ret := add(_2, 1)
|
||||||
|
sstore(_1, ret)
|
||||||
|
/// @src 0:410:418 \"this.f()\"
|
||||||
|
let _3 := /** @src 0:79:435 \"contract C...\" */ mload(64)
|
||||||
|
/// @src 0:410:418 \"this.f()\"
|
||||||
|
mstore(_3, /** @src 0:79:435 \"contract C...\" */ shl(228, 0x026121ff))
|
||||||
|
/// @src 0:410:418 \"this.f()\"
|
||||||
|
let _4 := staticcall(gas(), /** @src 0:410:414 \"this\" */ address(), /** @src 0:410:418 \"this.f()\" */ _3, /** @src 0:79:435 \"contract C...\" */ 4, /** @src 0:410:418 \"this.f()\" */ _3, 32)
|
||||||
|
if iszero(_4)
|
||||||
|
{
|
||||||
|
/// @src 0:79:435 \"contract C...\"
|
||||||
|
let pos := mload(64)
|
||||||
|
returndatacopy(pos, _1, returndatasize())
|
||||||
|
revert(pos, returndatasize())
|
||||||
|
}
|
||||||
|
/// @src 0:410:418 \"this.f()\"
|
||||||
|
let expr := /** @src 0:79:435 \"contract C...\" */ _1
|
||||||
|
/// @src 0:410:418 \"this.f()\"
|
||||||
|
if _4
|
||||||
|
{
|
||||||
|
let _5 := 32
|
||||||
|
if gt(_5, returndatasize()) { _5 := returndatasize() }
|
||||||
|
/// @src 0:79:435 \"contract C...\"
|
||||||
|
let newFreePtr := add(_3, and(add(_5, 31), not(31)))
|
||||||
|
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, _3))
|
||||||
|
{
|
||||||
|
mstore(_1, shl(224, 0x4e487b71))
|
||||||
|
mstore(4, 0x41)
|
||||||
|
revert(_1, 0x24)
|
||||||
|
}
|
||||||
|
mstore(64, newFreePtr)
|
||||||
|
/// @src 0:410:418 \"this.f()\"
|
||||||
|
expr := abi_decode_int256_fromMemory(_3, add(_3, _5))
|
||||||
|
}
|
||||||
|
/// @src 0:399:418 \"stateVar + this.f()\"
|
||||||
|
let expr_1 := checked_add_int256(ret, expr)
|
||||||
|
/// @src 0:392:429 \"return stateVar + this.f() + immutVar\"
|
||||||
|
let var := /** @src 0:399:429 \"stateVar + this.f() + immutVar\" */ checked_add_int256(expr_1, /** @src 0:421:429 \"immutVar\" */ loadimmutable(\"8\"))
|
||||||
|
/// @src 0:79:435 \"contract C...\"
|
||||||
|
let memPos := mload(64)
|
||||||
|
return(memPos, sub(abi_encode_int256(memPos, var), memPos))
|
||||||
|
}
|
||||||
|
function external_fun_constVar()
|
||||||
|
{
|
||||||
|
if callvalue() { revert(0, 0) }
|
||||||
|
if slt(add(calldatasize(), not(3)), 0) { revert(0, 0) }
|
||||||
|
let memPos := mload(64)
|
||||||
|
mstore(memPos, /** @src 0:124:126 \"41\" */ 0x29)
|
||||||
|
/// @src 0:79:435 \"contract C...\"
|
||||||
|
return(memPos, 32)
|
||||||
|
}
|
||||||
function panic_error_0x11()
|
function panic_error_0x11()
|
||||||
{
|
{
|
||||||
mstore(0, shl(224, 0x4e487b71))
|
mstore(0, shl(224, 0x4e487b71))
|
||||||
mstore(4, 0x11)
|
mstore(4, 0x11)
|
||||||
revert(0, 0x24)
|
revert(0, 0x24)
|
||||||
}
|
}
|
||||||
function checked_add_int256_556(y) -> sum
|
|
||||||
{
|
|
||||||
if and(1, sgt(y, sub(shl(255, 1), 42))) { panic_error_0x11() }
|
|
||||||
sum := add(/** @src 0:124:126 \"41\" */ 0x29, /** @src 0:79:435 \"contract C...\" */ y)
|
|
||||||
}
|
|
||||||
function checked_add_int256(x, y) -> sum
|
function checked_add_int256(x, y) -> sum
|
||||||
{
|
{
|
||||||
let _1 := slt(x, 0)
|
let _1 := slt(x, 0)
|
||||||
@ -701,51 +768,6 @@ object \"C_54\" {
|
|||||||
if and(_1, slt(y, sub(shl(255, 1), x))) { panic_error_0x11() }
|
if and(_1, slt(y, sub(shl(255, 1), x))) { panic_error_0x11() }
|
||||||
sum := add(x, y)
|
sum := add(x, y)
|
||||||
}
|
}
|
||||||
/// @ast-id 37 @src 0:311:348 \"modifier m()...\"
|
|
||||||
function modifier_m() -> _1
|
|
||||||
{
|
|
||||||
/// @src 0:79:435 \"contract C...\"
|
|
||||||
let _2 := 0
|
|
||||||
let _3 := sload(_2)
|
|
||||||
if eq(_3, sub(shl(255, 1), 1)) { panic_error_0x11() }
|
|
||||||
let ret := add(_3, 1)
|
|
||||||
sstore(_2, ret)
|
|
||||||
/// @src 0:410:418 \"this.f()\"
|
|
||||||
let _4 := /** @src 0:79:435 \"contract C...\" */ mload(64)
|
|
||||||
/// @src 0:410:418 \"this.f()\"
|
|
||||||
mstore(_4, /** @src 0:79:435 \"contract C...\" */ shl(228, 0x026121ff))
|
|
||||||
/// @src 0:410:418 \"this.f()\"
|
|
||||||
let _5 := staticcall(gas(), /** @src 0:410:414 \"this\" */ address(), /** @src 0:410:418 \"this.f()\" */ _4, 4, _4, 32)
|
|
||||||
if iszero(_5)
|
|
||||||
{
|
|
||||||
/// @src 0:79:435 \"contract C...\"
|
|
||||||
let pos := mload(64)
|
|
||||||
returndatacopy(pos, _2, returndatasize())
|
|
||||||
revert(pos, returndatasize())
|
|
||||||
}
|
|
||||||
/// @src 0:410:418 \"this.f()\"
|
|
||||||
let expr := /** @src 0:79:435 \"contract C...\" */ _2
|
|
||||||
/// @src 0:410:418 \"this.f()\"
|
|
||||||
if _5
|
|
||||||
{
|
|
||||||
/// @src 0:79:435 \"contract C...\"
|
|
||||||
let newFreePtr := add(_4, and(add(/** @src 0:410:418 \"this.f()\" */ returndatasize(), /** @src 0:79:435 \"contract C...\" */ 31), not(31)))
|
|
||||||
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, _4))
|
|
||||||
{
|
|
||||||
mstore(_2, shl(224, 0x4e487b71))
|
|
||||||
mstore(/** @src 0:410:418 \"this.f()\" */ 4, /** @src 0:79:435 \"contract C...\" */ 0x41)
|
|
||||||
revert(_2, 0x24)
|
|
||||||
}
|
|
||||||
mstore(64, newFreePtr)
|
|
||||||
/// @src 0:410:418 \"this.f()\"
|
|
||||||
expr := abi_decode_int256_fromMemory(_4, add(_4, returndatasize()))
|
|
||||||
}
|
|
||||||
/// @src 0:399:418 \"stateVar + this.f()\"
|
|
||||||
let expr_1 := checked_add_int256(ret, expr)
|
|
||||||
/// @src 0:343:344 \"_\"
|
|
||||||
_1 := /** @src 0:399:429 \"stateVar + this.f() + immutVar\" */ checked_add_int256(expr_1, /** @src 0:421:429 \"immutVar\" */ loadimmutable(\"8\"))
|
|
||||||
}
|
|
||||||
/// @src 0:79:435 \"contract C...\"
|
|
||||||
function abi_decode_int256_fromMemory(headStart, dataEnd) -> value0
|
function abi_decode_int256_fromMemory(headStart, dataEnd) -> value0
|
||||||
{
|
{
|
||||||
if slt(sub(dataEnd, headStart), 32) { revert(0, 0) }
|
if slt(sub(dataEnd, headStart), 32) { revert(0, 0) }
|
||||||
@ -997,48 +1019,28 @@ object \"D_72\" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_30()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
let ret_0 := fun_f_30()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x793816ec
|
case 0x793816ec
|
||||||
{
|
{
|
||||||
// stateVar()
|
// stateVar()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_stateVar_10()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
let ret_0 := getter_fun_stateVar_10()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x9942ec6f
|
case 0x9942ec6f
|
||||||
{
|
{
|
||||||
// f2()
|
// f2()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f2_53()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
let ret_0 := fun_f2_53()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xa00b982b
|
case 0xa00b982b
|
||||||
{
|
{
|
||||||
// constVar()
|
// constVar()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_constVar_5()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
let ret_0 := getter_fun_constVar_5()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -1085,6 +1087,17 @@ object \"D_72\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_30() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
let ret_0 := fun_f_30()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function shift_right_unsigned_dynamic(bits, value) -> newValue {
|
function shift_right_unsigned_dynamic(bits, value) -> newValue {
|
||||||
newValue :=
|
newValue :=
|
||||||
|
|
||||||
@ -1117,6 +1130,28 @@ object \"D_72\" {
|
|||||||
}
|
}
|
||||||
/// @src 1:91:166 \"contract D is C(3)...\"
|
/// @src 1:91:166 \"contract D is C(3)...\"
|
||||||
|
|
||||||
|
function external_fun_stateVar_10() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
let ret_0 := getter_fun_stateVar_10()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function external_fun_f2_53() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
let ret_0 := fun_f2_53()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function cleanup_t_rational_41_by_1(value) -> cleaned {
|
function cleanup_t_rational_41_by_1(value) -> cleaned {
|
||||||
cleaned := value
|
cleaned := value
|
||||||
}
|
}
|
||||||
@ -1145,6 +1180,17 @@ object \"D_72\" {
|
|||||||
}
|
}
|
||||||
/// @src 1:91:166 \"contract D is C(3)...\"
|
/// @src 1:91:166 \"contract D is C(3)...\"
|
||||||
|
|
||||||
|
function external_fun_constVar_5() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
let ret_0 := getter_fun_constVar_5()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
@ -1364,18 +1410,24 @@ object \"D_72\" {
|
|||||||
let expr_47
|
let expr_47
|
||||||
if _12 {
|
if _12 {
|
||||||
|
|
||||||
|
let _13 := 32
|
||||||
|
|
||||||
|
if gt(_13, returndatasize()) {
|
||||||
|
_13 := returndatasize()
|
||||||
|
}
|
||||||
|
|
||||||
// update freeMemoryPointer according to dynamic return size
|
// update freeMemoryPointer according to dynamic return size
|
||||||
finalize_allocation(_10, returndatasize())
|
finalize_allocation(_10, _13)
|
||||||
|
|
||||||
// decode return parameters from external try-call into retVars
|
// decode return parameters from external try-call into retVars
|
||||||
expr_47 := abi_decode_tuple_t_int256_fromMemory(_10, add(_10, returndatasize()))
|
expr_47 := abi_decode_tuple_t_int256_fromMemory(_10, add(_10, _13))
|
||||||
}
|
}
|
||||||
/// @src 0:399:418 \"stateVar + this.f()\"
|
/// @src 0:399:418 \"stateVar + this.f()\"
|
||||||
let expr_48 := checked_add_t_int256(expr_44, expr_47)
|
let expr_48 := checked_add_t_int256(expr_44, expr_47)
|
||||||
|
|
||||||
/// @src 0:421:429 \"immutVar\"
|
/// @src 0:421:429 \"immutVar\"
|
||||||
let _13 := loadimmutable(\"8\")
|
let _14 := loadimmutable(\"8\")
|
||||||
let expr_49 := _13
|
let expr_49 := _14
|
||||||
/// @src 0:399:429 \"stateVar + this.f() + immutVar\"
|
/// @src 0:399:429 \"stateVar + this.f() + immutVar\"
|
||||||
let expr_50 := checked_add_t_int256(expr_48, expr_49)
|
let expr_50 := checked_add_t_int256(expr_48, expr_49)
|
||||||
|
|
||||||
@ -1471,62 +1523,99 @@ object \"D_72\" {
|
|||||||
switch shr(224, calldataload(_1))
|
switch shr(224, calldataload(_1))
|
||||||
case 0x26121ff0 {
|
case 0x26121ff0 {
|
||||||
if callvalue() { revert(_1, _1) }
|
if callvalue() { revert(_1, _1) }
|
||||||
abi_decode(calldatasize())
|
if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) }
|
||||||
let ret := /** @src 0:286:305 \"constVar + immutVar\" */ checked_add_int256_556(/** @src 0:297:305 \"immutVar\" */ loadimmutable(\"8\"))
|
/// @src 0:297:305 \"immutVar\"
|
||||||
|
let _2 := loadimmutable(\"8\")
|
||||||
/// @src 1:91:166 \"contract D is C(3)...\"
|
/// @src 1:91:166 \"contract D is C(3)...\"
|
||||||
|
if and(1, sgt(_2, sub(shl(255, 1), 42))) { panic_error_0x11() }
|
||||||
let memPos := mload(64)
|
let memPos := mload(64)
|
||||||
return(memPos, sub(abi_encode_int256(memPos, ret), memPos))
|
mstore(memPos, add(/** @src 0:124:126 \"41\" */ 0x29, /** @src 1:91:166 \"contract D is C(3)...\" */ _2))
|
||||||
}
|
return(memPos, 32)
|
||||||
case 0x793816ec {
|
|
||||||
if callvalue() { revert(_1, _1) }
|
|
||||||
abi_decode(calldatasize())
|
|
||||||
let ret_1 := sload(_1)
|
|
||||||
let memPos_1 := mload(64)
|
|
||||||
return(memPos_1, sub(abi_encode_int256(memPos_1, ret_1), memPos_1))
|
|
||||||
}
|
|
||||||
case 0x9942ec6f {
|
|
||||||
if callvalue() { revert(_1, _1) }
|
|
||||||
abi_decode(calldatasize())
|
|
||||||
let ret_2 := /** @src 0:382:385 \"int\" */ modifier_m()
|
|
||||||
/// @src 1:91:166 \"contract D is C(3)...\"
|
|
||||||
let memPos_2 := mload(64)
|
|
||||||
return(memPos_2, sub(abi_encode_int256(memPos_2, ret_2), memPos_2))
|
|
||||||
}
|
|
||||||
case 0xa00b982b {
|
|
||||||
if callvalue() { revert(_1, _1) }
|
|
||||||
abi_decode(calldatasize())
|
|
||||||
let memPos_3 := mload(64)
|
|
||||||
return(memPos_3, sub(abi_encode_int256_555(memPos_3), memPos_3))
|
|
||||||
}
|
}
|
||||||
|
case 0x793816ec { external_fun_stateVar() }
|
||||||
|
case 0x9942ec6f { external_fun_f2() }
|
||||||
|
case 0xa00b982b { external_fun_constVar() }
|
||||||
}
|
}
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
function abi_decode(dataEnd)
|
|
||||||
{
|
|
||||||
if slt(add(dataEnd, not(3)), 0) { revert(0, 0) }
|
|
||||||
}
|
|
||||||
function abi_encode_int256_555(headStart) -> tail
|
|
||||||
{
|
|
||||||
tail := add(headStart, 32)
|
|
||||||
mstore(headStart, /** @src 0:124:126 \"41\" */ 0x29)
|
|
||||||
}
|
|
||||||
/// @src 1:91:166 \"contract D is C(3)...\"
|
|
||||||
function abi_encode_int256(headStart, value0) -> tail
|
function abi_encode_int256(headStart, value0) -> tail
|
||||||
{
|
{
|
||||||
tail := add(headStart, 32)
|
tail := add(headStart, 32)
|
||||||
mstore(headStart, value0)
|
mstore(headStart, value0)
|
||||||
}
|
}
|
||||||
|
function external_fun_stateVar()
|
||||||
|
{
|
||||||
|
if callvalue() { revert(0, 0) }
|
||||||
|
if slt(add(calldatasize(), not(3)), 0) { revert(0, 0) }
|
||||||
|
let _1 := sload(0)
|
||||||
|
let memPos := mload(64)
|
||||||
|
mstore(memPos, _1)
|
||||||
|
return(memPos, 32)
|
||||||
|
}
|
||||||
|
function external_fun_f2()
|
||||||
|
{
|
||||||
|
if callvalue() { revert(0, 0) }
|
||||||
|
let _1 := 0
|
||||||
|
if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) }
|
||||||
|
let _2 := sload(_1)
|
||||||
|
if eq(_2, sub(shl(255, 1), 1)) { panic_error_0x11() }
|
||||||
|
let ret := add(_2, 1)
|
||||||
|
sstore(_1, ret)
|
||||||
|
/// @src 0:410:418 \"this.f()\"
|
||||||
|
let _3 := /** @src 1:91:166 \"contract D is C(3)...\" */ mload(64)
|
||||||
|
/// @src 0:410:418 \"this.f()\"
|
||||||
|
mstore(_3, /** @src 1:91:166 \"contract D is C(3)...\" */ shl(228, 0x026121ff))
|
||||||
|
/// @src 0:410:418 \"this.f()\"
|
||||||
|
let _4 := staticcall(gas(), /** @src 0:410:414 \"this\" */ address(), /** @src 0:410:418 \"this.f()\" */ _3, /** @src 1:91:166 \"contract D is C(3)...\" */ 4, /** @src 0:410:418 \"this.f()\" */ _3, 32)
|
||||||
|
if iszero(_4)
|
||||||
|
{
|
||||||
|
/// @src 1:91:166 \"contract D is C(3)...\"
|
||||||
|
let pos := mload(64)
|
||||||
|
returndatacopy(pos, _1, returndatasize())
|
||||||
|
revert(pos, returndatasize())
|
||||||
|
}
|
||||||
|
/// @src 0:410:418 \"this.f()\"
|
||||||
|
let expr := /** @src 1:91:166 \"contract D is C(3)...\" */ _1
|
||||||
|
/// @src 0:410:418 \"this.f()\"
|
||||||
|
if _4
|
||||||
|
{
|
||||||
|
let _5 := 32
|
||||||
|
if gt(_5, returndatasize()) { _5 := returndatasize() }
|
||||||
|
/// @src 1:91:166 \"contract D is C(3)...\"
|
||||||
|
let newFreePtr := add(_3, and(add(_5, 31), not(31)))
|
||||||
|
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, _3))
|
||||||
|
{
|
||||||
|
mstore(_1, shl(224, 0x4e487b71))
|
||||||
|
mstore(4, 0x41)
|
||||||
|
revert(_1, 0x24)
|
||||||
|
}
|
||||||
|
mstore(64, newFreePtr)
|
||||||
|
/// @src 0:410:418 \"this.f()\"
|
||||||
|
expr := abi_decode_int256_fromMemory(_3, add(_3, _5))
|
||||||
|
}
|
||||||
|
/// @src 0:399:418 \"stateVar + this.f()\"
|
||||||
|
let expr_1 := checked_add_int256(ret, expr)
|
||||||
|
/// @src 0:392:429 \"return stateVar + this.f() + immutVar\"
|
||||||
|
let var := /** @src 0:399:429 \"stateVar + this.f() + immutVar\" */ checked_add_int256(expr_1, /** @src 0:421:429 \"immutVar\" */ loadimmutable(\"8\"))
|
||||||
|
/// @src 1:91:166 \"contract D is C(3)...\"
|
||||||
|
let memPos := mload(64)
|
||||||
|
return(memPos, sub(abi_encode_int256(memPos, var), memPos))
|
||||||
|
}
|
||||||
|
function external_fun_constVar()
|
||||||
|
{
|
||||||
|
if callvalue() { revert(0, 0) }
|
||||||
|
if slt(add(calldatasize(), not(3)), 0) { revert(0, 0) }
|
||||||
|
let memPos := mload(64)
|
||||||
|
mstore(memPos, /** @src 0:124:126 \"41\" */ 0x29)
|
||||||
|
/// @src 1:91:166 \"contract D is C(3)...\"
|
||||||
|
return(memPos, 32)
|
||||||
|
}
|
||||||
function panic_error_0x11()
|
function panic_error_0x11()
|
||||||
{
|
{
|
||||||
mstore(0, shl(224, 0x4e487b71))
|
mstore(0, shl(224, 0x4e487b71))
|
||||||
mstore(4, 0x11)
|
mstore(4, 0x11)
|
||||||
revert(0, 0x24)
|
revert(0, 0x24)
|
||||||
}
|
}
|
||||||
function checked_add_int256_556(y) -> sum
|
|
||||||
{
|
|
||||||
if and(1, sgt(y, sub(shl(255, 1), 42))) { panic_error_0x11() }
|
|
||||||
sum := add(/** @src 0:124:126 \"41\" */ 0x29, /** @src 1:91:166 \"contract D is C(3)...\" */ y)
|
|
||||||
}
|
|
||||||
function checked_add_int256(x, y) -> sum
|
function checked_add_int256(x, y) -> sum
|
||||||
{
|
{
|
||||||
let _1 := slt(x, 0)
|
let _1 := slt(x, 0)
|
||||||
@ -1534,51 +1623,6 @@ object \"D_72\" {
|
|||||||
if and(_1, slt(y, sub(shl(255, 1), x))) { panic_error_0x11() }
|
if and(_1, slt(y, sub(shl(255, 1), x))) { panic_error_0x11() }
|
||||||
sum := add(x, y)
|
sum := add(x, y)
|
||||||
}
|
}
|
||||||
/// @ast-id 37 @src 0:311:348 \"modifier m()...\"
|
|
||||||
function modifier_m() -> _1
|
|
||||||
{
|
|
||||||
/// @src 1:91:166 \"contract D is C(3)...\"
|
|
||||||
let _2 := 0
|
|
||||||
let _3 := sload(_2)
|
|
||||||
if eq(_3, sub(shl(255, 1), 1)) { panic_error_0x11() }
|
|
||||||
let ret := add(_3, 1)
|
|
||||||
sstore(_2, ret)
|
|
||||||
/// @src 0:410:418 \"this.f()\"
|
|
||||||
let _4 := /** @src 1:91:166 \"contract D is C(3)...\" */ mload(64)
|
|
||||||
/// @src 0:410:418 \"this.f()\"
|
|
||||||
mstore(_4, /** @src 1:91:166 \"contract D is C(3)...\" */ shl(228, 0x026121ff))
|
|
||||||
/// @src 0:410:418 \"this.f()\"
|
|
||||||
let _5 := staticcall(gas(), /** @src 0:410:414 \"this\" */ address(), /** @src 0:410:418 \"this.f()\" */ _4, 4, _4, 32)
|
|
||||||
if iszero(_5)
|
|
||||||
{
|
|
||||||
/// @src 1:91:166 \"contract D is C(3)...\"
|
|
||||||
let pos := mload(64)
|
|
||||||
returndatacopy(pos, _2, returndatasize())
|
|
||||||
revert(pos, returndatasize())
|
|
||||||
}
|
|
||||||
/// @src 0:410:418 \"this.f()\"
|
|
||||||
let expr := /** @src 1:91:166 \"contract D is C(3)...\" */ _2
|
|
||||||
/// @src 0:410:418 \"this.f()\"
|
|
||||||
if _5
|
|
||||||
{
|
|
||||||
/// @src 1:91:166 \"contract D is C(3)...\"
|
|
||||||
let newFreePtr := add(_4, and(add(/** @src 0:410:418 \"this.f()\" */ returndatasize(), /** @src 1:91:166 \"contract D is C(3)...\" */ 31), not(31)))
|
|
||||||
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, _4))
|
|
||||||
{
|
|
||||||
mstore(_2, shl(224, 0x4e487b71))
|
|
||||||
mstore(/** @src 0:410:418 \"this.f()\" */ 4, /** @src 1:91:166 \"contract D is C(3)...\" */ 0x41)
|
|
||||||
revert(_2, 0x24)
|
|
||||||
}
|
|
||||||
mstore(64, newFreePtr)
|
|
||||||
/// @src 0:410:418 \"this.f()\"
|
|
||||||
expr := abi_decode_int256_fromMemory(_4, add(_4, returndatasize()))
|
|
||||||
}
|
|
||||||
/// @src 0:399:418 \"stateVar + this.f()\"
|
|
||||||
let expr_1 := checked_add_int256(ret, expr)
|
|
||||||
/// @src 0:343:344 \"_\"
|
|
||||||
_1 := /** @src 0:399:429 \"stateVar + this.f() + immutVar\" */ checked_add_int256(expr_1, /** @src 0:421:429 \"immutVar\" */ loadimmutable(\"8\"))
|
|
||||||
}
|
|
||||||
/// @src 1:91:166 \"contract D is C(3)...\"
|
|
||||||
function abi_decode_int256_fromMemory(headStart, dataEnd) -> value0
|
function abi_decode_int256_fromMemory(headStart, dataEnd) -> value0
|
||||||
{
|
{
|
||||||
if slt(sub(dataEnd, headStart), 32) { revert(0, 0) }
|
if slt(sub(dataEnd, headStart), 32) { revert(0, 0) }
|
||||||
|
@ -34,17 +34,7 @@ object \"C_7\" {
|
|||||||
{
|
{
|
||||||
let selector := shift_right_224_unsigned(calldataload(0))
|
let selector := shift_right_224_unsigned(calldataload(0))
|
||||||
switch selector
|
switch selector
|
||||||
case 0x26121ff0 {
|
case 0x26121ff0 { external_fun_f_6() }
|
||||||
if callvalue()
|
|
||||||
{
|
|
||||||
revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb()
|
|
||||||
}
|
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
fun_f_6()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple__to__fromStack(memPos)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
|
||||||
default { }
|
default { }
|
||||||
}
|
}
|
||||||
revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74()
|
revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74()
|
||||||
@ -65,6 +55,18 @@ object \"C_7\" {
|
|||||||
}
|
}
|
||||||
function abi_encode_tuple__to__fromStack(headStart) -> tail
|
function abi_encode_tuple__to__fromStack(headStart) -> tail
|
||||||
{ tail := add(headStart, 0) }
|
{ tail := add(headStart, 0) }
|
||||||
|
function external_fun_f_6()
|
||||||
|
{
|
||||||
|
if callvalue()
|
||||||
|
{
|
||||||
|
revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb()
|
||||||
|
}
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
fun_f_6()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple__to__fromStack(memPos)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
}
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74()
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74()
|
||||||
{ revert(0, 0) }
|
{ revert(0, 0) }
|
||||||
/// @ast-id 6 @src 0:92:119 \"function f() public pure {}\"
|
/// @ast-id 6 @src 0:92:119 \"function f() public pure {}\"
|
||||||
|
@ -52,12 +52,7 @@ object \"C_7\" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_6()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
fun_f_6()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -94,6 +89,17 @@ object \"C_7\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_6() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
fun_f_6()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
|
@ -121,12 +121,7 @@ object \"D_16\" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_15()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
fun_f_15()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -163,6 +158,17 @@ object \"D_16\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_15() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
fun_f_15()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple__to__fromStack(memPos )
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
|
@ -53,12 +53,7 @@ object "test_11" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_10()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
let ret_0 := fun_f_10()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple_t_bool__to_t_bool__fromStack(memPos , ret_0)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -105,6 +100,17 @@ object "test_11" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_10() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
let ret_0 := fun_f_10()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple_t_bool__to_t_bool__fromStack(memPos , ret_0)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
|
@ -125,18 +125,7 @@ object "C_6" {
|
|||||||
if iszero(lt(calldatasize(), 4))
|
if iszero(lt(calldatasize(), 4))
|
||||||
{
|
{
|
||||||
let selector := shift_right_unsigned(calldataload(0))
|
let selector := shift_right_unsigned(calldataload(0))
|
||||||
if eq(0x26121ff0, selector)
|
if eq(0x26121ff0, selector) { external_fun_f() }
|
||||||
{
|
|
||||||
if callvalue()
|
|
||||||
{
|
|
||||||
revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb()
|
|
||||||
}
|
|
||||||
abi_decode(4, calldatasize())
|
|
||||||
fun_f()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple(memPos)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74()
|
revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74()
|
||||||
}
|
}
|
||||||
@ -421,6 +410,18 @@ object "C_6" {
|
|||||||
let tail_86 := tail_1
|
let tail_86 := tail_1
|
||||||
tail := tail_1
|
tail := tail_1
|
||||||
}
|
}
|
||||||
|
function external_fun_f()
|
||||||
|
{
|
||||||
|
if callvalue()
|
||||||
|
{
|
||||||
|
revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb()
|
||||||
|
}
|
||||||
|
abi_decode(4, calldatasize())
|
||||||
|
fun_f()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple(memPos)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
}
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74()
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74()
|
||||||
{ revert(0, 0) }
|
{ revert(0, 0) }
|
||||||
/// @ast-id 5 @src 0:74:101 "function f() public pure {}"
|
/// @ast-id 5 @src 0:74:101 "function f() public pure {}"
|
||||||
|
@ -52,12 +52,7 @@ object \"C_11\" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_10()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
let ret_0 := fun_f_10()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -132,6 +127,17 @@ object \"C_11\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_10() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
let ret_0 := fun_f_10()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
|
@ -52,12 +52,7 @@ object \"C_11\" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_10()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
let ret_0 := fun_f_10()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple_t_bytes32__to_t_bytes32__fromStack(memPos , ret_0)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -104,6 +99,17 @@ object \"C_11\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_10() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
let ret_0 := fun_f_10()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple_t_bytes32__to_t_bytes32__fromStack(memPos , ret_0)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
|
@ -52,12 +52,7 @@ object \"C_11\" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_10()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
let ret_0 := fun_f_10()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -104,6 +99,17 @@ object \"C_11\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_10() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
let ret_0 := fun_f_10()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
|
@ -52,12 +52,7 @@ object \"C_11\" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_10()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
let ret_0 := fun_f_10()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -132,6 +127,17 @@ object \"C_11\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_10() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
let ret_0 := fun_f_10()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
|
@ -52,12 +52,7 @@ object \"C_11\" {
|
|||||||
{
|
{
|
||||||
// f()
|
// f()
|
||||||
|
|
||||||
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
external_fun_f_10()
|
||||||
abi_decode_tuple_(4, calldatasize())
|
|
||||||
let ret_0 := fun_f_10()
|
|
||||||
let memPos := allocate_unbounded()
|
|
||||||
let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0)
|
|
||||||
return(memPos, sub(memEnd, memPos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default {}
|
default {}
|
||||||
@ -104,6 +99,17 @@ object \"C_11\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function external_fun_f_10() {
|
||||||
|
|
||||||
|
if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }
|
||||||
|
abi_decode_tuple_(4, calldatasize())
|
||||||
|
let ret_0 := fun_f_10()
|
||||||
|
let memPos := allocate_unbounded()
|
||||||
|
let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0)
|
||||||
|
return(memPos, sub(memEnd, memPos))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() {
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ function ens_test
|
|||||||
"${compile_only_presets[@]}"
|
"${compile_only_presets[@]}"
|
||||||
#ir-no-optimize # Compilation fails with "YulException: Variable var__945 is 1 slot(s) too deep inside the stack."
|
#ir-no-optimize # Compilation fails with "YulException: Variable var__945 is 1 slot(s) too deep inside the stack."
|
||||||
#ir-optimize-evm-only # Compilation fails with "YulException: Variable var__945 is 1 slot(s) too deep inside the stack."
|
#ir-optimize-evm-only # Compilation fails with "YulException: Variable var__945 is 1 slot(s) too deep inside the stack."
|
||||||
#ir-optimize-evm+yul # Compilation fails with "YulException: Variable _5 is 1 too deep in the stack [ _5 usr$i usr$h _7 usr$scratch usr$k usr$f _4 usr$len usr$j_2 RET _2 _1 var_data_mpos usr$totallen usr$x _12 ]"
|
ir-optimize-evm+yul # Needs memory-safe inline assembly patch
|
||||||
legacy-optimize-evm-only
|
legacy-optimize-evm-only
|
||||||
legacy-optimize-evm+yul
|
legacy-optimize-evm+yul
|
||||||
)
|
)
|
||||||
@ -68,6 +68,8 @@ function ens_test
|
|||||||
replace_version_pragmas
|
replace_version_pragmas
|
||||||
neutralize_packaged_contracts
|
neutralize_packaged_contracts
|
||||||
|
|
||||||
|
find . -name "*.sol" -exec sed -i -e 's/^\(\s*\)\(assembly\)/\1\/\/\/ @solidity memory-safe-assembly\n\1\2/' '{}' \;
|
||||||
|
|
||||||
for preset in $SELECTED_PRESETS; do
|
for preset in $SELECTED_PRESETS; do
|
||||||
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn
|
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn
|
||||||
store_benchmark_report hardhat ens "$repo" "$preset"
|
store_benchmark_report hardhat ens "$repo" "$preset"
|
||||||
|
@ -66,6 +66,11 @@ function perpetual_pools_test
|
|||||||
force_hardhat_unlimited_contract_size "$config_file" "$config_var"
|
force_hardhat_unlimited_contract_size "$config_file" "$config_var"
|
||||||
yarn install
|
yarn install
|
||||||
|
|
||||||
|
# The project depends on @openzeppelin/hardhat-upgrades, which is currently not prepared
|
||||||
|
# for the parallel compilation introduced in Hardhat 2.9.0.
|
||||||
|
# TODO: Remove when https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/528 is fixed.
|
||||||
|
yarn add hardhat@2.8.4
|
||||||
|
|
||||||
replace_version_pragmas
|
replace_version_pragmas
|
||||||
|
|
||||||
for preset in $SELECTED_PRESETS; do
|
for preset in $SELECTED_PRESETS; do
|
||||||
|
@ -56,7 +56,7 @@ function trident_test
|
|||||||
"${compile_only_presets[@]}"
|
"${compile_only_presets[@]}"
|
||||||
#ir-no-optimize # Compilation fails with: "YulException: Variable var_amount_165 is 9 slot(s) too deep inside the stack."
|
#ir-no-optimize # Compilation fails with: "YulException: Variable var_amount_165 is 9 slot(s) too deep inside the stack."
|
||||||
#ir-optimize-evm-only # Compilation fails with: "YulException: Variable var_amount_165 is 9 slot(s) too deep inside the stack."
|
#ir-optimize-evm-only # Compilation fails with: "YulException: Variable var_amount_165 is 9 slot(s) too deep inside the stack."
|
||||||
#ir-optimize-evm+yul # Compilation fails with: "YulException: Cannot swap Variable var_nearestTick with Variable _4: too deep in the stack by 4 slots"
|
ir-optimize-evm+yul # Needs memory-safe inline assembly patch
|
||||||
legacy-no-optimize
|
legacy-no-optimize
|
||||||
legacy-optimize-evm-only
|
legacy-optimize-evm-only
|
||||||
legacy-optimize-evm+yul
|
legacy-optimize-evm+yul
|
||||||
@ -87,6 +87,7 @@ function trident_test
|
|||||||
sed -i 's|uint32(-1)|type(uint32).max|g' contracts/flat/BentoBoxV1Flat.sol
|
sed -i 's|uint32(-1)|type(uint32).max|g' contracts/flat/BentoBoxV1Flat.sol
|
||||||
sed -i 's|IERC20(0)|IERC20(address(0))|g' contracts/flat/BentoBoxV1Flat.sol
|
sed -i 's|IERC20(0)|IERC20(address(0))|g' contracts/flat/BentoBoxV1Flat.sol
|
||||||
sed -i 's|IStrategy(0)|IStrategy(address(0))|g' contracts/flat/BentoBoxV1Flat.sol
|
sed -i 's|IStrategy(0)|IStrategy(address(0))|g' contracts/flat/BentoBoxV1Flat.sol
|
||||||
|
find contracts -name "*.sol" -exec sed -i -e 's/^\(\s*\)\(assembly\)/\1\/\/\/ @solidity memory-safe-assembly\n\1\2/' '{}' \;
|
||||||
|
|
||||||
# @sushiswap/core package contains contracts that get built with 0.6.12 and fail our compiler
|
# @sushiswap/core package contains contracts that get built with 0.6.12 and fail our compiler
|
||||||
# version check. It's not used by tests so we can remove it.
|
# version check. It's not used by tests so we can remove it.
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user