From ccf58625044b37a13e2849c2a64e79fdc303557e Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 25 Jun 2026 12:02:42 +0200 Subject: [PATCH 1/5] Rewrite storeBytesFromMemory without assembly --- std/std.solc | 70 +++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/std/std.solc b/std/std.solc index 6477d0614..5f7ce7efa 100644 --- a/std/std.solc +++ b/std/std.solc @@ -2331,41 +2331,39 @@ instance array(t):StorageCopy { // Shamelessly stolen from function copy_byte_array_to_storage_from_t_bytes_memory_ptr_to_t_bytes_storage // TODO: consider wrapping behaviour at end of storage function storeBytesFromMemory(slot: word, src: word) -> () { - assembly { - let newLen := mload(src) + let newLen = mload(src); // TODO: check old len, cleanup etc - let srcOffset := 32 - switch gt(newLen, 31) - case 1 { - mstore(0,slot) - let dstPtr := keccak256(0,32) - let loopEnd := and(newLen, not(0x1f)) - let i := 0 - for { } lt(i, loopEnd) { i := add(i, 0x20) } { - sstore(dstPtr, mload(add(src, srcOffset))) - dstPtr := add(dstPtr, 1) - srcOffset := add(srcOffset, 32) - } - if lt(loopEnd, newLen) { - let lastValue := mload(add(src, srcOffset)) - let lastLen := and(newLen, 0x1f) - let mask := not(shr(mul(8, lastLen), not(0))) - let nudata := and(lastValue, mask) // a Yul variable cannot be called "data". Go figure. - sstore(dstPtr, nudata) - } - sstore(slot, add(mul(newLen, 2), 1)) - } - default { - let value := 0 - if newLen { - value := mload(add(src, srcOffset)) - } - let mask := not(shr(mul(8, newLen), not(0))) - let nudata := and(value, mask) - let used := or(nudata, mul(2, newLen)) - sstore(slot,used) - } - } + let srcOffset = 32; + match newLen > 31 { + | true => + // Long byte array (out-of-place encoding) + mstore(0, slot); + let dstPtr = keccak256(0, 32); + let loopEnd = and_(newLen, not_(0x1f)); + for (let i = 0; i < loopEnd; i += 32) { + sstore(dstPtr, mload(src + srcOffset)); + dstPtr += 1; + srcOffset += 32; + } + if (loopEnd < newLen) { + let lastValue = mload(src + srcOffset); + let lastLen = and_(newLen, 0x1f); + let mask = not_(shr(8 * lastLen, not_(0))); + let data_ = and_(lastValue, mask); + sstore(dstPtr, data_); + } + sstore(slot, (newLen * 2) + 1); + | false => + // Short byte array (in-place encoding) + let value = 0; + if (newLen != 0) { + value = mload(src + srcOffset); + } + let mask = not_(shr(8 * newLen, not_(0))); + let data_ = and_(value, mask); + let used = or_(data_, 2 * newLen); + sstore(slot, used); + } } @@ -2382,13 +2380,13 @@ function loadBytesFromStorage(slot:word, memPtr:word) -> word { pos += 32; match outOfPlaceEncoding { | false => - // Short byte array + // Short byte array (in-place encoding) mstore(pos, slotValue & ~0xff); let empty = iszero(length); let notzero = iszero(empty); return pos + (notzero * 32); | true => - // Long byte array + // Long byte array (out-of-place encoding) let dataPos = hash1(slot); let i = 0; for (; i < length; i += 32, dataPos += 1) { From 40c9ae71936da407437c8fb5b45546f47d6ec789 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 25 Jun 2026 12:08:26 +0200 Subject: [PATCH 2/5] Simplify --- std/std.solc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/std/std.solc b/std/std.solc index 5f7ce7efa..cbfcab9e0 100644 --- a/std/std.solc +++ b/std/std.solc @@ -2337,13 +2337,10 @@ function storeBytesFromMemory(slot: word, src: word) -> () { match newLen > 31 { | true => // Long byte array (out-of-place encoding) - mstore(0, slot); - let dstPtr = keccak256(0, 32); + let dstPtr = hash1(slot); let loopEnd = and_(newLen, not_(0x1f)); - for (let i = 0; i < loopEnd; i += 32) { + for (let i = 0; i < loopEnd; i += 32, dstPtr += 1, srcOffset += 32) { sstore(dstPtr, mload(src + srcOffset)); - dstPtr += 1; - srcOffset += 32; } if (loopEnd < newLen) { let lastValue = mload(src + srcOffset); From 9517fdfd84c5f603651a89da6f3d31e633e8a7f9 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 30 Jun 2026 14:22:18 +0200 Subject: [PATCH 3/5] Optimize out one addition --- std/std.solc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/std/std.solc b/std/std.solc index cbfcab9e0..bcc1f5200 100644 --- a/std/std.solc +++ b/std/std.solc @@ -2333,17 +2333,17 @@ instance array(t):StorageCopy { function storeBytesFromMemory(slot: word, src: word) -> () { let newLen = mload(src); // TODO: check old len, cleanup etc - let srcOffset = 32; + src += 32; // Move to data. match newLen > 31 { | true => // Long byte array (out-of-place encoding) let dstPtr = hash1(slot); let loopEnd = and_(newLen, not_(0x1f)); - for (let i = 0; i < loopEnd; i += 32, dstPtr += 1, srcOffset += 32) { - sstore(dstPtr, mload(src + srcOffset)); + for (let i = 0; i < loopEnd; i += 32, dstPtr += 1, src += 32) { + sstore(dstPtr, mload(src)); } if (loopEnd < newLen) { - let lastValue = mload(src + srcOffset); + let lastValue = mload(src); let lastLen = and_(newLen, 0x1f); let mask = not_(shr(8 * lastLen, not_(0))); let data_ = and_(lastValue, mask); @@ -2354,7 +2354,7 @@ function storeBytesFromMemory(slot: word, src: word) -> () { // Short byte array (in-place encoding) let value = 0; if (newLen != 0) { - value = mload(src + srcOffset); + value = mload(src); } let mask = not_(shr(8 * newLen, not_(0))); let data_ = and_(value, mask); From dfd0078d688d66568fe1469e9c0f39dcb277269b Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 30 Jun 2026 14:24:45 +0200 Subject: [PATCH 4/5] Optimize further --- std/std.solc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/std/std.solc b/std/std.solc index bcc1f5200..d268a00e8 100644 --- a/std/std.solc +++ b/std/std.solc @@ -2339,10 +2339,12 @@ function storeBytesFromMemory(slot: word, src: word) -> () { // Long byte array (out-of-place encoding) let dstPtr = hash1(slot); let loopEnd = and_(newLen, not_(0x1f)); - for (let i = 0; i < loopEnd; i += 32, dstPtr += 1, src += 32) { + let trailing = loopEnd < newLen; + loopEnd += src; + for (; src < loopEnd; src += 32, dstPtr += 1) { sstore(dstPtr, mload(src)); } - if (loopEnd < newLen) { + if (trailing) { let lastValue = mload(src); let lastLen = and_(newLen, 0x1f); let mask = not_(shr(8 * lastLen, not_(0))); From 81b5bccd8a9daa5d8d3eeb2b978ab02c5ae45efe Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Sun, 2 Aug 2026 21:28:03 +0200 Subject: [PATCH 5/5] Use new expression sugars --- std/std.solc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/std/std.solc b/std/std.solc index d268a00e8..16e76199e 100644 --- a/std/std.solc +++ b/std/std.solc @@ -2338,7 +2338,7 @@ function storeBytesFromMemory(slot: word, src: word) -> () { | true => // Long byte array (out-of-place encoding) let dstPtr = hash1(slot); - let loopEnd = and_(newLen, not_(0x1f)); + let loopEnd = newLen & ~0x1f; let trailing = loopEnd < newLen; loopEnd += src; for (; src < loopEnd; src += 32, dstPtr += 1) { @@ -2346,9 +2346,9 @@ function storeBytesFromMemory(slot: word, src: word) -> () { } if (trailing) { let lastValue = mload(src); - let lastLen = and_(newLen, 0x1f); - let mask = not_(shr(8 * lastLen, not_(0))); - let data_ = and_(lastValue, mask); + let lastLen = newLen & 0x1f; + let mask = ~shr(8 * lastLen, ~0); + let data_ = lastValue & mask; sstore(dstPtr, data_); } sstore(slot, (newLen * 2) + 1); @@ -2358,9 +2358,9 @@ function storeBytesFromMemory(slot: word, src: word) -> () { if (newLen != 0) { value = mload(src); } - let mask = not_(shr(8 * newLen, not_(0))); - let data_ = and_(value, mask); - let used = or_(data_, 2 * newLen); + let mask = ~shr(8 * newLen, ~0); + let data_ = value & mask; + let used = data_ | (2 * newLen); sstore(slot, used); } }