aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/codegen/CompilerUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/codegen/CompilerUtils.cpp')
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp124
1 files changed, 64 insertions, 60 deletions
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index dc0b340c..7067ddd5 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -128,7 +128,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
m_context << Instruction::DUP1;
storeStringData(bytesConstRef(str->value()));
if (_padToWordBoundaries)
- m_context << u256(((str->value().size() + 31) / 32) * 32);
+ m_context << u256(max<size_t>(32, ((str->value().size() + 31) / 32) * 32));
else
m_context << u256(str->value().size());
m_context << Instruction::ADD;
@@ -180,6 +180,9 @@ void CompilerUtils::encodeToMemory(
t = t->mobileType()->interfaceType(_encodeAsLibraryTypes)->encodingType();
}
+ if (_givenTypes.empty())
+ return;
+
// Stack during operation:
// <v1> <v2> ... <vn> <mem_start> <dyn_head_1> ... <dyn_head_r> <end_of_mem>
// The values dyn_head_i are added during the first loop and they point to the head part
@@ -299,40 +302,15 @@ void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type)
m_context << Instruction::SWAP1 << Instruction::POP;
}
-void CompilerUtils::memoryCopyPrecompile()
-{
- // Stack here: size target source
-
- m_context.appendInlineAssembly(R"(
- {
- let words := div(add(len, 31), 32)
- let cost := add(15, mul(3, words))
- jumpi(invalidJumpLabel, iszero(call(cost, $identityContractAddress, 0, src, len, dst, len)))
- }
- )",
- { "len", "dst", "src" },
- map<string, string> {
- { "$identityContractAddress", toString(identityContractAddress) }
- }
- );
- m_context << Instruction::POP << Instruction::POP << Instruction::POP;
-}
-
void CompilerUtils::memoryCopy32()
{
// Stack here: size target source
m_context.appendInlineAssembly(R"(
{
- jumpi(end, eq(len, 0))
- start:
- mstore(dst, mload(src))
- jumpi(end, iszero(gt(len, 32)))
- dst := add(dst, 32)
- src := add(src, 32)
- len := sub(len, 32)
- jump(start)
- end:
+ for { let i := 0 } lt(i, len) { i := add(i, 32) } {
+ mstore(add(dst, i), mload(add(src, i)))
+ }
}
)",
{ "len", "dst", "src" }
@@ -346,21 +324,22 @@ void CompilerUtils::memoryCopy()
m_context.appendInlineAssembly(R"(
{
- // copy 32 bytes at once
- start32:
- jumpi(end32, lt(len, 32))
- mstore(dst, mload(src))
- dst := add(dst, 32)
- src := add(src, 32)
- len := sub(len, 32)
- jump(start32)
- end32:
+ // copy 32 bytes at once
+ for
+ {}
+ iszero(lt(len, 32))
+ {
+ dst := add(dst, 32)
+ src := add(src, 32)
+ len := sub(len, 32)
+ }
+ { mstore(dst, mload(src)) }
- // copy the remainder (0 < len < 32)
- let mask := sub(exp(256, sub(32, len)), 1)
- let srcpart := and(mload(src), not(mask))
- let dstpart := and(mload(dst), mask)
- mstore(dst, or(srcpart, dstpart))
+ // copy the remainder (0 < len < 32)
+ let mask := sub(exp(256, sub(32, len)), 1)
+ let srcpart := and(mload(src), not(mask))
+ let dstpart := and(mload(dst), mask)
+ mstore(dst, or(srcpart, dstpart))
}
)",
{ "len", "dst", "src" }
@@ -374,13 +353,16 @@ void CompilerUtils::splitExternalFunctionType(bool _leftAligned)
// address (right aligned), function identifier (right aligned)
if (_leftAligned)
{
- m_context << Instruction::DUP1 << (u256(1) << (64 + 32)) << Instruction::SWAP1 << Instruction::DIV;
+ m_context << Instruction::DUP1;
+ rightShiftNumberOnStack(64 + 32, false);
// <input> <address>
- m_context << Instruction::SWAP1 << (u256(1) << 64) << Instruction::SWAP1 << Instruction::DIV;
+ m_context << Instruction::SWAP1;
+ rightShiftNumberOnStack(64, false);
}
else
{
- m_context << Instruction::DUP1 << (u256(1) << 32) << Instruction::SWAP1 << Instruction::DIV;
+ m_context << Instruction::DUP1;
+ rightShiftNumberOnStack(32, false);
m_context << ((u256(1) << 160) - 1) << Instruction::AND << Instruction::SWAP1;
}
m_context << u256(0xffffffffUL) << Instruction::AND;
@@ -392,10 +374,10 @@ void CompilerUtils::combineExternalFunctionType(bool _leftAligned)
m_context << u256(0xffffffffUL) << Instruction::AND << Instruction::SWAP1;
if (!_leftAligned)
m_context << ((u256(1) << 160) - 1) << Instruction::AND;
- m_context << (u256(1) << 32) << Instruction::MUL;
+ leftShiftNumberOnStack(32);
m_context << Instruction::OR;
if (_leftAligned)
- m_context << (u256(1) << 64) << Instruction::MUL;
+ leftShiftNumberOnStack(64);
}
void CompilerUtils::pushCombinedFunctionEntryLabel(Declaration const& _function)
@@ -404,14 +386,21 @@ void CompilerUtils::pushCombinedFunctionEntryLabel(Declaration const& _function)
// If there is a runtime context, we have to merge both labels into the same
// stack slot in case we store it in storage.
if (CompilerContext* rtc = m_context.runtimeContext())
+ {
+ leftShiftNumberOnStack(32);
m_context <<
- (u256(1) << 32) <<
- Instruction::MUL <<
rtc->functionEntryLabel(_function).toSubAssemblyTag(m_context.runtimeSub()) <<
Instruction::OR;
+ }
}
-void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded, bool _chopSignBits)
+void CompilerUtils::convertType(
+ Type const& _typeOnStack,
+ Type const& _targetType,
+ bool _cleanupNeeded,
+ bool _chopSignBits,
+ bool _asPartOfArgumentDecoding
+)
{
// For a type extension, we need to remove all higher-order bits that we might have ignored in
// previous operations.
@@ -440,7 +429,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
// conversion from bytes to integer. no need to clean the high bit
// only to shift right because of opposite alignment
IntegerType const& targetIntegerType = dynamic_cast<IntegerType const&>(_targetType);
- m_context << (u256(1) << (256 - typeOnStack.numBytes() * 8)) << Instruction::SWAP1 << Instruction::DIV;
+ rightShiftNumberOnStack(256 - typeOnStack.numBytes() * 8, false);
if (targetIntegerType.numBits() < typeOnStack.numBytes() * 8)
convertType(IntegerType(typeOnStack.numBytes() * 8), _targetType, _cleanupNeeded);
}
@@ -469,7 +458,10 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
EnumType const& enumType = dynamic_cast<decltype(enumType)>(_typeOnStack);
solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error.");
m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT;
- m_context.appendConditionalInvalid();
+ if (_asPartOfArgumentDecoding)
+ m_context.appendConditionalRevert();
+ else
+ m_context.appendConditionalInvalid();
enumOverflowCheckPending = false;
}
break;
@@ -488,7 +480,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack))
if (targetBytesType.numBytes() * 8 > typeOnStack->numBits())
cleanHigherOrderBits(*typeOnStack);
- m_context << (u256(1) << (256 - targetBytesType.numBytes() * 8)) << Instruction::MUL;
+ leftShiftNumberOnStack(256 - targetBytesType.numBytes() * 8);
}
else if (targetTypeCategory == Type::Category::Enum)
{
@@ -953,7 +945,7 @@ unsigned CompilerUtils::sizeOnStack(vector<shared_ptr<Type const>> const& _varia
void CompilerUtils::computeHashStatic()
{
storeInMemory(0);
- m_context << u256(32) << u256(0) << Instruction::SHA3;
+ m_context << u256(32) << u256(0) << Instruction::KECCAK256;
}
void CompilerUtils::storeStringData(bytesConstRef _data)
@@ -998,13 +990,13 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
{
bool leftAligned = _type.category() == Type::Category::FixedBytes;
// add leading or trailing zeros by dividing/multiplying depending on alignment
- u256 shiftFactor = u256(1) << ((32 - numBytes) * 8);
- m_context << shiftFactor << Instruction::SWAP1 << Instruction::DIV;
+ int shiftFactor = (32 - numBytes) * 8;
+ rightShiftNumberOnStack(shiftFactor, false);
if (leftAligned)
- m_context << shiftFactor << Instruction::MUL;
+ leftShiftNumberOnStack(shiftFactor);
}
if (_fromCalldata)
- convertType(_type, _type, true);
+ convertType(_type, _type, true, false, true);
return numBytes;
}
@@ -1019,6 +1011,18 @@ void CompilerUtils::cleanHigherOrderBits(IntegerType const& _typeOnStack)
m_context << ((u256(1) << _typeOnStack.numBits()) - 1) << Instruction::AND;
}
+void CompilerUtils::leftShiftNumberOnStack(unsigned _bits)
+{
+ solAssert(_bits < 256, "");
+ m_context << (u256(1) << _bits) << Instruction::MUL;
+}
+
+void CompilerUtils::rightShiftNumberOnStack(unsigned _bits, bool _isSigned)
+{
+ solAssert(_bits < 256, "");
+ m_context << (u256(1) << _bits) << Instruction::SWAP1 << (_isSigned ? Instruction::SDIV : Instruction::DIV);
+}
+
unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWords)
{
unsigned numBytes = _type.calldataEncodedSize(_padToWords);
@@ -1031,7 +1035,7 @@ unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWords)
convertType(_type, _type, true);
if (numBytes != 32 && !leftAligned && !_padToWords)
// shift the value accordingly before storing
- m_context << (u256(1) << ((32 - numBytes) * 8)) << Instruction::MUL;
+ leftShiftNumberOnStack((32 - numBytes) * 8);
}
return numBytes;
}