Skip to content

Commit a837c17

Browse files
committed
evmasm: Don't update free memory pointer for value type returns
1 parent 7bb4bb1 commit a837c17

File tree

45 files changed

+217
-111
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+217
-111
lines changed

libsolidity/codegen/ExpressionCompiler.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2942,11 +2942,10 @@ void ExpressionCompiler::appendExternalFunctionCall(
29422942
utils().fetchFreeMemoryPointer();
29432943
// Stack: return_data_start
29442944

2945-
// The old decoder did not allocate any memory (i.e. did not touch the free
2946-
// memory pointer), but kept references to the return data for
2947-
// (statically-sized) arrays
2945+
// Only update free memory pointer if any return type needs memory (reference types).
2946+
// Value types are decoded directly to the stack via mload.
29482947
bool needToUpdateFreeMemoryPtr = false;
2949-
if (dynamicReturnSize || m_context.useABICoderV2())
2948+
if (dynamicReturnSize)
29502949
needToUpdateFreeMemoryPtr = true;
29512950
else
29522951
for (auto const& retType: returnTypes)
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
pragma abicoder v1;
2+
3+
interface I {
4+
function getStaticArray() external returns (uint[2] memory);
5+
}
6+
7+
contract Impl is I {
8+
function getStaticArray() external pure returns (uint[2] memory) {
9+
uint[2] memory arr;
10+
arr[0] = 1;
11+
arr[1] = 2;
12+
return arr;
13+
}
14+
}
15+
16+
// With ABIEncoderV1, static arrays allocate memory for returndata buffer.
17+
// The decoded array is in place, so only returndata buffer is allocated.
18+
contract C {
19+
I immutable impl = I(address(new Impl()));
20+
21+
function freeMemory() internal pure returns (uint m) { assembly { m := mload(0x40) } }
22+
23+
// 64 = returndata buffer only (decoded in place)
24+
function testStaticArray() public returns (uint memDiff) {
25+
uint memBefore = freeMemory();
26+
impl.getStaticArray();
27+
memDiff = freeMemory() - memBefore;
28+
}
29+
30+
// 640 = 10 calls * 64 bytes per call
31+
function testMemoryGrowsInLoop() public returns (uint memDiff) {
32+
uint memBefore = freeMemory();
33+
for (uint i = 0; i < 10; i++) {
34+
impl.getStaticArray();
35+
}
36+
memDiff = freeMemory() - memBefore;
37+
}
38+
}
39+
// ====
40+
// EVMVersion: >=byzantium
41+
// compileViaYul: false
42+
// ----
43+
// testStaticArray() -> 64
44+
// testMemoryGrowsInLoop() -> 640
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
pragma abicoder v1;
2+
3+
interface I {
4+
function getUint() external returns (uint256);
5+
}
6+
7+
contract Impl is I {
8+
function getUint() external pure returns (uint256) { return 42; }
9+
}
10+
11+
contract C {
12+
I immutable impl = I(address(new Impl()));
13+
14+
function freeMemory() internal pure returns (uint m) { assembly { m := mload(0x40) } }
15+
16+
function testValueType() public returns (uint memDiff) {
17+
uint memBefore = freeMemory();
18+
impl.getUint();
19+
memDiff = freeMemory() - memBefore;
20+
}
21+
22+
function testNoMemoryGrowthInLoop() public returns (uint memDiff) {
23+
uint memBefore = freeMemory();
24+
for (uint i = 0; i < 10; i++) {
25+
impl.getUint();
26+
}
27+
memDiff = freeMemory() - memBefore;
28+
}
29+
}
30+
// ====
31+
// compileViaYul: false
32+
// ----
33+
// testValueType() -> 0
34+
// testNoMemoryGrowthInLoop() -> 0

test/libsolidity/semanticTests/abiEncoderV1/struct/struct_storage_ptr.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ contract C {
2525
// library: L
2626
// f() -> 8, 7, 1, 2, 7, 12
2727
// gas irOptimized: 166609
28-
// gas legacy: 170486
29-
// gas legacyOptimized: 167252
28+
// gas legacy: 170439
29+
// gas legacyOptimized: 167202
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
pragma abicoder v2;
2+
3+
interface I {
4+
function getUint() external returns (uint256);
5+
}
6+
7+
contract Impl is I {
8+
function getUint() external pure returns (uint256) { return 42; }
9+
}
10+
11+
contract C {
12+
I immutable impl = I(address(new Impl()));
13+
14+
function freeMemory() internal pure returns (uint m) { assembly { m := mload(0x40) } }
15+
16+
function testValueType() public returns (uint memDiff) {
17+
uint memBefore = freeMemory();
18+
impl.getUint();
19+
memDiff = freeMemory() - memBefore;
20+
}
21+
22+
function testNoMemoryGrowthInLoop() public returns (uint memDiff) {
23+
uint memBefore = freeMemory();
24+
for (uint i = 0; i < 10; i++) {
25+
impl.getUint();
26+
}
27+
memDiff = freeMemory() - memBefore;
28+
}
29+
}
30+
// ----
31+
// testValueType() -> 0
32+
// testNoMemoryGrowthInLoop() -> 0

test/libsolidity/semanticTests/arithmetics/check_var_init.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ contract D {
1616
// ----
1717
// f() -> FAILURE, hex"4e487b71", 0x11
1818
// g(), 100 wei -> 1
19-
// gas legacy: 76780
19+
// gas legacy: 76745
2020
// gas legacy code: 23600

test/libsolidity/semanticTests/array/function_array_cross_calls.sol

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ contract C {
4444
// test() -> 5, 6, 7
4545
// gas irOptimized: 85886
4646
// gas irOptimized code: 158000
47-
// gas legacy: 97551
48-
// gas legacy code: 342800
49-
// gas legacyOptimized: 87808
50-
// gas legacyOptimized code: 193000
47+
// gas legacy: 97317
48+
// gas legacy code: 333800
49+
// gas legacyOptimized: 87541
50+
// gas legacyOptimized code: 183400

test/libsolidity/semanticTests/array/reusing_memory.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ contract Main {
2626
// f(uint256): 0x34 -> 0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1
2727
// gas irOptimized: 99328
2828
// gas irOptimized code: 12400
29-
// gas legacy: 101551
29+
// gas legacy: 101478
3030
// gas legacy code: 23600
31-
// gas legacyOptimized: 99612
31+
// gas legacyOptimized: 99533
3232
// gas legacyOptimized code: 13400

test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ contract Creator {
2828
// f(uint256,address[]): 7, 0x40, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 -> 7, 8
2929
// gas irOptimized: 327542
3030
// gas irOptimized code: 94000
31-
// gas legacy: 338477
31+
// gas legacy: 338407
3232
// gas legacy code: 244800
33-
// gas legacyOptimized: 329166
33+
// gas legacyOptimized: 329090
3434
// gas legacyOptimized code: 117000

test/libsolidity/semanticTests/constructor/bytes_in_constructors_packer.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ contract Creator {
2828
// f(uint256,bytes): 7, 0x40, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz" -> 7, "h"
2929
// gas irOptimized: 169055
3030
// gas irOptimized code: 99600
31-
// gas legacy: 172946
31+
// gas legacy: 172876
3232
// gas legacy code: 239800
33-
// gas legacyOptimized: 169823
33+
// gas legacyOptimized: 169747
3434
// gas legacyOptimized code: 118600

0 commit comments

Comments
 (0)