From e9dcfb0b624e5443942451fc865c154a2c5a73d7 Mon Sep 17 00:00:00 2001 From: bitshift Date: Fri, 9 Mar 2018 17:46:24 +0100 Subject: Implements pop() for value type arrays. --- libsolidity/codegen/ArrayUtils.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'libsolidity/codegen/ArrayUtils.cpp') diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 0fe66d2d..b434fddd 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -823,6 +823,39 @@ void ArrayUtils::incrementDynamicArraySize(ArrayType const& _type) const })", {"ref"}); } +void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const +{ + solAssert(_type.location() == DataLocation::Storage, ""); + solAssert(_type.isDynamicallySized(), ""); + if (!_type.isByteArray() && _type.baseType()->storageBytes() < 32) + solAssert(_type.baseType()->isValueType(), "Invalid storage size for non-value type."); + + // stack: ArrayReference + retrieveLength(_type); + // stack: ArrayReference oldLength + m_context << Instruction::DUP1; + // stack: ArrayReference oldLength oldLength + m_context << Instruction::ISZERO; + m_context.appendConditionalInvalid(); + + if (_type.isByteArray()) + { + } + else + { + // Stack: ArrayReference oldLength + m_context << u256(1) << Instruction::SWAP1 << Instruction::SUB; + // Stack ArrayReference newLength + m_context << Instruction::DUP2 << Instruction::DUP2; + // Stack ArrayReference newLength ArrayReference newLength; + accessIndex(_type, false); + // Stack: ArrayReference newLength storage_slot byte_offset + StorageItem(m_context, _type).setToZero(SourceLocation(), true); + // Stack: ArrayReference newLength + m_context << Instruction::SSTORE; + } +} + void ArrayUtils::clearStorageLoop(TypePointer const& _type) const { m_context.callLowLevelFunction( -- cgit v1.2.3 From 7156a01acc822ab66c189435421564afc8b1c922 Mon Sep 17 00:00:00 2001 From: Erik Kundt Date: Fri, 16 Mar 2018 17:06:38 +0100 Subject: Implements pop() for byte arrays. --- libsolidity/codegen/ArrayUtils.cpp | 75 +++++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 10 deletions(-) (limited to 'libsolidity/codegen/ArrayUtils.cpp') diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index b434fddd..096b2d4e 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -830,19 +830,74 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const if (!_type.isByteArray() && _type.baseType()->storageBytes() < 32) solAssert(_type.baseType()->isValueType(), "Invalid storage size for non-value type."); - // stack: ArrayReference - retrieveLength(_type); - // stack: ArrayReference oldLength - m_context << Instruction::DUP1; - // stack: ArrayReference oldLength oldLength - m_context << Instruction::ISZERO; - m_context.appendConditionalInvalid(); - if (_type.isByteArray()) { + m_context.appendInlineAssembly(R"({ + let slot_value := sload(ref) + switch and(slot_value, 1) + case 0 { + // short byte array + let length := and(div(slot_value, 2), 0x3f) + if iszero(length) { invalid() } + + // Zero-out the suffix of the byte array by masking it. + // Do not zero-out the least significant byte, but mask the + // higher bits of the length. + // (((1<<(8 * (32 - length))) - 1) << 8) + 128 + let mask := add(mul(0x100, sub(exp(0x100, sub(32, length)), 1)), 0x80) + slot_value := and(not(mask), slot_value) + + // Reduce the length by 1 + slot_value := sub(slot_value, 2) + sstore(ref, slot_value) + } + case 1 { + // long byte array + let length := div(slot_value, 2) + mstore(0, ref) + + switch length + case 32 + { + let slot := keccak256(0, 0x20) + let data := sload(slot) + sstore(slot, 0) + data := and(data, not(0xff)) + sstore(ref, or(data, 62)) + } + default + { + let slot := div(sub(length, 1), 32) + let offset := and(sub(length, 1), 0x1f) + slot := add(keccak256(0, 0x20), slot) + let data := sload(slot) + + // Zero-out the suffix of the byte array by masking it. + // ((1<<(8 * (32 - offset))) - 1) + let mask := sub(exp(0x100, sub(32, offset)), 1) + data := and(not(mask), data) + sstore(slot, data) + + // Reduce the length by 1 + slot_value := sub(slot_value, 2) + sstore(ref, slot_value) + } + } + })", {"ref"}); + m_context << Instruction::POP; } else - { + { + + // stack: ArrayReference + retrieveLength(_type); + // stack: ArrayReference oldLength + m_context << Instruction::DUP1; + // stack: ArrayReference oldLength oldLength + m_context << Instruction::ISZERO; + m_context.appendConditionalInvalid(); + + // Stack: ArrayReference oldLength m_context << u256(1) << Instruction::SWAP1 << Instruction::SUB; // Stack ArrayReference newLength @@ -852,7 +907,7 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const // Stack: ArrayReference newLength storage_slot byte_offset StorageItem(m_context, _type).setToZero(SourceLocation(), true); // Stack: ArrayReference newLength - m_context << Instruction::SSTORE; + m_context << Instruction::SWAP1 << Instruction::SSTORE; } } -- cgit v1.2.3 From 34b5eca1f8d9a8f04db20139601c6e944532f4e4 Mon Sep 17 00:00:00 2001 From: Erik Kundt Date: Wed, 4 Apr 2018 18:21:06 +0200 Subject: Improves assembly and adds more tests. --- libsolidity/codegen/ArrayUtils.cpp | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) (limited to 'libsolidity/codegen/ArrayUtils.cpp') diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 096b2d4e..d78e64a9 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -837,29 +837,23 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const switch and(slot_value, 1) case 0 { // short byte array - let length := and(div(slot_value, 2), 0x3f) + let length := and(div(slot_value, 2), 0x1f) if iszero(length) { invalid() } - // Zero-out the suffix of the byte array by masking it. - // Do not zero-out the least significant byte, but mask the - // higher bits of the length. - // (((1<<(8 * (32 - length))) - 1) << 8) + 128 - let mask := add(mul(0x100, sub(exp(0x100, sub(32, length)), 1)), 0x80) - slot_value := and(not(mask), slot_value) - - // Reduce the length by 1 - slot_value := sub(slot_value, 2) + // Zero-out the suffix inlcluding the least significant byte. + let mask := sub(exp(0x100, sub(33, length)), 1) + length := sub(length, 1) + slot_value := or(and(not(mask), slot_value), mul(length, 2)) sstore(ref, slot_value) } case 1 { // long byte array let length := div(slot_value, 2) + let slot := keccak256(0, 0x20) mstore(0, ref) - switch length case 32 { - let slot := keccak256(0, 0x20) let data := sload(slot) sstore(slot, 0) data := and(data, not(0xff)) @@ -867,14 +861,14 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const } default { - let slot := div(sub(length, 1), 32) - let offset := and(sub(length, 1), 0x1f) - slot := add(keccak256(0, 0x20), slot) + let slot_offset := div(sub(length, 1), 32) + let length_offset := and(sub(length, 1), 0x1f) + slot := add(slot, slot_offset) let data := sload(slot) // Zero-out the suffix of the byte array by masking it. // ((1<<(8 * (32 - offset))) - 1) - let mask := sub(exp(0x100, sub(32, offset)), 1) + let mask := sub(exp(0x100, sub(32, length_offset)), 1) data := and(not(mask), data) sstore(slot, data) @@ -887,8 +881,7 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const m_context << Instruction::POP; } else - { - + { // stack: ArrayReference retrieveLength(_type); // stack: ArrayReference oldLength @@ -897,7 +890,6 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const m_context << Instruction::ISZERO; m_context.appendConditionalInvalid(); - // Stack: ArrayReference oldLength m_context << u256(1) << Instruction::SWAP1 << Instruction::SUB; // Stack ArrayReference newLength @@ -905,7 +897,7 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const // Stack ArrayReference newLength ArrayReference newLength; accessIndex(_type, false); // Stack: ArrayReference newLength storage_slot byte_offset - StorageItem(m_context, _type).setToZero(SourceLocation(), true); + StorageItem(m_context, *_type.baseType()).setToZero(SourceLocation(), true); // Stack: ArrayReference newLength m_context << Instruction::SWAP1 << Instruction::SSTORE; } -- cgit v1.2.3 From 98d52beba3f989b3a5eeaba2d257de8de5df60a7 Mon Sep 17 00:00:00 2001 From: Erik Kundt Date: Wed, 16 May 2018 17:18:30 +0200 Subject: Adds syntax tests, documentation and changelog entry. Refines comment for array utility function. --- libsolidity/codegen/ArrayUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libsolidity/codegen/ArrayUtils.cpp') diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index d78e64a9..6bb9a961 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -840,7 +840,7 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const let length := and(div(slot_value, 2), 0x1f) if iszero(length) { invalid() } - // Zero-out the suffix inlcluding the least significant byte. + // Zero-out the suffix including the least significant byte. let mask := sub(exp(0x100, sub(33, length)), 1) length := sub(length, 1) slot_value := or(and(not(mask), slot_value), mul(length, 2)) -- cgit v1.2.3 From fea0d116f7d95e9a39f0c80c5156cb3656b03ce0 Mon Sep 17 00:00:00 2001 From: Erik Kundt Date: Tue, 29 May 2018 11:25:13 +0200 Subject: Fixes assembly bug and adds tests to cover it. --- libsolidity/codegen/ArrayUtils.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'libsolidity/codegen/ArrayUtils.cpp') diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 6bb9a961..14c887c3 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -848,9 +848,9 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const } case 1 { // long byte array + mstore(0, ref) let length := div(slot_value, 2) let slot := keccak256(0, 0x20) - mstore(0, ref) switch length case 32 { @@ -861,14 +861,13 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const } default { - let slot_offset := div(sub(length, 1), 32) - let length_offset := and(sub(length, 1), 0x1f) - slot := add(slot, slot_offset) + let offset_inside_slot := and(sub(length, 1), 0x1f) + slot := add(slot, div(sub(length, 1), 32)) let data := sload(slot) // Zero-out the suffix of the byte array by masking it. // ((1<<(8 * (32 - offset))) - 1) - let mask := sub(exp(0x100, sub(32, length_offset)), 1) + let mask := sub(exp(0x100, sub(32, offset_inside_slot)), 1) data := and(not(mask), data) sstore(slot, data) -- cgit v1.2.3 From 1dc28c065d91416caf778770ef57b73b30462b8d Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 7 May 2018 16:23:39 +0200 Subject: Properly pad data from calldata. --- libsolidity/codegen/ArrayUtils.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'libsolidity/codegen/ArrayUtils.cpp') diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 14c887c3..2b77db8f 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -303,12 +303,17 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord m_context << _sourceType.length(); if (baseSize > 1) m_context << u256(baseSize) << Instruction::MUL; - // stack: target source_offset source_len - m_context << Instruction::DUP1 << Instruction::DUP3 << Instruction::DUP5; - // stack: target source_offset source_len source_len source_offset target - m_context << Instruction::CALLDATACOPY; - m_context << Instruction::DUP3 << Instruction::ADD; - m_context << Instruction::SWAP2 << Instruction::POP << Instruction::POP; + + string routine = "calldatacopy(target, source, len)\n"; + if (_padToWordBoundaries) + routine += R"( + // Set padding suffix to zero + mstore(add(target, len), 0) + len := and(add(len, 0x1f), not(0x1f)) + )"; + routine += "target := add(target, len)\n"; + m_context.appendInlineAssembly("{" + routine + "}", {"target", "source", "len"}); + m_context << Instruction::POP << Instruction::POP; } else if (_sourceType.location() == DataLocation::Memory) { -- cgit v1.2.3 From 3321000f67add785383adb4ec544aad121552751 Mon Sep 17 00:00:00 2001 From: Anurag Dashputre Date: Sun, 30 Sep 2018 12:40:38 +0530 Subject: Removing extra default cases to force compile time error, instead of runtime. --- libsolidity/codegen/ArrayUtils.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'libsolidity/codegen/ArrayUtils.cpp') diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 2b77db8f..d33f749c 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -1108,8 +1108,6 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck) c m_context << endTag; break; } - default: - solAssert(false, ""); } } -- cgit v1.2.3