diff options
Diffstat (limited to 'libsolidity/codegen')
-rw-r--r-- | libsolidity/codegen/ABIFunctions.cpp | 38 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerUtils.cpp | 25 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerUtils.h | 35 | ||||
-rw-r--r-- | libsolidity/codegen/ContractCompiler.cpp | 2 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 116 |
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)); |