aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/codegen')
-rw-r--r--libsolidity/codegen/ABIFunctions.cpp38
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp25
-rw-r--r--libsolidity/codegen/CompilerUtils.h35
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp2
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp116
5 files changed, 132 insertions, 84 deletions
diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp
index 9f6c55ba..756148e7 100644
--- a/libsolidity/codegen/ABIFunctions.cpp
+++ b/libsolidity/codegen/ABIFunctions.cpp
@@ -162,7 +162,7 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
break;
}
case Type::Category::Contract:
- templ("body", "cleaned := " + cleanupFunction(IntegerType(0, IntegerType::Modifier::Address)) + "(value)");
+ templ("body", "cleaned := " + cleanupFunction(IntegerType(160, IntegerType::Modifier::Address)) + "(value)");
break;
case Type::Category::Enum:
{
@@ -243,7 +243,7 @@ string ABIFunctions::conversionFunction(Type const& _from, Type const& _to)
toCategory == Type::Category::Integer ||
toCategory == Type::Category::Contract,
"");
- IntegerType const addressType(0, IntegerType::Modifier::Address);
+ IntegerType const addressType(160, IntegerType::Modifier::Address);
IntegerType const& to =
toCategory == Type::Category::Integer ?
dynamic_cast<IntegerType const&>(_to) :
@@ -487,6 +487,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArray(
// TODO if this is not a byte array, we might just copy byte-by-byte anyway,
// because the encoding is position-independent, but we have to check that.
Whiskers templ(R"(
+ // <readableTypeNameFrom> -> <readableTypeNameTo>
function <functionName>(start, length, pos) -> end {
<storeLength> // might update pos
<copyFun>(start, pos, length)
@@ -495,6 +496,8 @@ string ABIFunctions::abiEncodingFunctionCalldataArray(
)");
templ("storeLength", _to.isDynamicallySized() ? "mstore(pos, length) pos := add(pos, 0x20)" : "");
templ("functionName", functionName);
+ templ("readableTypeNameFrom", _from.toString(true));
+ templ("readableTypeNameTo", _to.toString(true));
templ("copyFun", copyToMemoryFunction(true));
templ("roundUpFun", roundUpFunction());
return templ.render();
@@ -527,6 +530,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
Whiskers templ(
dynamicBase ?
R"(
+ // <readableTypeNameFrom> -> <readableTypeNameTo>
function <functionName>(value, pos) <return> {
let length := <lengthFun>(value)
<storeLength> // might update pos
@@ -545,6 +549,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
}
)" :
R"(
+ // <readableTypeNameFrom> -> <readableTypeNameTo>
function <functionName>(value, pos) <return> {
let length := <lengthFun>(value)
<storeLength> // might update pos
@@ -560,6 +565,8 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
)"
);
templ("functionName", functionName);
+ templ("readableTypeNameFrom", _from.toString(true));
+ templ("readableTypeNameTo", _to.toString(true));
templ("return", dynamic ? " -> end " : "");
templ("assignEnd", dynamic ? "end := pos" : "");
templ("lengthFun", arrayLengthFunction(_from));
@@ -639,6 +646,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
{
solAssert(_to.isByteArray(), "");
Whiskers templ(R"(
+ // <readableTypeNameFrom> -> <readableTypeNameTo>
function <functionName>(value, pos) -> ret {
let slotValue := sload(value)
switch and(slotValue, 1)
@@ -665,6 +673,8 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
}
)");
templ("functionName", functionName);
+ templ("readableTypeNameFrom", _from.toString(true));
+ templ("readableTypeNameTo", _to.toString(true));
templ("arrayDataSlot", arrayDataAreaFunction(_from));
return templ.render();
}
@@ -681,6 +691,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
// more than desired, i.e. it writes beyond the end of memory.
Whiskers templ(
R"(
+ // <readableTypeNameFrom> -> <readableTypeNameTo>
function <functionName>(value, pos) <return> {
let length := <lengthFun>(value)
<storeLength> // might update pos
@@ -701,6 +712,8 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
)"
);
templ("functionName", functionName);
+ templ("readableTypeNameFrom", _from.toString(true));
+ templ("readableTypeNameTo", _to.toString(true));
templ("return", dynamic ? " -> end " : "");
templ("assignEnd", dynamic ? "end := pos" : "");
templ("lengthFun", arrayLengthFunction(_from));
@@ -748,6 +761,7 @@ string ABIFunctions::abiEncodingFunctionStruct(
bool fromStorage = _from.location() == DataLocation::Storage;
bool dynamic = _to.isDynamicallyEncoded();
Whiskers templ(R"(
+ // <readableTypeNameFrom> -> <readableTypeNameTo>
function <functionName>(value, pos) <return> {
let tail := add(pos, <headSize>)
<init>
@@ -761,6 +775,8 @@ string ABIFunctions::abiEncodingFunctionStruct(
}
)");
templ("functionName", functionName);
+ templ("readableTypeNameFrom", _from.toString(true));
+ templ("readableTypeNameTo", _to.toString(true));
templ("return", dynamic ? " -> end " : "");
templ("assignEnd", dynamic ? "end := tail" : "");
// to avoid multiple loads from the same slot for subsequent members
@@ -995,9 +1011,11 @@ string ABIFunctions::shiftLeftFunction(size_t _numBits)
return createFunction(functionName, [&]() {
solAssert(_numBits < 256, "");
return
- Whiskers(R"(function <functionName>(value) -> newValue {
+ Whiskers(R"(
+ function <functionName>(value) -> newValue {
newValue := mul(value, <multiplier>)
- })")
+ }
+ )")
("functionName", functionName)
("multiplier", toCompactHexWithPrefix(u256(1) << _numBits))
.render();
@@ -1010,9 +1028,11 @@ string ABIFunctions::shiftRightFunction(size_t _numBits, bool _signed)
return createFunction(functionName, [&]() {
solAssert(_numBits < 256, "");
return
- Whiskers(R"(function <functionName>(value) -> newValue {
+ Whiskers(R"(
+ function <functionName>(value) -> newValue {
newValue := <div>(value, <multiplier>)
- })")
+ }
+ )")
("functionName", functionName)
("div", _signed ? "sdiv" : "div")
("multiplier", toCompactHexWithPrefix(u256(1) << _numBits))
@@ -1025,9 +1045,11 @@ string ABIFunctions::roundUpFunction()
string functionName = "round_up_to_mul_of_32";
return createFunction(functionName, [&]() {
return
- Whiskers(R"(function <functionName>(value) -> result {
+ Whiskers(R"(
+ function <functionName>(value) -> result {
result := and(add(value, 31), not(31))
- })")
+ }
+ )")
("functionName", functionName)
.render();
});
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index 37aa1aea..f9b181ae 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -191,7 +191,7 @@ void CompilerUtils::encodeToMemory(
{
// Use the new JULIA-based encoding function
auto stackHeightBefore = m_context.stackHeight();
- abiEncode(_givenTypes, targetTypes, _encodeAsLibraryTypes);
+ abiEncodeV2(_givenTypes, targetTypes, _encodeAsLibraryTypes);
solAssert(stackHeightBefore - m_context.stackHeight() == sizeOnStack(_givenTypes), "");
return;
}
@@ -302,7 +302,7 @@ void CompilerUtils::encodeToMemory(
popStackSlots(argSize + dynPointers + 1);
}
-void CompilerUtils::abiEncode(
+void CompilerUtils::abiEncodeV2(
TypePointers const& _givenTypes,
TypePointers const& _targetTypes,
bool _encodeAsLibraryTypes
@@ -541,7 +541,7 @@ void CompilerUtils::convertType(
else
{
solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Contract, "");
- IntegerType addressType(0, IntegerType::Modifier::Address);
+ IntegerType addressType(160, IntegerType::Modifier::Address);
IntegerType const& targetType = targetTypeCategory == Type::Category::Integer
? dynamic_cast<IntegerType const&>(_targetType) : addressType;
if (stackTypeCategory == Type::Category::RationalNumber)
@@ -596,7 +596,6 @@ void CompilerUtils::convertType(
storeInMemoryDynamic(IntegerType(256));
// stack: mempos datapos
storeStringData(data);
- break;
}
else
solAssert(
@@ -810,9 +809,8 @@ void CompilerUtils::convertType(
if (_cleanupNeeded)
m_context << Instruction::ISZERO << Instruction::ISZERO;
break;
- case Type::Category::Function:
- {
- if (targetTypeCategory == Type::Category::Integer)
+ default:
+ if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Integer)
{
IntegerType const& targetType = dynamic_cast<IntegerType const&>(_targetType);
solAssert(targetType.isAddress(), "Function type can only be converted to address.");
@@ -821,17 +819,16 @@ void CompilerUtils::convertType(
// stack: <address> <function_id>
m_context << Instruction::POP;
- break;
}
- }
- // fall-through
- default:
- // All other types should not be convertible to non-equal types.
- solAssert(_typeOnStack == _targetType, "Invalid type conversion requested.");
- if (_cleanupNeeded && _targetType.canBeStored() && _targetType.storageBytes() < 32)
+ else
+ {
+ // All other types should not be convertible to non-equal types.
+ solAssert(_typeOnStack == _targetType, "Invalid type conversion requested.");
+ if (_cleanupNeeded && _targetType.canBeStored() && _targetType.storageBytes() < 32)
m_context
<< ((u256(1) << (8 * _targetType.storageBytes())) - 1)
<< Instruction::AND;
+ }
break;
}
diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h
index 5e45699b..ad3989ad 100644
--- a/libsolidity/codegen/CompilerUtils.h
+++ b/libsolidity/codegen/CompilerUtils.h
@@ -102,13 +102,26 @@ public:
/// @note the locations of target reference types are ignored, because it will always be
/// memory.
void encodeToMemory(
- TypePointers const& _givenTypes = {},
- TypePointers const& _targetTypes = {},
- bool _padToWords = true,
- bool _copyDynamicDataInPlace = false,
+ TypePointers const& _givenTypes,
+ TypePointers const& _targetTypes,
+ bool _padToWords,
+ bool _copyDynamicDataInPlace,
bool _encodeAsLibraryTypes = false
);
+ /// Special case of @a encodeToMemory which assumes tight packing, e.g. no zero padding
+ /// and dynamic data is encoded in-place.
+ /// Stack pre: <value0> <value1> ... <valueN-1> <head_start>
+ /// Stack post: <mem_ptr>
+ void packedEncode(
+ TypePointers const& _givenTypes,
+ TypePointers const& _targetTypes,
+ bool _encodeAsLibraryTypes = false
+ )
+ {
+ encodeToMemory(_givenTypes, _targetTypes, false, true, _encodeAsLibraryTypes);
+ }
+
/// Special case of @a encodeToMemory which assumes that everything is padded to words
/// and dynamic data is not copied in place (i.e. a proper ABI encoding).
/// Stack pre: <value0> <value1> ... <valueN-1> <head_start>
@@ -117,6 +130,20 @@ public:
TypePointers const& _givenTypes,
TypePointers const& _targetTypes,
bool _encodeAsLibraryTypes = false
+ )
+ {
+ encodeToMemory(_givenTypes, _targetTypes, true, false, _encodeAsLibraryTypes);
+ }
+
+ /// Special case of @a encodeToMemory which assumes that everything is padded to words
+ /// and dynamic data is not copied in place (i.e. a proper ABI encoding).
+ /// Uses a new, less tested encoder implementation.
+ /// Stack pre: <value0> <value1> ... <valueN-1> <head_start>
+ /// Stack post: <mem_ptr>
+ void abiEncodeV2(
+ TypePointers const& _givenTypes,
+ TypePointers const& _targetTypes,
+ bool _encodeAsLibraryTypes = false
);
/// Zero-initialises (the data part of) an already allocated memory array.
diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp
index 92782b8d..429db532 100644
--- a/libsolidity/codegen/ContractCompiler.cpp
+++ b/libsolidity/codegen/ContractCompiler.cpp
@@ -421,7 +421,7 @@ void ContractCompiler::appendReturnValuePacker(TypePointers const& _typeParamete
utils.fetchFreeMemoryPointer();
//@todo optimization: if we return a single memory array, there should be enough space before
// its data to add the needed parts and we avoid a memory copy.
- utils.encodeToMemory(_typeParameters, _typeParameters, true, false, _isLibrary);
+ utils.abiEncode(_typeParameters, _typeParameters, _isLibrary);
utils.toSizeAfterFreeMemoryPointer();
m_context << Instruction::RETURN;
}
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index c94baa10..c2bf0f5c 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -581,7 +581,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
_context << Instruction::ADD;
}
);
- utils().encodeToMemory(argumentTypes, function.parameterTypes());
+ utils().abiEncode(argumentTypes, function.parameterTypes());
// now on stack: memory_end_ptr
// need: size, offset, endowment
utils().toSizeAfterFreeMemoryPointer();
@@ -675,7 +675,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
argumentTypes.push_back(arg->annotation().type);
}
utils().fetchFreeMemoryPointer();
- utils().encodeToMemory(argumentTypes, TypePointers(), function.padArguments(), true);
+ solAssert(!function.padArguments(), "");
+ utils().packedEncode(argumentTypes, TypePointers());
utils().toSizeAfterFreeMemoryPointer();
m_context << Instruction::KECCAK256;
break;
@@ -694,11 +695,10 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
}
arguments.front()->accept(*this);
utils().fetchFreeMemoryPointer();
- utils().encodeToMemory(
+ utils().packedEncode(
{arguments.front()->annotation().type},
- {function.parameterTypes().front()},
- false,
- true);
+ {function.parameterTypes().front()}
+ );
utils().toSizeAfterFreeMemoryPointer();
m_context << logInstruction(logNumber);
break;
@@ -717,11 +717,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
if (auto const& arrayType = dynamic_pointer_cast<ArrayType const>(function.parameterTypes()[arg - 1]))
{
utils().fetchFreeMemoryPointer();
- utils().encodeToMemory(
+ utils().packedEncode(
{arguments[arg - 1]->annotation().type},
- {arrayType},
- false,
- true
+ {arrayType}
);
utils().toSizeAfterFreeMemoryPointer();
m_context << Instruction::KECCAK256;
@@ -751,7 +749,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
nonIndexedParamTypes.push_back(function.parameterTypes()[arg]);
}
utils().fetchFreeMemoryPointer();
- utils().encodeToMemory(nonIndexedArgTypes, nonIndexedParamTypes);
+ utils().abiEncode(nonIndexedArgTypes, nonIndexedParamTypes);
// need: topic1 ... topicn memsize memstart
utils().toSizeAfterFreeMemoryPointer();
m_context << logInstruction(numIndexed);
@@ -1014,59 +1012,65 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
switch (_memberAccess.expression().annotation().type->category())
{
case Type::Category::Contract:
+ case Type::Category::Integer:
{
bool alsoSearchInteger = false;
- ContractType const& type = dynamic_cast<ContractType const&>(*_memberAccess.expression().annotation().type);
- if (type.isSuper())
+ if (_memberAccess.expression().annotation().type->category() == Type::Category::Contract)
{
- solAssert(!!_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved.");
- utils().pushCombinedFunctionEntryLabel(m_context.superFunction(
- dynamic_cast<FunctionDefinition const&>(*_memberAccess.annotation().referencedDeclaration),
- type.contractDefinition()
- ));
+ ContractType const& type = dynamic_cast<ContractType const&>(*_memberAccess.expression().annotation().type);
+ if (type.isSuper())
+ {
+ solAssert(!!_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved.");
+ utils().pushCombinedFunctionEntryLabel(m_context.superFunction(
+ dynamic_cast<FunctionDefinition const&>(*_memberAccess.annotation().referencedDeclaration),
+ type.contractDefinition()
+ ));
+ }
+ else
+ {
+ // ordinary contract type
+ if (Declaration const* declaration = _memberAccess.annotation().referencedDeclaration)
+ {
+ u256 identifier;
+ if (auto const* variable = dynamic_cast<VariableDeclaration const*>(declaration))
+ identifier = FunctionType(*variable).externalIdentifier();
+ else if (auto const* function = dynamic_cast<FunctionDefinition const*>(declaration))
+ identifier = FunctionType(*function).externalIdentifier();
+ else
+ solAssert(false, "Contract member is neither variable nor function.");
+ utils().convertType(type, IntegerType(160, IntegerType::Modifier::Address), true);
+ m_context << identifier;
+ }
+ else
+ // not found in contract, search in members inherited from address
+ alsoSearchInteger = true;
+ }
}
else
+ alsoSearchInteger = true;
+
+ if (alsoSearchInteger)
{
- // ordinary contract type
- if (Declaration const* declaration = _memberAccess.annotation().referencedDeclaration)
+ if (member == "balance")
{
- u256 identifier;
- if (auto const* variable = dynamic_cast<VariableDeclaration const*>(declaration))
- identifier = FunctionType(*variable).externalIdentifier();
- else if (auto const* function = dynamic_cast<FunctionDefinition const*>(declaration))
- identifier = FunctionType(*function).externalIdentifier();
- else
- solAssert(false, "Contract member is neither variable nor function.");
- utils().convertType(type, IntegerType(0, IntegerType::Modifier::Address), true);
- m_context << identifier;
+ utils().convertType(
+ *_memberAccess.expression().annotation().type,
+ IntegerType(160, IntegerType::Modifier::Address),
+ true
+ );
+ m_context << Instruction::BALANCE;
}
+ else if ((set<string>{"send", "transfer", "call", "callcode", "delegatecall"}).count(member))
+ utils().convertType(
+ *_memberAccess.expression().annotation().type,
+ IntegerType(160, IntegerType::Modifier::Address),
+ true
+ );
else
- // not found in contract, search in members inherited from address
- alsoSearchInteger = true;
+ solAssert(false, "Invalid member access to integer");
}
- if (!alsoSearchInteger)
- break;
- }
- // fall-through
- case Type::Category::Integer:
- if (member == "balance")
- {
- utils().convertType(
- *_memberAccess.expression().annotation().type,
- IntegerType(0, IntegerType::Modifier::Address),
- true
- );
- m_context << Instruction::BALANCE;
- }
- else if ((set<string>{"send", "transfer", "call", "callcode", "delegatecall"}).count(member))
- utils().convertType(
- *_memberAccess.expression().annotation().type,
- IntegerType(0, IntegerType::Modifier::Address),
- true
- );
- else
- solAssert(false, "Invalid member access to integer");
break;
+ }
case Type::Category::Function:
if (member == "selector")
{
@@ -1206,11 +1210,9 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
utils().fetchFreeMemoryPointer();
// stack: base index mem
// note: the following operations must not allocate memory!
- utils().encodeToMemory(
+ utils().packedEncode(
TypePointers{_indexAccess.indexExpression()->annotation().type},
- TypePointers{keyType},
- false,
- true
+ TypePointers{keyType}
);
m_context << Instruction::SWAP1;
utils().storeInMemoryDynamic(IntegerType(256));