aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/codegen')
-rw-r--r--libsolidity/codegen/ABIFunctions.cpp128
-rw-r--r--libsolidity/codegen/ABIFunctions.h7
-rw-r--r--libsolidity/codegen/CompilerContext.cpp20
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp2
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp2
-rw-r--r--libsolidity/codegen/ContractCompiler.h4
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp2
-rw-r--r--libsolidity/codegen/ExpressionCompiler.h2
8 files changed, 154 insertions, 13 deletions
diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp
index 3a9f1a48..9f6c55ba 100644
--- a/libsolidity/codegen/ABIFunctions.cpp
+++ b/libsolidity/codegen/ABIFunctions.cpp
@@ -404,9 +404,11 @@ string ABIFunctions::abiEncodingFunction(
else
solAssert(false, "");
}
- else if (dynamic_cast<StructType const*>(&to))
+ else if (auto const* toStruct = dynamic_cast<StructType const*>(&to))
{
- solUnimplementedAssert(false, "Structs not yet implemented.");
+ StructType const* fromStruct = dynamic_cast<StructType const*>(&_from);
+ solAssert(fromStruct, "");
+ return abiEncodingFunctionStruct(*fromStruct, *toStruct, _encodeAsLibraryTypes);
}
else if (_from.category() == Type::Category::Function)
return abiEncodingFunctionFunctionType(
@@ -534,7 +536,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
for { let i := 0 } lt(i, length) { i := add(i, 1) }
{
mstore(pos, sub(tail, headStart))
- tail := <encodeToMemoryFun>(<arrayElementAccess>(srcPtr), tail)
+ tail := <encodeToMemoryFun>(<arrayElementAccess>, tail)
srcPtr := <nextArrayElement>(srcPtr)
pos := add(pos, <elementEncodedSize>)
}
@@ -549,7 +551,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
let srcPtr := <dataAreaFun>(value)
for { let i := 0 } lt(i, length) { i := add(i, 1) }
{
- <encodeToMemoryFun>(<arrayElementAccess>(srcPtr), pos)
+ <encodeToMemoryFun>(<arrayElementAccess>, pos)
srcPtr := <nextArrayElement>(srcPtr)
pos := add(pos, <elementEncodedSize>)
}
@@ -573,7 +575,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
_encodeAsLibraryTypes,
true
));
- templ("arrayElementAccess", inMemory ? "mload" : "sload");
+ templ("arrayElementAccess", inMemory ? "mload(srcPtr)" : _from.baseType()->isValueType() ? "sload(srcPtr)" : "srcPtr" );
templ("nextArrayElement", nextArrayElementFunction(_from));
return templ.render();
});
@@ -726,6 +728,122 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
});
}
+string ABIFunctions::abiEncodingFunctionStruct(
+ StructType const& _from,
+ StructType const& _to,
+ bool _encodeAsLibraryTypes
+)
+{
+ string functionName =
+ "abi_encode_" +
+ _from.identifier() +
+ "_to_" +
+ _to.identifier() +
+ (_encodeAsLibraryTypes ? "_library" : "");
+
+ solUnimplementedAssert(!_from.dataStoredIn(DataLocation::CallData), "");
+ solAssert(&_from.structDefinition() == &_to.structDefinition(), "");
+
+ return createFunction(functionName, [&]() {
+ bool fromStorage = _from.location() == DataLocation::Storage;
+ bool dynamic = _to.isDynamicallyEncoded();
+ Whiskers templ(R"(
+ function <functionName>(value, pos) <return> {
+ let tail := add(pos, <headSize>)
+ <init>
+ <#members>
+ {
+ // <memberName>
+ <encode>
+ }
+ </members>
+ <assignEnd>
+ }
+ )");
+ templ("functionName", functionName);
+ templ("return", dynamic ? " -> end " : "");
+ templ("assignEnd", dynamic ? "end := tail" : "");
+ // to avoid multiple loads from the same slot for subsequent members
+ templ("init", fromStorage ? "let slotValue := 0" : "");
+ u256 previousSlotOffset(-1);
+ u256 encodingOffset = 0;
+ vector<map<string, string>> members;
+ for (auto const& member: _to.members(nullptr))
+ {
+ solAssert(member.type, "");
+ if (!member.type->canLiveOutsideStorage())
+ continue;
+ solUnimplementedAssert(
+ member.type->mobileType() &&
+ member.type->mobileType()->interfaceType(_encodeAsLibraryTypes) &&
+ member.type->mobileType()->interfaceType(_encodeAsLibraryTypes)->encodingType(),
+ "Encoding type \"" + member.type->toString() + "\" not yet implemented."
+ );
+ auto memberTypeTo = member.type->mobileType()->interfaceType(_encodeAsLibraryTypes)->encodingType();
+ auto memberTypeFrom = _from.memberType(member.name);
+ solAssert(memberTypeFrom, "");
+ bool dynamicMember = memberTypeTo->isDynamicallyEncoded();
+ if (dynamicMember)
+ solAssert(dynamic, "");
+ Whiskers memberTempl(R"(
+ <preprocess>
+ let memberValue := <retrieveValue>
+ )" + (
+ dynamicMember ?
+ string(R"(
+ mstore(add(pos, <encodingOffset>), sub(tail, pos))
+ tail := <abiEncode>(memberValue, tail)
+ )") :
+ string(R"(
+ <abiEncode>(memberValue, add(pos, <encodingOffset>))
+ )")
+ )
+ );
+ if (fromStorage)
+ {
+ solAssert(memberTypeFrom->isValueType() == memberTypeTo->isValueType(), "");
+ u256 storageSlotOffset;
+ size_t intraSlotOffset;
+ tie(storageSlotOffset, intraSlotOffset) = _from.storageOffsetsOfMember(member.name);
+ if (memberTypeFrom->isValueType())
+ {
+ if (storageSlotOffset != previousSlotOffset)
+ {
+ memberTempl("preprocess", "slotValue := sload(add(value, " + toCompactHexWithPrefix(storageSlotOffset) + "))");
+ previousSlotOffset = storageSlotOffset;
+ }
+ else
+ memberTempl("preprocess", "");
+ memberTempl("retrieveValue", shiftRightFunction(intraSlotOffset * 8, false) + "(slotValue)");
+ }
+ else
+ {
+ solAssert(memberTypeFrom->dataStoredIn(DataLocation::Storage), "");
+ solAssert(intraSlotOffset == 0, "");
+ memberTempl("preprocess", "");
+ memberTempl("retrieveValue", "add(value, " + toCompactHexWithPrefix(storageSlotOffset) + ")");
+ }
+ }
+ else
+ {
+ memberTempl("preprocess", "");
+ string sourceOffset = toCompactHexWithPrefix(_from.memoryOffsetOfMember(member.name));
+ memberTempl("retrieveValue", "mload(add(value, " + sourceOffset + "))");
+ }
+ memberTempl("encodingOffset", toCompactHexWithPrefix(encodingOffset));
+ encodingOffset += dynamicMember ? 0x20 : memberTypeTo->calldataEncodedSize();
+ memberTempl("abiEncode", abiEncodingFunction(*memberTypeFrom, *memberTypeTo, _encodeAsLibraryTypes, false));
+
+ members.push_back({});
+ members.back()["encode"] = memberTempl.render();
+ members.back()["memberName"] = member.name;
+ }
+ templ("members", members);
+ templ("headSize", toCompactHexWithPrefix(encodingOffset));
+ return templ.render();
+ });
+}
+
string ABIFunctions::abiEncodingFunctionStringLiteral(
Type const& _from,
Type const& _to,
diff --git a/libsolidity/codegen/ABIFunctions.h b/libsolidity/codegen/ABIFunctions.h
index 5bbd842f..de2a140a 100644
--- a/libsolidity/codegen/ABIFunctions.h
+++ b/libsolidity/codegen/ABIFunctions.h
@@ -123,6 +123,13 @@ private:
bool _encodeAsLibraryTypes
);
+ /// Part of @a abiEncodingFunction for struct types.
+ std::string abiEncodingFunctionStruct(
+ StructType const& _givenType,
+ StructType const& _targetType,
+ bool _encodeAsLibraryTypes
+ );
+
// @returns the name of the ABI encoding function with the given type
// and queues the generation of the function to the requested functions.
// Case for _givenType being a string literal
diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp
index 5a77162e..d87c7be5 100644
--- a/libsolidity/codegen/CompilerContext.cpp
+++ b/libsolidity/codegen/CompilerContext.cpp
@@ -26,6 +26,7 @@
#include <libsolidity/codegen/Compiler.h>
#include <libsolidity/interface/Version.h>
#include <libsolidity/interface/ErrorReporter.h>
+#include <libsolidity/interface/SourceReferenceFormatter.h>
#include <libsolidity/parsing/Scanner.h>
#include <libsolidity/inlineasm/AsmParser.h>
#include <libsolidity/inlineasm/AsmCodeGen.h>
@@ -312,8 +313,23 @@ void CompilerContext::appendInlineAssembly(
ErrorReporter errorReporter(errors);
auto scanner = make_shared<Scanner>(CharStream(_assembly), "--CODEGEN--");
auto parserResult = assembly::Parser(errorReporter).parse(scanner);
- solAssert(parserResult, "Failed to parse inline assembly block.");
- solAssert(errorReporter.errors().empty(), "Failed to parse inline assembly block.");
+ if (!parserResult || !errorReporter.errors().empty())
+ {
+ string message =
+ "Error parsing inline assembly block:\n"
+ "------------------ Input: -----------------\n" +
+ _assembly + "\n"
+ "------------------ Errors: ----------------\n";
+ for (auto const& error: errorReporter.errors())
+ message += SourceReferenceFormatter::formatExceptionInformation(
+ *error,
+ (error->type() == Error::Type::Warning) ? "Warning" : "Error",
+ [&](string const&) -> Scanner const& { return *scanner; }
+ );
+ message += "-------------------------------------------\n";
+
+ solAssert(false, message);
+ }
assembly::AsmAnalysisInfo analysisInfo;
assembly::AsmAnalyzer analyzer(analysisInfo, errorReporter, false, identifierAccess.resolve);
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index 1e623357..37aa1aea 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -121,7 +121,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
{
if (auto ref = dynamic_cast<ReferenceType const*>(&_type))
{
- solAssert(ref->location() == DataLocation::Memory, "");
+ solUnimplementedAssert(ref->location() == DataLocation::Memory, "");
storeInMemoryDynamic(IntegerType(256), _padToWordBoundaries);
}
else if (auto str = dynamic_cast<StringLiteralType const*>(&_type))
diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp
index 51496368..92782b8d 100644
--- a/libsolidity/codegen/ContractCompiler.cpp
+++ b/libsolidity/codegen/ContractCompiler.cpp
@@ -333,7 +333,7 @@ void ContractCompiler::appendCalldataUnpacker(TypePointers const& _typeParameter
{
// stack: v1 v2 ... v(k-1) base_offset current_offset
TypePointer type = parameterType->decodingType();
- solAssert(type, "No decoding type found.");
+ solUnimplementedAssert(type, "No decoding type found.");
if (type->category() == Type::Category::Array)
{
auto const& arrayType = dynamic_cast<ArrayType const&>(*type);
diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h
index 38c1e045..7c5ee59f 100644
--- a/libsolidity/codegen/ContractCompiler.h
+++ b/libsolidity/codegen/ContractCompiler.h
@@ -96,8 +96,8 @@ private:
virtual bool visit(IfStatement const& _ifStatement) override;
virtual bool visit(WhileStatement const& _whileStatement) override;
virtual bool visit(ForStatement const& _forStatement) override;
- virtual bool visit(Continue const& _continue) override;
- virtual bool visit(Break const& _break) override;
+ virtual bool visit(Continue const& _continueStatement) override;
+ virtual bool visit(Break const& _breakStatement) override;
virtual bool visit(Return const& _return) override;
virtual bool visit(Throw const& _throw) override;
virtual bool visit(VariableDeclarationStatement const& _variableDeclarationStatement) override;
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 631a25ff..c94baa10 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -1819,7 +1819,7 @@ void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression)
setLValue<StorageItem>(_expression, *_expression.annotation().type);
}
-bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token::Value _op) const
+bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token::Value _op)
{
if (Token::isCompareOp(_op) || Token::isShiftOp(_op))
return true;
diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h
index 5f6c3d64..cdfa096e 100644
--- a/libsolidity/codegen/ExpressionCompiler.h
+++ b/libsolidity/codegen/ExpressionCompiler.h
@@ -119,7 +119,7 @@ private:
/// @returns true if the operator applied to the given type requires a cleanup prior to the
/// operation.
- bool cleanupNeededForOp(Type::Category _type, Token::Value _op) const;
+ static bool cleanupNeededForOp(Type::Category _type, Token::Value _op);
/// @returns the CompilerUtils object containing the current context.
CompilerUtils utils();