From f627dc77d01a9367b41d4a2e1654f045f9e4264a Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 14 May 2018 15:26:10 +0200 Subject: Fix continue inside do-while. --- libsolidity/codegen/ContractCompiler.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 0889ac7c..f195b416 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -666,32 +666,36 @@ bool ContractCompiler::visit(WhileStatement const& _whileStatement) { StackHeightChecker checker(m_context); CompilerContext::LocationSetter locationSetter(m_context, _whileStatement); + eth::AssemblyItem loopStart = m_context.newTag(); eth::AssemblyItem loopEnd = m_context.newTag(); - m_continueTags.push_back(loopStart); m_breakTags.push_back(loopEnd); m_context << loopStart; - // While loops have the condition prepended - if (!_whileStatement.isDoWhile()) + if (_whileStatement.isDoWhile()) { - compileExpression(_whileStatement.condition()); - m_context << Instruction::ISZERO; - m_context.appendConditionalJumpTo(loopEnd); - } + eth::AssemblyItem condition = m_context.newTag(); + m_continueTags.push_back(condition); - _whileStatement.body().accept(*this); + _whileStatement.body().accept(*this); - // Do-while loops have the condition appended - if (_whileStatement.isDoWhile()) + m_context << condition; + compileExpression(_whileStatement.condition()); + m_context << Instruction::ISZERO << Instruction::ISZERO; + m_context.appendConditionalJumpTo(loopStart); + } + else { + m_continueTags.push_back(loopStart); compileExpression(_whileStatement.condition()); m_context << Instruction::ISZERO; m_context.appendConditionalJumpTo(loopEnd); - } - m_context.appendJumpTo(loopStart); + _whileStatement.body().accept(*this); + + m_context.appendJumpTo(loopStart); + } m_context << loopEnd; m_continueTags.pop_back(); -- cgit v1.2.3 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 ++++++++++++++++++++++++++++++ libsolidity/codegen/ArrayUtils.h | 5 +++++ libsolidity/codegen/ExpressionCompiler.cpp | 27 +++++++++++++++++++++++- 3 files changed, 64 insertions(+), 1 deletion(-) (limited to 'libsolidity/codegen') 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( diff --git a/libsolidity/codegen/ArrayUtils.h b/libsolidity/codegen/ArrayUtils.h index 99786397..84d591d7 100644 --- a/libsolidity/codegen/ArrayUtils.h +++ b/libsolidity/codegen/ArrayUtils.h @@ -73,6 +73,11 @@ public: /// Stack pre: reference (excludes byte offset) /// Stack post: new_length void incrementDynamicArraySize(ArrayType const& _type) const; + /// Decrements the size of a dynamic array by one if length is nonzero. Returns otherwise. + /// Clears the removed data element. In case of a byte array, this might move the data. + /// Stack pre: reference + /// Stack post: + void popStorageArrayElement(ArrayType const& _type) const; /// Appends a loop that clears a sequence of storage slots of the given type (excluding end). /// Stack pre: end_ref start_ref /// Stack post: end_ref diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 4bcc1fa9..ac7610fc 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -866,6 +866,20 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) StorageByteArrayElement(m_context).storeValue(*type, _functionCall.location(), true); break; } + case FunctionType::Kind::ByteArrayPop: + case FunctionType::Kind::ArrayPop: + { + _functionCall.expression().accept(*this); + solAssert(function.parameterTypes().empty(), ""); + + ArrayType const& arrayType = dynamic_cast( + *dynamic_cast(_functionCall.expression()).expression().annotation().type + ); + solAssert(arrayType.dataStoredIn(DataLocation::Storage), ""); + + ArrayUtils(m_context).popStorageArrayElement(arrayType); + break; + } case FunctionType::Kind::ObjectCreation: { ArrayType const& arrayType = dynamic_cast(*_functionCall.annotation().type); @@ -1348,10 +1362,21 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) else if (member == "push") { solAssert( - type.isDynamicallySized() && type.location() == DataLocation::Storage, + type.isDynamicallySized() && + type.location() == DataLocation::Storage && + type.category() == Type::Category::Array, "Tried to use .push() on a non-dynamically sized array" ); } + else if (member == "pop") + { + solAssert( + type.isDynamicallySized() && + type.location() == DataLocation::Storage && + type.category() == Type::Category::Array, + "Tried to use .pop() on a non-dynamically sized array" + ); + } else solAssert(false, "Illegal array member."); break; -- 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') 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 +++++++++++------------------- libsolidity/codegen/ExpressionCompiler.cpp | 14 ++----------- 2 files changed, 14 insertions(+), 32 deletions(-) (limited to 'libsolidity/codegen') 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; } diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index ac7610fc..93d440c8 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -866,7 +866,6 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) StorageByteArrayElement(m_context).storeValue(*type, _functionCall.location(), true); break; } - case FunctionType::Kind::ByteArrayPop: case FunctionType::Kind::ArrayPop: { _functionCall.expression().accept(*this); @@ -1359,22 +1358,13 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) break; } } - else if (member == "push") + else if (member == "push" || member == "pop") { solAssert( type.isDynamicallySized() && type.location() == DataLocation::Storage && type.category() == Type::Category::Array, - "Tried to use .push() on a non-dynamically sized array" - ); - } - else if (member == "pop") - { - solAssert( - type.isDynamicallySized() && - type.location() == DataLocation::Storage && - type.category() == Type::Category::Array, - "Tried to use .pop() on a non-dynamically sized array" + "Tried to use ." + member + "() on a non-dynamically sized array" ); } else -- 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 +- libsolidity/codegen/ArrayUtils.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'libsolidity/codegen') 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)) diff --git a/libsolidity/codegen/ArrayUtils.h b/libsolidity/codegen/ArrayUtils.h index 84d591d7..daf50bf5 100644 --- a/libsolidity/codegen/ArrayUtils.h +++ b/libsolidity/codegen/ArrayUtils.h @@ -73,7 +73,7 @@ public: /// Stack pre: reference (excludes byte offset) /// Stack post: new_length void incrementDynamicArraySize(ArrayType const& _type) const; - /// Decrements the size of a dynamic array by one if length is nonzero. Returns otherwise. + /// Decrements the size of a dynamic array by one if length is nonzero. Causes an invalid instruction otherwise. /// Clears the removed data element. In case of a byte array, this might move the data. /// Stack pre: reference /// Stack post: -- 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') 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 1d57d74e82ffc032da2ce3289d878f2eee29b1b2 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 12 Jun 2018 00:46:23 +0100 Subject: Fail if break/continue statements are used outside for/while loops in ContractCompiler --- libsolidity/codegen/ContractCompiler.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index f195b416..81aba21e 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -749,16 +749,16 @@ bool ContractCompiler::visit(ForStatement const& _forStatement) bool ContractCompiler::visit(Continue const& _continueStatement) { CompilerContext::LocationSetter locationSetter(m_context, _continueStatement); - if (!m_continueTags.empty()) - m_context.appendJumpTo(m_continueTags.back()); + solAssert(!m_continueTags.empty(), ""); + m_context.appendJumpTo(m_continueTags.back()); return false; } bool ContractCompiler::visit(Break const& _breakStatement) { CompilerContext::LocationSetter locationSetter(m_context, _breakStatement); - if (!m_breakTags.empty()) - m_context.appendJumpTo(m_breakTags.back()); + solAssert(!m_breakTags.empty(), ""); + m_context.appendJumpTo(m_breakTags.back()); return false; } -- cgit v1.2.3 From f33dc92cbd908a6d852368fa30144bda9e8da439 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 7 May 2018 19:09:52 +0200 Subject: Use proper SAR for signed right shifts and emulate on pre-constantinople. --- libsolidity/codegen/ExpressionCompiler.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 93d440c8..908c703a 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1737,11 +1737,28 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator, Type co m_context << u256(2) << Instruction::EXP << Instruction::MUL; break; case Token::SAR: - // NOTE: SAR rounds differently than SDIV - if (m_context.evmVersion().hasBitwiseShifting() && !c_valueSigned) - m_context << Instruction::SHR; + if (m_context.evmVersion().hasBitwiseShifting()) + m_context << (c_valueSigned ? Instruction::SAR : Instruction::SHR); else - m_context << u256(2) << Instruction::EXP << Instruction::SWAP1 << (c_valueSigned ? Instruction::SDIV : Instruction::DIV); + { + if (c_valueSigned) + // For negative values xor_mask has all bits set and xor(value_to_shift, xor_mask) will be + // the bitwise complement of value_to_shift, i.e. abs(value_to_shift) - 1. Dividing this by + // exp(2, shift_amount) results in a value that is positive and strictly smaller than the + // absolute value of the desired result. Taking the complement again changes the sign + // back to negative and subtracts one, resulting in rounding towards negative infinity. + // For positive values xor_mask is zero and xor(value_to_shift, xor_mask) is again value_to_shift. + m_context.appendInlineAssembly(R"({ + let xor_mask := sub(0, slt(value_to_shift, 0)) + value_to_shift := xor(div(xor(value_to_shift, xor_mask), exp(2, shift_amount)), xor_mask) + })", {"value_to_shift", "shift_amount"}); + else + m_context.appendInlineAssembly(R"({ + value_to_shift := div(value_to_shift, exp(2, shift_amount)) + })", {"value_to_shift", "shift_amount"}); + m_context << Instruction::POP; + + } break; case Token::SHR: default: -- cgit v1.2.3 From e84b55bd6feded46789d2d398cd1b4092ef7a1c0 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Thu, 7 Jun 2018 17:08:42 +0200 Subject: Extend explanatory remark and argue using bitwise operations instead of rounding. --- libsolidity/codegen/ExpressionCompiler.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 908c703a..0470c3ec 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1742,12 +1742,20 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator, Type co else { if (c_valueSigned) - // For negative values xor_mask has all bits set and xor(value_to_shift, xor_mask) will be - // the bitwise complement of value_to_shift, i.e. abs(value_to_shift) - 1. Dividing this by - // exp(2, shift_amount) results in a value that is positive and strictly smaller than the - // absolute value of the desired result. Taking the complement again changes the sign - // back to negative and subtracts one, resulting in rounding towards negative infinity. - // For positive values xor_mask is zero and xor(value_to_shift, xor_mask) is again value_to_shift. + // In the following assembly snippet, xor_mask will be zero, if value_to_shift is positive. + // Therefor xor'ing with xor_mask is the identity and the computation reduces to + // div(value_to_shift, exp(2, shift_amount)), which is correct, since for positive values + // arithmetic right shift is dividing by a power of two (which, as a bitwise operation, results + // in discarding bits on the right and filling with zeros from the left). + // For negative values arithmetic right shift, viewed as a bitwise operation, discards bits to the + // right and fills in ones from the left. This is achieved as follows: + // If value_to_shift is negative, then xor_mask will have all bits set, so xor'ing with xor_mask + // will flip all bits. First all bits in value_to_shift are flipped. As for the positive case, + // dividing by a power of two using integer arithmetic results in discarding bits to the right + // and filling with zeros from the left. Flipping all bits in the result again, turns all zeros + // on the left to ones and restores the non-discarded, shifted bits to their original value (they + // have now been flipped twice). In summary we now have discarded bits to the right and filled with + // ones from the left, i.e. we have performed an arithmetic right shift. m_context.appendInlineAssembly(R"({ let xor_mask := sub(0, slt(value_to_shift, 0)) value_to_shift := xor(div(xor(value_to_shift, xor_mask), exp(2, shift_amount)), xor_mask) -- 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') 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 4cdb6c809a15f22085ae5850c99e05c60be8cb1b Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 12 Jun 2018 19:28:52 +0100 Subject: Change comments --- libsolidity/codegen/ABIFunctions.cpp | 4 ++-- libsolidity/codegen/ABIFunctions.h | 2 +- libsolidity/codegen/CompilerUtils.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 3e3aa0ae..4818e111 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -17,7 +17,7 @@ /** * @author Christian * @date 2017 - * Routines that generate JULIA code related to ABI encoding, decoding and type conversions. + * Routines that generate Yul code related to ABI encoding, decoding and type conversions. */ #include @@ -989,7 +989,7 @@ string ABIFunctions::abiEncodingFunctionStringLiteral( )"); templ("functionName", functionName); - // TODO this can make use of CODECOPY for large strings once we have that in JULIA + // TODO this can make use of CODECOPY for large strings once we have that in Yul size_t words = (value.size() + 31) / 32; templ("overallSize", to_string(32 + words * 32)); templ("length", to_string(value.size())); diff --git a/libsolidity/codegen/ABIFunctions.h b/libsolidity/codegen/ABIFunctions.h index db4d40f5..6bfb3f15 100644 --- a/libsolidity/codegen/ABIFunctions.h +++ b/libsolidity/codegen/ABIFunctions.h @@ -17,7 +17,7 @@ /** * @author Christian * @date 2017 - * Routines that generate JULIA code related to ABI encoding, decoding and type conversions. + * Routines that generate Yul code related to ABI encoding, decoding and type conversions. */ #pragma once diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index d9f17263..3446be55 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -186,7 +186,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem /// Stack: if (m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)) { - // Use the new JULIA-based decoding function + // Use the new Yul-based decoding function auto stackHeightBefore = m_context.stackHeight(); abiDecodeV2(_typeParameters, _fromMemory); solAssert(m_context.stackHeight() - stackHeightBefore == sizeOnStack(_typeParameters) - 2, ""); @@ -368,7 +368,7 @@ void CompilerUtils::encodeToMemory( m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2) ) { - // Use the new JULIA-based encoding function + // Use the new Yul-based encoding function auto stackHeightBefore = m_context.stackHeight(); abiEncodeV2(_givenTypes, targetTypes, _encodeAsLibraryTypes); solAssert(stackHeightBefore - m_context.stackHeight() == sizeOnStack(_givenTypes), ""); -- cgit v1.2.3 From 0e66a1ddde9ad3cf3c05e43afc808431e63ac588 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 7 May 2018 22:34:31 +0200 Subject: Single bytes argument. In 0.5.0 mode, only accept a single bytes argument for ``.call``, ``keccak256`` and others and do not pad when encoding. --- libsolidity/codegen/ExpressionCompiler.cpp | 39 +++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 11 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 0470c3ec..6b0cd92e 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1802,13 +1802,14 @@ void ExpressionCompiler::appendExternalFunctionCall( if (_functionType.bound()) utils().moveToStackTop(gasValueSize, _functionType.selfType()->sizeOnStack()); + bool const v050 = m_context.experimentalFeatureActive(ExperimentalFeature::V050); auto funKind = _functionType.kind(); bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall; bool isCallCode = funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::CallCode; bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall; bool useStaticCall = _functionType.stateMutability() <= StateMutability::View && - m_context.experimentalFeatureActive(ExperimentalFeature::V050) && + v050 && m_context.evmVersion().hasStaticCall(); bool haveReturndatacopy = m_context.evmVersion().supportsReturndata(); @@ -1836,6 +1837,7 @@ void ExpressionCompiler::appendExternalFunctionCall( // Evaluate arguments. TypePointers argumentTypes; TypePointers parameterTypes = _functionType.parameterTypes(); + // This can be removed (will always be false) with 0.5.0 bool manualFunctionId = false; if ( (funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall) && @@ -1908,16 +1910,31 @@ void ExpressionCompiler::appendExternalFunctionCall( m_context << dupInstruction(2 + gasValueSize + CompilerUtils::sizeOnStack(argumentTypes)); utils().storeInMemoryDynamic(IntegerType(8 * CompilerUtils::dataStartOffset), false); } - // If the function takes arbitrary parameters, copy dynamic length data in place. - // Move arguments to memory, will not update the free memory pointer (but will update the memory - // pointer on the stack). - utils().encodeToMemory( - argumentTypes, - parameterTypes, - _functionType.padArguments(), - _functionType.takesArbitraryParameters(), - isCallCode || isDelegateCall - ); + + // This is a function that takes a single bytes parameter which is supposed to be passed + // on inline and without padding. + if (_functionType.takesSinglePackedBytesParameter() && v050 && argumentTypes.size() == 1) + { + utils().encodeToMemory( + argumentTypes, + TypePointers{make_shared(DataLocation::Memory)}, + false, + true + ); + } + else + { + // If the function takes arbitrary parameters, copy dynamic length data in place. + // Move arguments to memory, will not update the free memory pointer (but will update the memory + // pointer on the stack). + utils().encodeToMemory( + argumentTypes, + parameterTypes, + _functionType.padArguments(), + _functionType.takesArbitraryParameters(), + isCallCode || isDelegateCall + ); + } // Stack now: // -- cgit v1.2.3 From 23c414200570b8751bde3fbcb3a3f7105e9ad8f8 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 18 May 2018 18:03:41 +0200 Subject: Bare functions take single bytes argument. --- libsolidity/codegen/ExpressionCompiler.cpp | 71 +++++++----------------------- 1 file changed, 15 insertions(+), 56 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 6b0cd92e..e579264e 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1837,39 +1837,12 @@ void ExpressionCompiler::appendExternalFunctionCall( // Evaluate arguments. TypePointers argumentTypes; TypePointers parameterTypes = _functionType.parameterTypes(); - // This can be removed (will always be false) with 0.5.0 - bool manualFunctionId = false; - if ( - (funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall) && - !_arguments.empty() - ) - { - solAssert(_arguments.front()->annotation().type->mobileType(), ""); - manualFunctionId = - _arguments.front()->annotation().type->mobileType()->calldataEncodedSize(false) == - CompilerUtils::dataStartOffset; - } - if (manualFunctionId) - { - // If we have a Bare* and the first type has exactly 4 bytes, use it as - // function identifier. - _arguments.front()->accept(*this); - utils().convertType( - *_arguments.front()->annotation().type, - IntegerType(8 * CompilerUtils::dataStartOffset), - true - ); - for (unsigned i = 0; i < gasValueSize; ++i) - m_context << swapInstruction(gasValueSize - i); - gasStackPos++; - valueStackPos++; - } if (_functionType.bound()) { argumentTypes.push_back(_functionType.selfType()); parameterTypes.insert(parameterTypes.begin(), _functionType.selfType()); } - for (size_t i = manualFunctionId ? 1 : 0; i < _arguments.size(); ++i) + for (size_t i = 0; i < _arguments.size(); ++i) { _arguments[i]->accept(*this); argumentTypes.push_back(_arguments[i]->annotation().type); @@ -1905,36 +1878,22 @@ void ExpressionCompiler::appendExternalFunctionCall( // Copy function identifier to memory. utils().fetchFreeMemoryPointer(); - if (!_functionType.isBareCall() || manualFunctionId) + if (!_functionType.isBareCall()) { m_context << dupInstruction(2 + gasValueSize + CompilerUtils::sizeOnStack(argumentTypes)); utils().storeInMemoryDynamic(IntegerType(8 * CompilerUtils::dataStartOffset), false); } - // This is a function that takes a single bytes parameter which is supposed to be passed - // on inline and without padding. - if (_functionType.takesSinglePackedBytesParameter() && v050 && argumentTypes.size() == 1) - { - utils().encodeToMemory( - argumentTypes, - TypePointers{make_shared(DataLocation::Memory)}, - false, - true - ); - } - else - { - // If the function takes arbitrary parameters, copy dynamic length data in place. - // Move arguments to memory, will not update the free memory pointer (but will update the memory - // pointer on the stack). - utils().encodeToMemory( - argumentTypes, - parameterTypes, - _functionType.padArguments(), - _functionType.takesArbitraryParameters(), - isCallCode || isDelegateCall - ); - } + // If the function takes arbitrary parameters or is a bare call, copy dynamic length data in place. + // Move arguments to memory, will not update the free memory pointer (but will update the memory + // pointer on the stack). + utils().encodeToMemory( + argumentTypes, + parameterTypes, + _functionType.padArguments(), + _functionType.takesArbitraryParameters() || _functionType.isBareCall(), + isCallCode || isDelegateCall + ); // Stack now: // @@ -2013,9 +1972,9 @@ void ExpressionCompiler::appendExternalFunctionCall( unsigned remainsSize = 2 + // contract address, input_memory_end - _functionType.valueSet() + - _functionType.gasSet() + - (!_functionType.isBareCall() || manualFunctionId); + (_functionType.valueSet() ? 1 : 0) + + (_functionType.gasSet() ? 1 : 0) + + (!_functionType.isBareCall() ? 1 : 0); if (returnSuccessCondition) m_context << swapInstruction(remainsSize); -- cgit v1.2.3 From a55e8c93ce1c3982ec224eacbb56cca243acb15e Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 23 May 2018 16:55:58 +0200 Subject: Save double encode call for sha3. --- libsolidity/codegen/ExpressionCompiler.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index e579264e..ecbd0243 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -699,16 +699,24 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) } case FunctionType::Kind::SHA3: { - TypePointers argumentTypes; - for (auto const& arg: arguments) + solAssert(arguments.size() == 1, ""); + solAssert(!function.padArguments(), ""); + TypePointer const& argType = arguments.front()->annotation().type; + solAssert(argType, ""); + arguments.front()->accept(*this); + // Optimization: If type is bytes or string, then do not encode, + // but directly compute keccak256 on memory. + if (*argType == ArrayType(DataLocation::Memory) || *argType == ArrayType(DataLocation::Memory, true)) { - arg->accept(*this); - argumentTypes.push_back(arg->annotation().type); + ArrayUtils(m_context).retrieveLength(ArrayType(DataLocation::Memory)); + m_context << Instruction::SWAP1 << u256(0x20) << Instruction::ADD; + } + else + { + utils().fetchFreeMemoryPointer(); + utils().packedEncode({argType}, TypePointers()); + utils().toSizeAfterFreeMemoryPointer(); } - utils().fetchFreeMemoryPointer(); - solAssert(!function.padArguments(), ""); - utils().packedEncode(argumentTypes, TypePointers()); - utils().toSizeAfterFreeMemoryPointer(); m_context << Instruction::KECCAK256; break; } -- cgit v1.2.3 From 7763d21cc6181204b1454437b051ac56d3e89339 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Mon, 4 Jun 2018 12:31:18 +0200 Subject: Revert if calldata is too short or points out of bounds --- libsolidity/codegen/CompilerUtils.cpp | 78 ++++++++++++------------------ libsolidity/codegen/CompilerUtils.h | 2 +- libsolidity/codegen/ExpressionCompiler.cpp | 2 +- 3 files changed, 34 insertions(+), 48 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 3446be55..a5e96335 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -181,7 +181,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound } } -void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMemory, bool _revertOnOutOfBounds) +void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMemory) { /// Stack: if (m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)) @@ -194,14 +194,10 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem } //@todo this does not yet support nested dynamic arrays - - if (_revertOnOutOfBounds) - { - size_t encodedSize = 0; - for (auto const& t: _typeParameters) - encodedSize += t->decodingType()->calldataEncodedSize(true); - m_context.appendInlineAssembly("{ if lt(len, " + to_string(encodedSize) + ") { revert(0, 0) } }", {"len"}); - } + size_t encodedSize = 0; + for (auto const& t: _typeParameters) + encodedSize += t->decodingType()->calldataEncodedSize(true); + m_context.appendInlineAssembly("{ if lt(len, " + to_string(encodedSize) + ") { revert(0, 0) } }", {"len"}); m_context << Instruction::DUP2 << Instruction::ADD; m_context << Instruction::SWAP1; @@ -231,26 +227,21 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem { // compute data pointer m_context << Instruction::DUP1 << Instruction::MLOAD; - if (_revertOnOutOfBounds) - { - // Check that the data pointer is valid and that length times - // item size is still inside the range. - Whiskers templ(R"({ - if gt(ptr, 0x100000000) { revert(0, 0) } - ptr := add(ptr, base_offset) - let array_data_start := add(ptr, 0x20) - if gt(array_data_start, input_end) { revert(0, 0) } - let array_length := mload(ptr) - if or( - gt(array_length, 0x100000000), - gt(add(array_data_start, mul(array_length, )), input_end) - ) { revert(0, 0) } - })"); - templ("item_size", to_string(arrayType.isByteArray() ? 1 : arrayType.baseType()->calldataEncodedSize(true))); - m_context.appendInlineAssembly(templ.render(), {"input_end", "base_offset", "offset", "ptr"}); - } - else - m_context << Instruction::DUP3 << Instruction::ADD; + // Check that the data pointer is valid and that length times + // item size is still inside the range. + Whiskers templ(R"({ + if gt(ptr, 0x100000000) { revert(0, 0) } + ptr := add(ptr, base_offset) + let array_data_start := add(ptr, 0x20) + if gt(array_data_start, input_end) { revert(0, 0) } + let array_length := mload(ptr) + if or( + gt(array_length, 0x100000000), + gt(add(array_data_start, mul(array_length, )), input_end) + ) { revert(0, 0) } + })"); + templ("item_size", to_string(arrayType.isByteArray() ? 1 : arrayType.baseType()->calldataEncodedSize(true))); + m_context.appendInlineAssembly(templ.render(), {"input_end", "base_offset", "offset", "ptr"}); // stack: v1 v2 ... v(k-1) input_end base_offset current_offset v(k) moveIntoStack(3); m_context << u256(0x20) << Instruction::ADD; @@ -273,30 +264,25 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem loadFromMemoryDynamic(IntegerType(256), !_fromMemory); m_context << Instruction::SWAP1; // stack: input_end base_offset next_pointer data_offset - if (_revertOnOutOfBounds) - m_context.appendInlineAssembly("{ if gt(data_offset, 0x100000000) { revert(0, 0) } }", {"data_offset"}); + m_context.appendInlineAssembly("{ if gt(data_offset, 0x100000000) { revert(0, 0) } }", {"data_offset"}); m_context << Instruction::DUP3 << Instruction::ADD; // stack: input_end base_offset next_pointer array_head_ptr - if (_revertOnOutOfBounds) - m_context.appendInlineAssembly( - "{ if gt(add(array_head_ptr, 0x20), input_end) { revert(0, 0) } }", - {"input_end", "base_offset", "next_ptr", "array_head_ptr"} - ); + m_context.appendInlineAssembly( + "{ if gt(add(array_head_ptr, 0x20), input_end) { revert(0, 0) } }", + {"input_end", "base_offset", "next_ptr", "array_head_ptr"} + ); // retrieve length loadFromMemoryDynamic(IntegerType(256), !_fromMemory, true); // stack: input_end base_offset next_pointer array_length data_pointer m_context << Instruction::SWAP2; // stack: input_end base_offset data_pointer array_length next_pointer - if (_revertOnOutOfBounds) - { - unsigned itemSize = arrayType.isByteArray() ? 1 : arrayType.baseType()->calldataEncodedSize(true); - m_context.appendInlineAssembly(R"({ - if or( - gt(array_length, 0x100000000), - gt(add(data_ptr, mul(array_length, )" + to_string(itemSize) + R"()), input_end) - ) { revert(0, 0) } - })", {"input_end", "base_offset", "data_ptr", "array_length", "next_ptr"}); - } + unsigned itemSize = arrayType.isByteArray() ? 1 : arrayType.baseType()->calldataEncodedSize(true); + m_context.appendInlineAssembly(R"({ + if or( + gt(array_length, 0x100000000), + gt(add(data_ptr, mul(array_length, )" + to_string(itemSize) + R"()), input_end) + ) { revert(0, 0) } + })", {"input_end", "base_offset", "data_ptr", "array_length", "next_ptr"}); } else { diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h index 8e3a8a5d..0ff3ad7c 100644 --- a/libsolidity/codegen/CompilerUtils.h +++ b/libsolidity/codegen/CompilerUtils.h @@ -102,7 +102,7 @@ public: /// area. Also has a hard cap of 0x100000000 for any given length/offset field. /// Stack pre: /// Stack post: ... - void abiDecode(TypePointers const& _typeParameters, bool _fromMemory = false, bool _revertOnOutOfBounds = false); + void abiDecode(TypePointers const& _typeParameters, bool _fromMemory = false); /// Copies values (of types @a _givenTypes) given on the stack to a location in memory given /// at the stack top, encoding them according to the ABI as the given types @a _targetTypes. diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 0470c3ec..c4215c29 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -2065,7 +2065,7 @@ void ExpressionCompiler::appendExternalFunctionCall( mstore(0x40, newMem) })", {"start", "size"}); - utils().abiDecode(returnTypes, true, true); + utils().abiDecode(returnTypes, true); } } -- cgit v1.2.3 From c8ac8618324d8d167c79a926880b2b5ab853f7f3 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 4 Jul 2018 11:23:51 +0200 Subject: Fix allocation of byte arrays. --- libsolidity/codegen/CompilerUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index a5e96335..2f45765a 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -510,7 +510,7 @@ void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type) codecopy(memptr, codesize(), size) memptr := add(memptr, size) })"); - templ("element_size", to_string(_type.baseType()->memoryHeadSize())); + templ("element_size", to_string(_type.isByteArray() ? 1 : _type.baseType()->memoryHeadSize())); m_context.appendInlineAssembly(templ.render(), {"length", "memptr"}); } else -- cgit v1.2.3 From 1f77deada1abc9ca1e635ab13d45707e852a5628 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Thu, 3 May 2018 16:40:33 +0200 Subject: [050] Reserving and popping local vars in their scope --- libsolidity/codegen/CompilerContext.cpp | 15 ++++- libsolidity/codegen/CompilerContext.h | 4 +- libsolidity/codegen/ContractCompiler.cpp | 104 +++++++++++++++++++++---------- libsolidity/codegen/ContractCompiler.h | 28 +++++++-- 4 files changed, 110 insertions(+), 41 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index a35eea73..9c5dc89c 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -130,7 +130,7 @@ void CompilerContext::addVariable(VariableDeclaration const& _declaration, m_localVariables[&_declaration].push_back(unsigned(m_asm->deposit()) - _offsetToCurrent); } -void CompilerContext::removeVariable(VariableDeclaration const& _declaration) +void CompilerContext::removeVariable(Declaration const& _declaration) { solAssert(m_localVariables.count(&_declaration) && !m_localVariables[&_declaration].empty(), ""); m_localVariables[&_declaration].pop_back(); @@ -138,6 +138,19 @@ void CompilerContext::removeVariable(VariableDeclaration const& _declaration) m_localVariables.erase(&_declaration); } +void CompilerContext::removeVariablesAboveStackHeight(unsigned _stackHeight) +{ + vector toRemove; + for (auto _var: m_localVariables) + { + solAssert(!_var.second.empty(), ""); + if (_var.second.back() >= _stackHeight) + toRemove.push_back(_var.first); + } + for (auto _var: toRemove) + removeVariable(*_var); +} + eth::Assembly const& CompilerContext::compiledContract(const ContractDefinition& _contract) const { auto ret = m_compiledContracts.find(&_contract); diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 5776b5d1..f3934615 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -71,7 +71,9 @@ public: void addStateVariable(VariableDeclaration const& _declaration, u256 const& _storageOffset, unsigned _byteOffset); void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0); - void removeVariable(VariableDeclaration const& _declaration); + void removeVariable(Declaration const& _declaration); + /// Removes all local variables currently allocated above _stackHeight. + void removeVariablesAboveStackHeight(unsigned _stackHeight); void setCompiledContracts(std::map const& _contracts) { m_compiledContracts = _contracts; } eth::Assembly const& compiledContract(ContractDefinition const& _contract) const; diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 81aba21e..def4a878 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -427,7 +427,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) m_context.startFunction(_function); // stack upon entry: [return address] [arg0] [arg1] ... [argn] - // reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp] + // reserve additional slots: [retarg0] ... [retargm] unsigned parametersSize = CompilerUtils::sizeOnStack(_function.parameters()); if (!_function.isConstructor()) @@ -441,22 +441,18 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) for (ASTPointer const& variable: _function.returnParameters()) appendStackVariableInitialisation(*variable); - for (VariableDeclaration const* localVariable: _function.localVariables()) - appendStackVariableInitialisation(*localVariable); if (_function.isConstructor()) if (auto c = m_context.nextConstructor(dynamic_cast(*_function.scope()))) appendBaseConstructor(*c); - solAssert(m_returnTags.empty(), ""); m_breakTags.clear(); m_continueTags.clear(); - m_stackCleanupForReturn = 0; m_currentFunction = &_function; m_modifierDepth = -1; + m_scopeStackHeight.clear(); appendModifierOrFunctionCode(); - solAssert(m_returnTags.empty(), ""); // Now we need to re-shuffle the stack. For this we keep a record of the stack layout @@ -467,14 +463,12 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) unsigned const c_argumentsSize = CompilerUtils::sizeOnStack(_function.parameters()); unsigned const c_returnValuesSize = CompilerUtils::sizeOnStack(_function.returnParameters()); - unsigned const c_localVariablesSize = CompilerUtils::sizeOnStack(_function.localVariables()); vector stackLayout; stackLayout.push_back(c_returnValuesSize); // target of return address stackLayout += vector(c_argumentsSize, -1); // discard all arguments for (unsigned i = 0; i < c_returnValuesSize; ++i) stackLayout.push_back(i); - stackLayout += vector(c_localVariablesSize, -1); if (stackLayout.size() > 17) BOOST_THROW_EXCEPTION( @@ -493,18 +487,19 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) m_context << swapInstruction(stackLayout.size() - stackLayout.back() - 1); swap(stackLayout[stackLayout.back()], stackLayout.back()); } - //@todo assert that everything is in place now + for (int i = 0; i < int(stackLayout.size()); ++i) + if (stackLayout[i] != i) + solAssert(false, "Invalid stack layout on cleanup."); for (ASTPointer const& variable: _function.parameters() + _function.returnParameters()) m_context.removeVariable(*variable); - for (VariableDeclaration const* localVariable: _function.localVariables()) - m_context.removeVariable(*localVariable); m_context.adjustStackOffset(-(int)c_returnValuesSize); /// The constructor and the fallback function doesn't to jump out. if (!_function.isConstructor() && !_function.isFallback()) m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction); + return false; } @@ -669,14 +664,16 @@ bool ContractCompiler::visit(WhileStatement const& _whileStatement) eth::AssemblyItem loopStart = m_context.newTag(); eth::AssemblyItem loopEnd = m_context.newTag(); - m_breakTags.push_back(loopEnd); + m_breakTags.push_back({loopEnd, m_context.stackHeight()}); + + visitLoop(&_whileStatement); m_context << loopStart; if (_whileStatement.isDoWhile()) { eth::AssemblyItem condition = m_context.newTag(); - m_continueTags.push_back(condition); + m_continueTags.push_back({condition, m_context.stackHeight()}); _whileStatement.body().accept(*this); @@ -687,7 +684,7 @@ bool ContractCompiler::visit(WhileStatement const& _whileStatement) } else { - m_continueTags.push_back(loopStart); + m_continueTags.push_back({loopStart, m_context.stackHeight()}); compileExpression(_whileStatement.condition()); m_context << Instruction::ISZERO; m_context.appendConditionalJumpTo(loopEnd); @@ -712,12 +709,14 @@ bool ContractCompiler::visit(ForStatement const& _forStatement) eth::AssemblyItem loopStart = m_context.newTag(); eth::AssemblyItem loopEnd = m_context.newTag(); eth::AssemblyItem loopNext = m_context.newTag(); - m_continueTags.push_back(loopNext); - m_breakTags.push_back(loopEnd); + + visitLoop(&_forStatement); if (_forStatement.initializationExpression()) _forStatement.initializationExpression()->accept(*this); + m_breakTags.push_back({loopEnd, m_context.stackHeight()}); + m_continueTags.push_back({loopNext, m_context.stackHeight()}); m_context << loopStart; // if there is no terminating condition in for, default is to always be true @@ -737,11 +736,16 @@ bool ContractCompiler::visit(ForStatement const& _forStatement) _forStatement.loopExpression()->accept(*this); m_context.appendJumpTo(loopStart); + m_context << loopEnd; m_continueTags.pop_back(); m_breakTags.pop_back(); + // For the case where no break/return is executed: + // loop initialization variables have to be freed + popScopedVariables(&_forStatement); + checker.check(); return false; } @@ -750,7 +754,7 @@ bool ContractCompiler::visit(Continue const& _continueStatement) { CompilerContext::LocationSetter locationSetter(m_context, _continueStatement); solAssert(!m_continueTags.empty(), ""); - m_context.appendJumpTo(m_continueTags.back()); + popAndJump(m_context.stackHeight() - m_continueTags.back().second, m_continueTags.back().first); return false; } @@ -758,7 +762,7 @@ bool ContractCompiler::visit(Break const& _breakStatement) { CompilerContext::LocationSetter locationSetter(m_context, _breakStatement); solAssert(!m_breakTags.empty(), ""); - m_context.appendJumpTo(m_breakTags.back()); + popAndJump(m_context.stackHeight() - m_breakTags.back().second, m_breakTags.back().first); return false; } @@ -784,10 +788,8 @@ bool ContractCompiler::visit(Return const& _return) for (auto const& retVariable: boost::adaptors::reverse(returnParameters)) CompilerUtils(m_context).moveToStackVariable(*retVariable); } - for (unsigned i = 0; i < m_stackCleanupForReturn; ++i) - m_context << Instruction::POP; - m_context.appendJumpTo(m_returnTags.back()); - m_context.adjustStackOffset(m_stackCleanupForReturn); + + popAndJump(m_context.stackHeight() - m_returnTags.back().second, m_returnTags.back().first); return false; } @@ -810,8 +812,15 @@ bool ContractCompiler::visit(EmitStatement const& _emit) bool ContractCompiler::visit(VariableDeclarationStatement const& _variableDeclarationStatement) { - StackHeightChecker checker(m_context); CompilerContext::LocationSetter locationSetter(m_context, _variableDeclarationStatement); + + // Local variable slots are reserved when their declaration is visited, + // and freed in the end of their scope. + for (auto _decl: _variableDeclarationStatement.declarations()) + if (_decl) + appendStackVariableInitialisation(*_decl); + + StackHeightChecker checker(m_context); if (Expression const* expression = _variableDeclarationStatement.initialValue()) { CompilerUtils utils(m_context); @@ -861,6 +870,18 @@ bool ContractCompiler::visit(PlaceholderStatement const& _placeholderStatement) return true; } +bool ContractCompiler::visit(Block const& _block) +{ + m_scopeStackHeight[m_modifierDepth][&_block] = m_context.stackHeight(); + return true; +} + +void ContractCompiler::endVisit(Block const& _block) +{ + // Frees local variables declared in the scope of this block. + popScopedVariables(&_block); +} + void ContractCompiler::appendMissingFunctions() { while (Declaration const* function = m_context.nextFunctionToCompile()) @@ -916,27 +937,19 @@ void ContractCompiler::appendModifierOrFunctionCode() modifier.parameters()[i]->annotation().type ); } - for (VariableDeclaration const* localVariable: modifier.localVariables()) - { - addedVariables.push_back(localVariable); - appendStackVariableInitialisation(*localVariable); - } - stackSurplus = - CompilerUtils::sizeOnStack(modifier.parameters()) + - CompilerUtils::sizeOnStack(modifier.localVariables()); + stackSurplus = CompilerUtils::sizeOnStack(modifier.parameters()); codeBlock = &modifier.body(); } } if (codeBlock) { - m_returnTags.push_back(m_context.newTag()); - + m_returnTags.push_back({m_context.newTag(), m_context.stackHeight()}); codeBlock->accept(*this); solAssert(!m_returnTags.empty(), ""); - m_context << m_returnTags.back(); + m_context << m_returnTags.back().first; m_returnTags.pop_back(); CompilerUtils(m_context).popStackSlots(stackSurplus); @@ -983,3 +996,26 @@ eth::AssemblyPointer ContractCompiler::cloneRuntime() const a << u256(0x20) << u256(0) << Instruction::RETURN; return make_shared(a); } + +void ContractCompiler::popScopedVariables(ASTNode const* _node) +{ + unsigned blockHeight = m_scopeStackHeight[m_modifierDepth][_node]; + unsigned stackDiff = m_context.stackHeight() - blockHeight; + CompilerUtils(m_context).popStackSlots(stackDiff); + m_context.removeVariablesAboveStackHeight(blockHeight); + m_scopeStackHeight[m_modifierDepth].erase(_node); + if (m_scopeStackHeight[m_modifierDepth].size() == 0) + m_scopeStackHeight.erase(m_modifierDepth); +} + +void ContractCompiler::visitLoop(BreakableStatement const* _loop) +{ + m_scopeStackHeight[m_modifierDepth][_loop] = m_context.stackHeight(); +} + +void ContractCompiler::popAndJump(unsigned _amount, eth::AssemblyItem const& _jumpTo) +{ + CompilerUtils(m_context).popStackSlots(_amount); + m_context.appendJumpTo(_jumpTo); + m_context.adjustStackOffset(_amount); +} diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h index 02a3452f..72f46495 100644 --- a/libsolidity/codegen/ContractCompiler.h +++ b/libsolidity/codegen/ContractCompiler.h @@ -109,6 +109,8 @@ private: virtual bool visit(VariableDeclarationStatement const& _variableDeclarationStatement) override; virtual bool visit(ExpressionStatement const& _expressionStatement) override; virtual bool visit(PlaceholderStatement const&) override; + virtual bool visit(Block const& _block) override; + virtual void endVisit(Block const& _block) override; /// Repeatedly visits all function which are referenced but which are not compiled yet. void appendMissingFunctions(); @@ -123,19 +125,35 @@ private: /// @returns the runtime assembly for clone contracts. eth::AssemblyPointer cloneRuntime() const; + /// Frees the variables of a certain scope (to be used when leaving). + void popScopedVariables(ASTNode const* _node); + + /// Pops _amount slots from the stack and jumps to _jumpTo. + /// Also readjusts the stack offset to the original value. + void popAndJump(unsigned _amount, eth::AssemblyItem const& _jumpTo); + + /// Sets the stack height for the visited loop. + void visitLoop(BreakableStatement const* _loop); + bool const m_optimise; /// Pointer to the runtime compiler in case this is a creation compiler. ContractCompiler* m_runtimeCompiler = nullptr; CompilerContext& m_context; - std::vector m_breakTags; ///< tag to jump to for a "break" statement - std::vector m_continueTags; ///< tag to jump to for a "continue" statement - /// Tag to jump to for a "return" statement, needs to be stacked because of modifiers. - std::vector m_returnTags; + /// Tag to jump to for a "break" statement and the stack height after freeing the local loop variables. + std::vector> m_breakTags; + /// Tag to jump to for a "continue" statement and the stack height after freeing the local loop variables. + std::vector> m_continueTags; + /// Tag to jump to for a "return" statement and the stack height after freeing the local function or modifier variables. + /// Needs to be stacked because of modifiers. + std::vector> m_returnTags; unsigned m_modifierDepth = 0; FunctionDefinition const* m_currentFunction = nullptr; - unsigned m_stackCleanupForReturn = 0; ///< this number of stack elements need to be removed before jump to m_returnTag + // arguments for base constructors, filled in derived-to-base order std::map const* m_baseArguments; + + /// Stores the variables that were declared inside a specific scope, for each modifier depth. + std::map> m_scopeStackHeight; }; } -- cgit v1.2.3 From 9d895e002d0e5e1e3435d03ac82277caa397bbec Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 4 Jul 2018 14:14:41 +0200 Subject: Added tests and review suggestions --- libsolidity/codegen/CompilerUtils.cpp | 8 ++++++++ libsolidity/codegen/CompilerUtils.h | 4 ++++ libsolidity/codegen/ContractCompiler.cpp | 26 +++++++++----------------- libsolidity/codegen/ContractCompiler.h | 6 +----- 4 files changed, 22 insertions(+), 22 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 2f45765a..92c45227 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1170,6 +1170,14 @@ void CompilerUtils::popStackSlots(size_t _amount) m_context << Instruction::POP; } +void CompilerUtils::popAndJump(unsigned _toHeight, eth::AssemblyItem const& _jumpTo) +{ + unsigned amount = m_context.stackHeight() - _toHeight; + popStackSlots(amount); + m_context.appendJumpTo(_jumpTo); + m_context.adjustStackOffset(amount); +} + unsigned CompilerUtils::sizeOnStack(vector> const& _variableTypes) { unsigned size = 0; diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h index 0ff3ad7c..26df4765 100644 --- a/libsolidity/codegen/CompilerUtils.h +++ b/libsolidity/codegen/CompilerUtils.h @@ -241,6 +241,10 @@ public: void popStackElement(Type const& _type); /// Removes element from the top of the stack _amount times. void popStackSlots(size_t _amount); + /// Pops slots from the stack such that its height is _toHeight. + /// Adds jump to _jumpTo. + /// Readjusts the stack offset to the original value. + void popAndJump(unsigned _toHeight, eth::AssemblyItem const& _jumpTo); template static unsigned sizeOnStack(std::vector const& _variables); diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index def4a878..474d2b68 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -446,6 +446,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) if (auto c = m_context.nextConstructor(dynamic_cast(*_function.scope()))) appendBaseConstructor(*c); + solAssert(m_returnTags.empty(), ""); m_breakTags.clear(); m_continueTags.clear(); m_currentFunction = &_function; @@ -666,8 +667,6 @@ bool ContractCompiler::visit(WhileStatement const& _whileStatement) eth::AssemblyItem loopEnd = m_context.newTag(); m_breakTags.push_back({loopEnd, m_context.stackHeight()}); - visitLoop(&_whileStatement); - m_context << loopStart; if (_whileStatement.isDoWhile()) @@ -710,7 +709,7 @@ bool ContractCompiler::visit(ForStatement const& _forStatement) eth::AssemblyItem loopEnd = m_context.newTag(); eth::AssemblyItem loopNext = m_context.newTag(); - visitLoop(&_forStatement); + storeStackHeight(&_forStatement); if (_forStatement.initializationExpression()) _forStatement.initializationExpression()->accept(*this); @@ -754,7 +753,7 @@ bool ContractCompiler::visit(Continue const& _continueStatement) { CompilerContext::LocationSetter locationSetter(m_context, _continueStatement); solAssert(!m_continueTags.empty(), ""); - popAndJump(m_context.stackHeight() - m_continueTags.back().second, m_continueTags.back().first); + CompilerUtils(m_context).popAndJump(m_continueTags.back().second, m_continueTags.back().first); return false; } @@ -762,7 +761,7 @@ bool ContractCompiler::visit(Break const& _breakStatement) { CompilerContext::LocationSetter locationSetter(m_context, _breakStatement); solAssert(!m_breakTags.empty(), ""); - popAndJump(m_context.stackHeight() - m_breakTags.back().second, m_breakTags.back().first); + CompilerUtils(m_context).popAndJump(m_breakTags.back().second, m_breakTags.back().first); return false; } @@ -789,7 +788,7 @@ bool ContractCompiler::visit(Return const& _return) CompilerUtils(m_context).moveToStackVariable(*retVariable); } - popAndJump(m_context.stackHeight() - m_returnTags.back().second, m_returnTags.back().first); + CompilerUtils(m_context).popAndJump(m_returnTags.back().second, m_returnTags.back().first); return false; } @@ -872,7 +871,7 @@ bool ContractCompiler::visit(PlaceholderStatement const& _placeholderStatement) bool ContractCompiler::visit(Block const& _block) { - m_scopeStackHeight[m_modifierDepth][&_block] = m_context.stackHeight(); + storeStackHeight(&_block); return true; } @@ -999,7 +998,7 @@ eth::AssemblyPointer ContractCompiler::cloneRuntime() const void ContractCompiler::popScopedVariables(ASTNode const* _node) { - unsigned blockHeight = m_scopeStackHeight[m_modifierDepth][_node]; + unsigned blockHeight = m_scopeStackHeight.at(m_modifierDepth).at(_node); unsigned stackDiff = m_context.stackHeight() - blockHeight; CompilerUtils(m_context).popStackSlots(stackDiff); m_context.removeVariablesAboveStackHeight(blockHeight); @@ -1008,14 +1007,7 @@ void ContractCompiler::popScopedVariables(ASTNode const* _node) m_scopeStackHeight.erase(m_modifierDepth); } -void ContractCompiler::visitLoop(BreakableStatement const* _loop) -{ - m_scopeStackHeight[m_modifierDepth][_loop] = m_context.stackHeight(); -} - -void ContractCompiler::popAndJump(unsigned _amount, eth::AssemblyItem const& _jumpTo) +void ContractCompiler::storeStackHeight(ASTNode const* _node) { - CompilerUtils(m_context).popStackSlots(_amount); - m_context.appendJumpTo(_jumpTo); - m_context.adjustStackOffset(_amount); + m_scopeStackHeight[m_modifierDepth][_node] = m_context.stackHeight(); } diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h index 72f46495..8516ec2c 100644 --- a/libsolidity/codegen/ContractCompiler.h +++ b/libsolidity/codegen/ContractCompiler.h @@ -128,12 +128,8 @@ private: /// Frees the variables of a certain scope (to be used when leaving). void popScopedVariables(ASTNode const* _node); - /// Pops _amount slots from the stack and jumps to _jumpTo. - /// Also readjusts the stack offset to the original value. - void popAndJump(unsigned _amount, eth::AssemblyItem const& _jumpTo); - /// Sets the stack height for the visited loop. - void visitLoop(BreakableStatement const* _loop); + void storeStackHeight(ASTNode const* _node); bool const m_optimise; /// Pointer to the runtime compiler in case this is a creation compiler. -- cgit v1.2.3 From b750ca9741aba47cc8ba650a04dd620725ed4610 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Fri, 6 Jul 2018 09:56:27 +0200 Subject: Add more tests and assertions --- libsolidity/codegen/CompilerContext.cpp | 2 ++ libsolidity/codegen/CompilerUtils.cpp | 1 + libsolidity/codegen/ContractCompiler.cpp | 1 + 3 files changed, 4 insertions(+) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 9c5dc89c..51f76399 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -127,6 +127,8 @@ void CompilerContext::addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent) { solAssert(m_asm->deposit() >= 0 && unsigned(m_asm->deposit()) >= _offsetToCurrent, ""); + unsigned sizeOnStack = _declaration.annotation().type->sizeOnStack(); + solAssert(sizeOnStack == 1 || sizeOnStack == 2, ""); m_localVariables[&_declaration].push_back(unsigned(m_asm->deposit()) - _offsetToCurrent); } diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 92c45227..5adce4a0 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1172,6 +1172,7 @@ void CompilerUtils::popStackSlots(size_t _amount) void CompilerUtils::popAndJump(unsigned _toHeight, eth::AssemblyItem const& _jumpTo) { + solAssert(m_context.stackHeight() >= _toHeight, ""); unsigned amount = m_context.stackHeight() - _toHeight; popStackSlots(amount); m_context.appendJumpTo(_jumpTo); diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 474d2b68..207e0af7 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -999,6 +999,7 @@ eth::AssemblyPointer ContractCompiler::cloneRuntime() const void ContractCompiler::popScopedVariables(ASTNode const* _node) { unsigned blockHeight = m_scopeStackHeight.at(m_modifierDepth).at(_node); + solAssert(m_context.stackHeight() >= blockHeight, ""); unsigned stackDiff = m_context.stackHeight() - blockHeight; CompilerUtils(m_context).popStackSlots(stackDiff); m_context.removeVariablesAboveStackHeight(blockHeight); -- cgit v1.2.3 From 0c5e0e0d59dc55fcfe5b95a8c649a7a769ad3400 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Tue, 10 Jul 2018 18:39:26 +0200 Subject: Added assertion and tests suggestions --- libsolidity/codegen/CompilerContext.cpp | 8 ++++++++ libsolidity/codegen/CompilerContext.h | 2 ++ libsolidity/codegen/ContractCompiler.cpp | 10 +++++++--- 3 files changed, 17 insertions(+), 3 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 51f76399..3b1b4ec0 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -128,6 +128,8 @@ void CompilerContext::addVariable(VariableDeclaration const& _declaration, { solAssert(m_asm->deposit() >= 0 && unsigned(m_asm->deposit()) >= _offsetToCurrent, ""); unsigned sizeOnStack = _declaration.annotation().type->sizeOnStack(); + // Variables should not have stack size other than [1, 2], + // but that might change when new types are introduced. solAssert(sizeOnStack == 1 || sizeOnStack == 2, ""); m_localVariables[&_declaration].push_back(unsigned(m_asm->deposit()) - _offsetToCurrent); } @@ -146,6 +148,7 @@ void CompilerContext::removeVariablesAboveStackHeight(unsigned _stackHeight) for (auto _var: m_localVariables) { solAssert(!_var.second.empty(), ""); + solAssert(_var.second.back() <= stackHeight(), ""); if (_var.second.back() >= _stackHeight) toRemove.push_back(_var.first); } @@ -153,6 +156,11 @@ void CompilerContext::removeVariablesAboveStackHeight(unsigned _stackHeight) removeVariable(*_var); } +unsigned CompilerContext::numberOfLocalVariables() const +{ + return m_localVariables.size(); +} + eth::Assembly const& CompilerContext::compiledContract(const ContractDefinition& _contract) const { auto ret = m_compiledContracts.find(&_contract); diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index f3934615..3f357821 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -74,6 +74,8 @@ public: void removeVariable(Declaration const& _declaration); /// Removes all local variables currently allocated above _stackHeight. void removeVariablesAboveStackHeight(unsigned _stackHeight); + /// Returns the number of currently allocated local variables. + unsigned numberOfLocalVariables() const; void setCompiledContracts(std::map const& _contracts) { m_compiledContracts = _contracts; } eth::Assembly const& compiledContract(ContractDefinition const& _contract) const; diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 207e0af7..93f698bc 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -498,8 +498,12 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) m_context.adjustStackOffset(-(int)c_returnValuesSize); /// The constructor and the fallback function doesn't to jump out. - if (!_function.isConstructor() && !_function.isFallback()) - m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction); + if (!_function.isConstructor()) + { + solAssert(m_context.numberOfLocalVariables() == 0, ""); + if (!_function.isFallback()) + m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction); + } return false; } @@ -999,10 +1003,10 @@ eth::AssemblyPointer ContractCompiler::cloneRuntime() const void ContractCompiler::popScopedVariables(ASTNode const* _node) { unsigned blockHeight = m_scopeStackHeight.at(m_modifierDepth).at(_node); + m_context.removeVariablesAboveStackHeight(blockHeight); solAssert(m_context.stackHeight() >= blockHeight, ""); unsigned stackDiff = m_context.stackHeight() - blockHeight; CompilerUtils(m_context).popStackSlots(stackDiff); - m_context.removeVariablesAboveStackHeight(blockHeight); m_scopeStackHeight[m_modifierDepth].erase(_node); if (m_scopeStackHeight[m_modifierDepth].size() == 0) m_scopeStackHeight.erase(m_modifierDepth); -- cgit v1.2.3 From 383b88793c3c72a7d8d216cbd9576b49270191a6 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 10 Jul 2018 21:23:00 +0200 Subject: Throw unimplemented exception for complex calldata arrays. --- libsolidity/codegen/ABIFunctions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 4818e111..b3f1bc7e 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -1188,7 +1188,8 @@ string ABIFunctions::abiDecodingFunctionCalldataArray(ArrayType const& _type) solAssert(_type.dataStoredIn(DataLocation::CallData), ""); if (!_type.isDynamicallySized()) solAssert(_type.length() < u256("0xffffffffffffffff"), ""); - solAssert(!_type.baseType()->isDynamicallyEncoded(), ""); + if (_type.baseType()->isDynamicallyEncoded()) + solUnimplemented("Calldata arrays with non-value base types are not yet supported by Solidity."); solAssert(_type.baseType()->calldataEncodedSize() < u256("0xffffffffffffffff"), ""); string functionName = -- cgit v1.2.3 From 140dbfdbd8f4319d1d02339feea0a8636a3738e5 Mon Sep 17 00:00:00 2001 From: Cryptomental Date: Tue, 10 Jul 2018 09:18:59 +0200 Subject: Code, Changelog, ReleaseChecklist: Fix typos. Refs: #4442 --- libsolidity/codegen/ABIFunctions.h | 2 +- libsolidity/codegen/CompilerUtils.cpp | 4 ++-- libsolidity/codegen/ExpressionCompiler.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ABIFunctions.h b/libsolidity/codegen/ABIFunctions.h index 6bfb3f15..3caaa1d9 100644 --- a/libsolidity/codegen/ABIFunctions.h +++ b/libsolidity/codegen/ABIFunctions.h @@ -203,7 +203,7 @@ private: std::string arrayLengthFunction(ArrayType const& _type); /// @returns the name of a function that computes the number of bytes required /// to store an array in memory given its length (internally encoded, not ABI encoded). - /// The function reverts for too large lengthes. + /// The function reverts for too large lengths. std::string arrayAllocationSizeFunction(ArrayType const& _type); /// @returns the name of a function that converts a storage slot number /// or a memory pointer to the slot number / memory pointer for the data position of an array diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 2f45765a..2e335ca5 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -363,8 +363,8 @@ void CompilerUtils::encodeToMemory( // Stack during operation: // ... ... - // The values dyn_head_i are added during the first loop and they point to the head part - // of the ith dynamic parameter, which is filled once the dynamic parts are processed. + // The values dyn_head_n are added during the first loop and they point to the head part + // of the nth dynamic parameter, which is filled once the dynamic parts are processed. // store memory start pointer m_context << Instruction::DUP1; diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 2e548e32..483faae4 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1751,7 +1751,7 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator, Type co { if (c_valueSigned) // In the following assembly snippet, xor_mask will be zero, if value_to_shift is positive. - // Therefor xor'ing with xor_mask is the identity and the computation reduces to + // Therefore xor'ing with xor_mask is the identity and the computation reduces to // div(value_to_shift, exp(2, shift_amount)), which is correct, since for positive values // arithmetic right shift is dividing by a power of two (which, as a bitwise operation, results // in discarding bits on the right and filling with zeros from the left). @@ -1879,7 +1879,7 @@ void ExpressionCompiler::appendExternalFunctionCall( { m_context << u256(0); utils().fetchFreeMemoryPointer(); - // This touches too much, but that way we save some rounding arithmetics + // This touches too much, but that way we save some rounding arithmetic m_context << u256(retSize) << Instruction::ADD << Instruction::MSTORE; } } -- cgit v1.2.3 From 38026d311443f5f0f8fb23a928839136b56c97bd Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 4 Jul 2018 16:29:52 +0200 Subject: Use STATICCALL for view and pure --- libsolidity/codegen/ExpressionCompiler.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 483faae4..dfa3e58f 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1810,15 +1810,11 @@ void ExpressionCompiler::appendExternalFunctionCall( if (_functionType.bound()) utils().moveToStackTop(gasValueSize, _functionType.selfType()->sizeOnStack()); - bool const v050 = m_context.experimentalFeatureActive(ExperimentalFeature::V050); auto funKind = _functionType.kind(); bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall; bool isCallCode = funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::CallCode; bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall; - bool useStaticCall = - _functionType.stateMutability() <= StateMutability::View && - v050 && - m_context.evmVersion().hasStaticCall(); + bool useStaticCall = _functionType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall(); bool haveReturndatacopy = m_context.evmVersion().supportsReturndata(); unsigned retSize = 0; -- cgit v1.2.3 From 7355298c2f4a1283036f7cb6be349a583a4f4111 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 11 Jul 2018 14:53:34 +0200 Subject: Fix handling of fixed point types in arithmetics. --- libsolidity/codegen/ExpressionCompiler.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 483faae4..24b8cbfb 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -349,6 +349,10 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) case Token::Inc: // ++ (pre- or postfix) case Token::Dec: // -- (pre- or postfix) solAssert(!!m_currentLValue, "LValue not retrieved."); + solUnimplementedAssert( + _unaryOperation.annotation().type->category() != Type::Category::FixedPoint, + "Not yet implemented - FixedPointType." + ); m_currentLValue->retrieveValue(_unaryOperation.location()); if (!_unaryOperation.isPrefixOperation()) { @@ -1647,12 +1651,12 @@ void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type) { - IntegerType const& type = dynamic_cast(_type); - bool const c_isSigned = type.isSigned(); - if (_type.category() == Type::Category::FixedPoint) solUnimplemented("Not yet implemented - FixedPointType."); + IntegerType const& type = dynamic_cast(_type); + bool const c_isSigned = type.isSigned(); + switch (_operator) { case Token::Add: -- cgit v1.2.3 From fc370591f02d2bcfe52b62776a871b33e933bd34 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 4 Jul 2018 18:34:24 +0200 Subject: Disallow multi variable declarations with mismatching number of values. --- libsolidity/codegen/ContractCompiler.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 93f698bc..bbb3db3d 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -833,20 +833,19 @@ bool ContractCompiler::visit(VariableDeclarationStatement const& _variableDeclar valueTypes = tupleType->components(); else valueTypes = TypePointers{expression->annotation().type}; - auto const& assignments = _variableDeclarationStatement.annotation().assignments; - solAssert(assignments.size() == valueTypes.size(), ""); - for (size_t i = 0; i < assignments.size(); ++i) + auto const& declarations = _variableDeclarationStatement.declarations(); + solAssert(declarations.size() == valueTypes.size(), ""); + for (size_t i = 0; i < declarations.size(); ++i) { - size_t j = assignments.size() - i - 1; + size_t j = declarations.size() - i - 1; solAssert(!!valueTypes[j], ""); - VariableDeclaration const* varDecl = assignments[j]; - if (!varDecl) - utils.popStackElement(*valueTypes[j]); - else + if (VariableDeclaration const* varDecl = declarations[j].get()) { utils.convertType(*valueTypes[j], *varDecl->annotation().type); utils.moveToStackVariable(*varDecl); } + else + utils.popStackElement(*valueTypes[j]); } } checker.check(); -- cgit v1.2.3 From faa9c221d41c45e12411c654919f318f6e7fc98f Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 18 Jul 2018 19:51:24 +0200 Subject: Changes in ExpressionCompiler --- libsolidity/codegen/ExpressionCompiler.cpp | 89 +++++++++++++----------------- 1 file changed, 39 insertions(+), 50 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 4cec69c8..54518906 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1214,63 +1214,52 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) switch (_memberAccess.expression().annotation().type->category()) { case Type::Category::Contract: - case Type::Category::Integer: { - bool alsoSearchInteger = false; - if (_memberAccess.expression().annotation().type->category() == Type::Category::Contract) + ContractType const& type = dynamic_cast(*_memberAccess.expression().annotation().type); + if (type.isSuper()) { - ContractType const& type = dynamic_cast(*_memberAccess.expression().annotation().type); - if (type.isSuper()) - { - solAssert(!!_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved."); - utils().pushCombinedFunctionEntryLabel(m_context.superFunction( - dynamic_cast(*_memberAccess.annotation().referencedDeclaration), - type.contractDefinition() - )); - } + solAssert(!!_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved."); + utils().pushCombinedFunctionEntryLabel(m_context.superFunction( + dynamic_cast(*_memberAccess.annotation().referencedDeclaration), + type.contractDefinition() + )); + } + // ordinary contract type + else if (Declaration const* declaration = _memberAccess.annotation().referencedDeclaration) + { + u256 identifier; + if (auto const* variable = dynamic_cast(declaration)) + identifier = FunctionType(*variable).externalIdentifier(); + else if (auto const* function = dynamic_cast(declaration)) + identifier = FunctionType(*function).externalIdentifier(); else - { - // ordinary contract type - if (Declaration const* declaration = _memberAccess.annotation().referencedDeclaration) - { - u256 identifier; - if (auto const* variable = dynamic_cast(declaration)) - identifier = FunctionType(*variable).externalIdentifier(); - else if (auto const* function = dynamic_cast(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; - } + solAssert(false, "Contract member is neither variable nor function."); + utils().convertType(type, IntegerType(160, IntegerType::Modifier::Address), true); + m_context << identifier; } else - alsoSearchInteger = true; - - if (alsoSearchInteger) + solAssert(false, "Invalid member access in contract"); + break; + } + case Type::Category::Integer: + { + if (member == "balance") { - if (member == "balance") - { - utils().convertType( - *_memberAccess.expression().annotation().type, - IntegerType(160, IntegerType::Modifier::Address), - true - ); - m_context << Instruction::BALANCE; - } - else if ((set{"send", "transfer", "call", "callcode", "delegatecall"}).count(member)) - utils().convertType( - *_memberAccess.expression().annotation().type, - IntegerType(160, IntegerType::Modifier::Address), - true - ); - else - solAssert(false, "Invalid member access to integer"); + utils().convertType( + *_memberAccess.expression().annotation().type, + IntegerType(160, IntegerType::Modifier::Address), + true + ); + m_context << Instruction::BALANCE; } + else if ((set{"send", "transfer", "call", "callcode", "delegatecall"}).count(member)) + utils().convertType( + *_memberAccess.expression().annotation().type, + IntegerType(160, IntegerType::Modifier::Address), + true + ); + else + solAssert(false, "Invalid member access to integer"); break; } case Type::Category::Function: -- cgit v1.2.3 From a2f03ea9e56b1ac5c2822e05bec4cad9bdf36979 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Mon, 23 Jul 2018 23:31:02 +0200 Subject: Fix abiDecode comment --- libsolidity/codegen/CompilerUtils.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h index 26df4765..ad3d7327 100644 --- a/libsolidity/codegen/CompilerUtils.h +++ b/libsolidity/codegen/CompilerUtils.h @@ -97,9 +97,9 @@ public: /// Creates code that unpacks the arguments according to their types specified by a vector of TypePointers. /// From memory if @a _fromMemory is true, otherwise from call data. - /// Calls revert if @a _revertOnOutOfBounds is true and the supplied size is shorter - /// than the static data requirements or if dynamic data pointers reach outside of the - /// area. Also has a hard cap of 0x100000000 for any given length/offset field. + /// Calls revert if the supplied size is shorter than the static data requirements + /// or if dynamic data pointers reach outside of the area. + /// Also has a hard cap of 0x100000000 for any given length/offset field. /// Stack pre: /// Stack post: ... void abiDecode(TypePointers const& _typeParameters, bool _fromMemory = false); -- cgit v1.2.3 From f74cff622dd0eb8d4e64c014731e00fb9ea1d078 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 19 Jun 2018 19:30:38 +0200 Subject: Properly explain all the analsys steps in CompilerStack --- libsolidity/codegen/ContractCompiler.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index bbb3db3d..2f15a33d 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -71,7 +71,11 @@ void ContractCompiler::compileContract( appendDelegatecallCheck(); initializeContext(_contract, _contracts); + // This generates the dispatch function for externally visible functions + // and adds the function to the compilation queue. Additionally internal functions, + // which are referenced directly or indirectly will be added. appendFunctionSelector(_contract); + // This processes the above populated queue until it is empty. appendMissingFunctions(); } -- cgit v1.2.3 From 7a8a243eef5551189c51c753463683097cf92f94 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 18 Jul 2018 15:46:23 +0200 Subject: Isolate determining the encoding type into its own function. --- libsolidity/codegen/ABIFunctions.cpp | 18 ++++-------------- libsolidity/codegen/CompilerUtils.cpp | 17 +++++------------ 2 files changed, 9 insertions(+), 26 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index b3f1bc7e..1ce77d67 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -471,13 +471,8 @@ string ABIFunctions::abiEncodingFunction( bool _fromStack ) { - solUnimplementedAssert( - _to.mobileType() && - _to.mobileType()->interfaceType(_encodeAsLibraryTypes) && - _to.mobileType()->interfaceType(_encodeAsLibraryTypes)->encodingType(), - "Encoding type \"" + _to.toString() + "\" not yet implemented." - ); - TypePointer toInterface = _to.mobileType()->interfaceType(_encodeAsLibraryTypes)->encodingType(); + TypePointer toInterface = _to.fullEncodingType(_encodeAsLibraryTypes, true, false); + solUnimplementedAssert(toInterface, "Encoding type \"" + _to.toString() + "\" not yet implemented."); Type const& to = *toInterface; if (_from.category() == Type::Category::StringLiteral) @@ -886,13 +881,8 @@ string ABIFunctions::abiEncodingFunctionStruct( 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(); + TypePointer memberTypeTo = member.type->fullEncodingType(_encodeAsLibraryTypes, true, false); + solUnimplementedAssert(memberTypeTo, "Encoding type \"" + member.type->toString() + "\" not yet implemented."); auto memberTypeFrom = _from.memberType(member.name); solAssert(memberTypeFrom, ""); bool dynamicMember = memberTypeTo->isDynamicallyEncoded(); diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 2d81a106..bd3ec8f5 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -333,26 +333,19 @@ void CompilerUtils::encodeToMemory( ) { // stack: ... + bool const encoderV2 = m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2); TypePointers targetTypes = _targetTypes.empty() ? _givenTypes : _targetTypes; solAssert(targetTypes.size() == _givenTypes.size(), ""); for (TypePointer& t: targetTypes) { - solUnimplementedAssert( - t->mobileType() && - t->mobileType()->interfaceType(_encodeAsLibraryTypes) && - t->mobileType()->interfaceType(_encodeAsLibraryTypes)->encodingType(), - "Encoding type \"" + t->toString() + "\" not yet implemented." - ); - t = t->mobileType()->interfaceType(_encodeAsLibraryTypes)->encodingType(); + TypePointer tEncoding = t->fullEncodingType(_encodeAsLibraryTypes, encoderV2, !_padToWordBoundaries); + solUnimplementedAssert(tEncoding, "Encoding type \"" + t->toString() + "\" not yet implemented."); + t = std::move(tEncoding); } if (_givenTypes.empty()) return; - else if ( - _padToWordBoundaries && - !_copyDynamicDataInPlace && - m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2) - ) + else if (_padToWordBoundaries && !_copyDynamicDataInPlace && encoderV2) { // Use the new Yul-based encoding function auto stackHeightBefore = m_context.stackHeight(); -- cgit v1.2.3 From 3fcd62921ebcc8015d1d6829b818dea40e64e845 Mon Sep 17 00:00:00 2001 From: Jesse Busman Date: Thu, 28 Jun 2018 17:43:09 +0200 Subject: Renamed FunctionType::hasEqualArgumentTypes to FunctionType::hasEqualParameterTypes --- libsolidity/codegen/CompilerContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 3b1b4ec0..71b615b8 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -411,7 +411,7 @@ FunctionDefinition const& CompilerContext::resolveVirtualFunction( if ( function->name() == name && !function->isConstructor() && - FunctionType(*function).hasEqualArgumentTypes(functionType) + FunctionType(*function).hasEqualParameterTypes(functionType) ) return *function; solAssert(false, "Super function " + name + " not found."); -- cgit v1.2.3 From eccc603291737ad20c74b45989201d71268a6727 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 2 Aug 2018 15:22:33 +0100 Subject: FixedBytes(0) is invalid, do not check for it in ABIEncoderV2 --- libsolidity/codegen/ABIFunctions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 1ce77d67..dda77958 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -228,7 +228,8 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure) if (type.numBytes() == 32) templ("body", "cleaned := value"); else if (type.numBytes() == 0) - templ("body", "cleaned := 0"); + // This is disallowed in the type system. + solAssert(false, ""); else { size_t numBits = type.numBytes() * 8; -- cgit v1.2.3 From 71e26f6adb7d6b28400a6607570bb1e17da24feb Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 6 Aug 2018 18:32:18 +0200 Subject: Remove clone feature. --- libsolidity/codegen/Compiler.cpp | 13 ---------- libsolidity/codegen/Compiler.h | 6 ----- libsolidity/codegen/ContractCompiler.cpp | 44 -------------------------------- libsolidity/codegen/ContractCompiler.h | 10 -------- 4 files changed, 73 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp index d3afada5..55f1d252 100644 --- a/libsolidity/codegen/Compiler.cpp +++ b/libsolidity/codegen/Compiler.cpp @@ -46,19 +46,6 @@ void Compiler::compileContract( m_context.optimise(m_optimize, m_optimizeRuns); } -void Compiler::compileClone( - ContractDefinition const& _contract, - map const& _contracts -) -{ - solAssert(!_contract.isLibrary(), ""); - ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimize); - ContractCompiler cloneCompiler(&runtimeCompiler, m_context, m_optimize); - m_runtimeSub = cloneCompiler.compileClone(_contract, _contracts); - - m_context.optimise(m_optimize, m_optimizeRuns); -} - eth::AssemblyItem Compiler::functionEntryLabel(FunctionDefinition const& _function) const { return m_runtimeContext.functionEntryLabelIfExists(_function); diff --git a/libsolidity/codegen/Compiler.h b/libsolidity/codegen/Compiler.h index f6865d75..4028ae63 100644 --- a/libsolidity/codegen/Compiler.h +++ b/libsolidity/codegen/Compiler.h @@ -50,12 +50,6 @@ public: std::map const& _contracts, bytes const& _metadata ); - /// Compiles a contract that uses DELEGATECALL to call into a pre-deployed version of the given - /// contract at runtime, but contains the full creation-time code. - void compileClone( - ContractDefinition const& _contract, - std::map const& _contracts - ); /// @returns Entire assembly. eth::Assembly const& assembly() const { return m_context.assembly(); } /// @returns The entire assembled object (with constructor). diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 2f15a33d..f9493d6d 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -94,27 +94,6 @@ size_t ContractCompiler::compileConstructor( } } -size_t ContractCompiler::compileClone( - ContractDefinition const& _contract, - map const& _contracts -) -{ - initializeContext(_contract, _contracts); - - appendInitAndConstructorCode(_contract); - - //@todo determine largest return size of all runtime functions - auto runtimeSub = m_context.addSubroutine(cloneRuntime()); - - // stack contains sub size - m_context << Instruction::DUP1 << runtimeSub << u256(0) << Instruction::CODECOPY; - m_context << u256(0) << Instruction::RETURN; - - appendMissingFunctions(); - - return size_t(runtimeSub.data()); -} - void ContractCompiler::initializeContext( ContractDefinition const& _contract, map const& _compiledContracts @@ -980,29 +959,6 @@ void ContractCompiler::compileExpression(Expression const& _expression, TypePoin CompilerUtils(m_context).convertType(*_expression.annotation().type, *_targetType); } -eth::AssemblyPointer ContractCompiler::cloneRuntime() const -{ - eth::Assembly a; - a << Instruction::CALLDATASIZE; - a << u256(0) << Instruction::DUP1 << Instruction::CALLDATACOPY; - //@todo adjust for larger return values, make this dynamic. - a << u256(0x20) << u256(0) << Instruction::CALLDATASIZE; - a << u256(0); - // this is the address which has to be substituted by the linker. - //@todo implement as special "marker" AssemblyItem. - a << u256("0xcafecafecafecafecafecafecafecafecafecafe"); - a << u256(eth::GasCosts::callGas(m_context.evmVersion()) + 10) << Instruction::GAS << Instruction::SUB; - a << Instruction::DELEGATECALL; - //Propagate error condition (if DELEGATECALL pushes 0 on stack). - a << Instruction::ISZERO; - a << Instruction::ISZERO; - eth::AssemblyItem afterTag = a.appendJumpI().tag(); - a << Instruction::INVALID << afterTag; - //@todo adjust for larger return values, make this dynamic. - a << u256(0x20) << u256(0) << Instruction::RETURN; - return make_shared(a); -} - void ContractCompiler::popScopedVariables(ASTNode const* _node) { unsigned blockHeight = m_scopeStackHeight.at(m_modifierDepth).at(_node); diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h index 8516ec2c..5fa650b1 100644 --- a/libsolidity/codegen/ContractCompiler.h +++ b/libsolidity/codegen/ContractCompiler.h @@ -56,13 +56,6 @@ public: ContractDefinition const& _contract, std::map const& _contracts ); - /// Compiles a contract that uses DELEGATECALL to call into a pre-deployed version of the given - /// contract at runtime, but contains the full creation-time code. - /// @returns the identifier of the runtime sub-assembly. - size_t compileClone( - ContractDefinition const& _contract, - std::map const& _contracts - ); private: /// Registers the non-function objects inside the contract with the context and stores the basic @@ -122,9 +115,6 @@ private: void appendStackVariableInitialisation(VariableDeclaration const& _variable); void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer()); - /// @returns the runtime assembly for clone contracts. - eth::AssemblyPointer cloneRuntime() const; - /// Frees the variables of a certain scope (to be used when leaving). void popScopedVariables(ASTNode const* _node); -- cgit v1.2.3 From b11e39e25ee14b2d56db86ea48e3229a7a6cad52 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 7 Aug 2018 18:44:51 +0200 Subject: Remove remaining instances of ``fillRight`` left over from tuple wildcards assignments. --- libsolidity/codegen/CompilerUtils.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index bd3ec8f5..b30851fb 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -947,20 +947,12 @@ void CompilerUtils::convertType( { TupleType const& sourceTuple = dynamic_cast(_typeOnStack); TupleType const& targetTuple = dynamic_cast(_targetType); - // fillRight: remove excess values at right side, !fillRight: remove eccess values at left side - bool fillRight = !targetTuple.components().empty() && ( - !targetTuple.components().back() || - targetTuple.components().front() - ); + solAssert(targetTuple.components().size() == sourceTuple.components().size(), ""); unsigned depth = sourceTuple.sizeOnStack(); for (size_t i = 0; i < sourceTuple.components().size(); ++i) { TypePointer sourceType = sourceTuple.components()[i]; - TypePointer targetType; - if (fillRight && i < targetTuple.components().size()) - targetType = targetTuple.components()[i]; - else if (!fillRight && targetTuple.components().size() + i >= sourceTuple.components().size()) - targetType = targetTuple.components()[targetTuple.components().size() - (sourceTuple.components().size() - i)]; + TypePointer targetType = targetTuple.components()[i]; if (!sourceType) { solAssert(!targetType, ""); -- cgit v1.2.3 From e902ce1aa02dc5d19cc9dd231fa538646884826d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Aereal=20Ae=C3=B3n?= Date: Wed, 8 Aug 2018 11:26:30 -0300 Subject: Removing std:: from std::to_string and include for boost/lexical_cast --- libsolidity/codegen/ContractCompiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 2f15a33d..2fffcf76 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -50,7 +50,7 @@ class StackHeightChecker public: explicit StackHeightChecker(CompilerContext const& _context): m_context(_context), stackHeight(m_context.stackHeight()) {} - void check() { solAssert(m_context.stackHeight() == stackHeight, std::string("I sense a disturbance in the stack: ") + std::to_string(m_context.stackHeight()) + " vs " + std::to_string(stackHeight)); } + void check() { solAssert(m_context.stackHeight() == stackHeight, std::string("I sense a disturbance in the stack: ") + to_string(m_context.stackHeight()) + " vs " + to_string(stackHeight)); } private: CompilerContext const& m_context; unsigned stackHeight; -- cgit v1.2.3 From a9819aa8bc68a35414aaa280d829018669ec770f Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 7 Aug 2018 23:38:08 +0100 Subject: Remove code generation for Throw statement It is disallowed in the type system. --- libsolidity/codegen/ContractCompiler.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 02274d60..e26bc13a 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -779,11 +779,9 @@ bool ContractCompiler::visit(Return const& _return) return false; } -bool ContractCompiler::visit(Throw const& _throw) +bool ContractCompiler::visit(Throw const&) { - CompilerContext::LocationSetter locationSetter(m_context, _throw); - // Do not send back an error detail. - m_context.appendRevert(); + solAssert(false, "Throw statement is disallowed."); return false; } -- cgit v1.2.3 From ed52f422b78b262c6d0e2e88b45e6cbeec470dc7 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 8 Aug 2018 16:31:46 +0100 Subject: Rename FunctionKind SHA3 to KECCAK256 (as the instruction was renamed in libevmasm) --- libsolidity/codegen/ExpressionCompiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 54518906..412a7255 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -701,7 +701,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context.appendRevert(); break; } - case FunctionType::Kind::SHA3: + case FunctionType::Kind::KECCAK256: { solAssert(arguments.size() == 1, ""); solAssert(!function.padArguments(), ""); -- cgit v1.2.3 From 9328ea4c3c023950e59405941cfc25ec4c0ed1b4 Mon Sep 17 00:00:00 2001 From: chriseth Date: Sat, 30 Jun 2018 18:09:13 +0200 Subject: Add abi.decode(bytes data, (...)) --- libsolidity/codegen/ExpressionCompiler.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 412a7255..7a4548f5 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1070,6 +1070,27 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) // stack now: break; } + case FunctionType::Kind::ABIDecode: + { + arguments.front()->accept(*this); + TypePointer firstArgType = arguments.front()->annotation().type; + TypePointers const& targetTypes = dynamic_cast(*_functionCall.annotation().type).components(); + if ( + *firstArgType == ArrayType(DataLocation::CallData) || + *firstArgType == ArrayType(DataLocation::CallData, true) + ) + utils().abiDecode(targetTypes, false); + else + { + utils().convertType(*firstArgType, ArrayType(DataLocation::Memory)); + m_context << Instruction::DUP1 << u256(32) << Instruction::ADD; + m_context << Instruction::SWAP1 << Instruction::MLOAD; + // stack now: + + utils().abiDecode(targetTypes, true); + } + break; + } case FunctionType::Kind::GasLeft: m_context << Instruction::GAS; break; -- cgit v1.2.3 From 7ca0aaaf6f62aafd0fe36ae6b7dc777361ae40e3 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 15 Aug 2018 14:40:20 +0200 Subject: Add ``staticcall`` to ``address``. --- libsolidity/codegen/ExpressionCompiler.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 7a4548f5..9baad7d1 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -571,6 +571,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) case FunctionType::Kind::BareCall: case FunctionType::Kind::BareCallCode: case FunctionType::Kind::BareDelegateCall: + case FunctionType::Kind::BareStaticCall: _functionCall.expression().accept(*this); appendExternalFunctionCall(function, arguments); break; @@ -1172,6 +1173,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) case FunctionType::Kind::BareCall: case FunctionType::Kind::BareCallCode: case FunctionType::Kind::BareDelegateCall: + case FunctionType::Kind::BareStaticCall: case FunctionType::Kind::Transfer: _memberAccess.expression().accept(*this); m_context << funType->externalIdentifier(); @@ -1273,7 +1275,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) ); m_context << Instruction::BALANCE; } - else if ((set{"send", "transfer", "call", "callcode", "delegatecall"}).count(member)) + else if ((set{"send", "transfer", "call", "callcode", "delegatecall", "staticcall"}).count(member)) utils().convertType( *_memberAccess.expression().annotation().type, IntegerType(160, IntegerType::Modifier::Address), @@ -1825,10 +1827,13 @@ void ExpressionCompiler::appendExternalFunctionCall( utils().moveToStackTop(gasValueSize, _functionType.selfType()->sizeOnStack()); auto funKind = _functionType.kind(); - bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall; + + solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), ""); + + bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::BareStaticCall; bool isCallCode = funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::CallCode; bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall; - bool useStaticCall = _functionType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall(); + bool useStaticCall = funKind == FunctionType::Kind::BareStaticCall || (_functionType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall()); bool haveReturndatacopy = m_context.evmVersion().supportsReturndata(); unsigned retSize = 0; -- cgit v1.2.3 From 455345871d286c24d393fbc9dea3d8a71f1a5b23 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 15 Aug 2018 17:11:43 +0200 Subject: More safeguards for (library) function types. --- libsolidity/codegen/ExpressionCompiler.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 7a4548f5..f1fce64f 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1164,18 +1164,18 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) solAssert(false, "event not found"); // no-op, because the parent node will do the job break; - case FunctionType::Kind::External: - case FunctionType::Kind::Creation: case FunctionType::Kind::DelegateCall: + _memberAccess.expression().accept(*this); + m_context << funType->externalIdentifier(); + break; case FunctionType::Kind::CallCode: + case FunctionType::Kind::External: + case FunctionType::Kind::Creation: case FunctionType::Kind::Send: case FunctionType::Kind::BareCall: case FunctionType::Kind::BareCallCode: case FunctionType::Kind::BareDelegateCall: case FunctionType::Kind::Transfer: - _memberAccess.expression().accept(*this); - m_context << funType->externalIdentifier(); - break; case FunctionType::Kind::Log0: case FunctionType::Kind::Log1: case FunctionType::Kind::Log2: -- cgit v1.2.3 From 94c327c1aeaf1fb09a53f1e4979b16f357b690c7 Mon Sep 17 00:00:00 2001 From: Anurag Dashputre Date: Thu, 23 Aug 2018 13:09:00 +0530 Subject: Removed unused "FunctionType::Kind::CallCode" from Types.h and all its usage --- libsolidity/codegen/ExpressionCompiler.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 53a06090..fbb1879a 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -566,7 +566,6 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) break; } case FunctionType::Kind::External: - case FunctionType::Kind::CallCode: case FunctionType::Kind::DelegateCall: case FunctionType::Kind::BareCall: case FunctionType::Kind::BareCallCode: @@ -1169,7 +1168,6 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) _memberAccess.expression().accept(*this); m_context << funType->externalIdentifier(); break; - case FunctionType::Kind::CallCode: case FunctionType::Kind::External: case FunctionType::Kind::Creation: case FunctionType::Kind::Send: @@ -1831,7 +1829,7 @@ void ExpressionCompiler::appendExternalFunctionCall( solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), ""); bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::BareStaticCall; - bool isCallCode = funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::CallCode; + bool isCallCode = funKind == FunctionType::Kind::BareCallCode; bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall; bool useStaticCall = funKind == FunctionType::Kind::BareStaticCall || (_functionType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall()); @@ -1959,7 +1957,7 @@ void ExpressionCompiler::appendExternalFunctionCall( bool existenceChecked = false; // Check the the target contract exists (has code) for non-low-level calls. - if (funKind == FunctionType::Kind::External || funKind == FunctionType::Kind::CallCode || funKind == FunctionType::Kind::DelegateCall) + if (funKind == FunctionType::Kind::External || funKind == FunctionType::Kind::DelegateCall) { m_context << Instruction::DUP1 << Instruction::EXTCODESIZE << Instruction::ISZERO; // TODO: error message? -- cgit v1.2.3 From a102f3b783dec236e9a733f5a5338efce3ef8319 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 3 Sep 2018 15:01:15 +0200 Subject: Remove trailing whitespace for all files in the repository. --- libsolidity/codegen/ExpressionCompiler.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index fbb1879a..a844aeb8 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -281,19 +281,19 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple) if (_tuple.isInlineArray()) { ArrayType const& arrayType = dynamic_cast(*_tuple.annotation().type); - + solAssert(!arrayType.isDynamicallySized(), "Cannot create dynamically sized inline array."); m_context << max(u256(32u), arrayType.memorySize()); utils().allocateMemory(); m_context << Instruction::DUP1; - + for (auto const& component: _tuple.components()) { component->accept(*this); utils().convertType(*component->annotation().type, *arrayType.baseType(), true); - utils().storeInMemoryDynamic(*arrayType.baseType(), true); + utils().storeInMemoryDynamic(*arrayType.baseType(), true); } - + m_context << Instruction::POP; } else @@ -1569,7 +1569,7 @@ void ExpressionCompiler::endVisit(Literal const& _literal) { CompilerContext::LocationSetter locationSetter(m_context, _literal); TypePointer type = _literal.annotation().type; - + switch (type->category()) { case Type::Category::RationalNumber: @@ -1827,7 +1827,7 @@ void ExpressionCompiler::appendExternalFunctionCall( auto funKind = _functionType.kind(); solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), ""); - + bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::BareStaticCall; bool isCallCode = funKind == FunctionType::Kind::BareCallCode; bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall; -- cgit v1.2.3 From 82f512a7d40a3bd6a13dd799be66dd164fded077 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 15 Aug 2018 23:30:09 +0200 Subject: Add return data to bare calls. --- libsolidity/codegen/ExpressionCompiler.cpp | 67 ++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 22 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index a844aeb8..3e8b7337 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1827,33 +1827,34 @@ void ExpressionCompiler::appendExternalFunctionCall( auto funKind = _functionType.kind(); solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), ""); - - bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::BareStaticCall; + + bool returnSuccessConditionAndReturndata = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::BareStaticCall; bool isCallCode = funKind == FunctionType::Kind::BareCallCode; bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall; bool useStaticCall = funKind == FunctionType::Kind::BareStaticCall || (_functionType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall()); bool haveReturndatacopy = m_context.evmVersion().supportsReturndata(); unsigned retSize = 0; - TypePointers returnTypes; - if (returnSuccessCondition) - retSize = 0; // return value actually is success condition - else if (haveReturndatacopy) - returnTypes = _functionType.returnParameterTypes(); - else - returnTypes = _functionType.returnParameterTypesWithoutDynamicTypes(); - bool dynamicReturnSize = false; - for (auto const& retType: returnTypes) - if (retType->isDynamicallyEncoded()) - { - solAssert(haveReturndatacopy, ""); - dynamicReturnSize = true; - retSize = 0; - break; - } + TypePointers returnTypes; + if (!returnSuccessConditionAndReturndata) + { + if (haveReturndatacopy) + returnTypes = _functionType.returnParameterTypes(); else - retSize += retType->calldataEncodedSize(); + returnTypes = _functionType.returnParameterTypesWithoutDynamicTypes(); + + for (auto const& retType: returnTypes) + if (retType->isDynamicallyEncoded()) + { + solAssert(haveReturndatacopy, ""); + dynamicReturnSize = true; + retSize = 0; + break; + } + else + retSize += retType->calldataEncodedSize(); + } // Evaluate arguments. TypePointers argumentTypes; @@ -1997,7 +1998,7 @@ void ExpressionCompiler::appendExternalFunctionCall( (_functionType.gasSet() ? 1 : 0) + (!_functionType.isBareCall() ? 1 : 0); - if (returnSuccessCondition) + if (returnSuccessConditionAndReturndata) m_context << swapInstruction(remainsSize); else { @@ -2008,9 +2009,31 @@ void ExpressionCompiler::appendExternalFunctionCall( utils().popStackSlots(remainsSize); - if (returnSuccessCondition) + if (returnSuccessConditionAndReturndata) { - // already there + // success condition is already there + // The return parameter types can be empty, when this function is used as + // an internal helper function e.g. for ``send`` and ``transfer``. In that + // case we're only interested in the success condition, not the return data. + if (!_functionType.returnParameterTypes().empty()) + { + if (haveReturndatacopy) + { + m_context << Instruction::RETURNDATASIZE; + m_context.appendInlineAssembly(R"({ + switch v case 0 { + v := 0x60 + } default { + v := mload(0x40) + mstore(0x40, add(v, and(add(returndatasize(), 0x3f), not(0x1f)))) + mstore(v, returndatasize()) + returndatacopy(add(v, 0x20), 0, returndatasize()) + } + })", {"v"}); + } + else + utils().pushZeroPointer(); + } } else if (funKind == FunctionType::Kind::RIPEMD160) { -- cgit v1.2.3 From 1ae6ec9038d83a82d5e8b57a8c6138dd4970d422 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 4 Sep 2018 17:28:52 +0200 Subject: Remove trailing whitespace. --- libsolidity/codegen/ExpressionCompiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 3e8b7337..a13b3e6c 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1827,7 +1827,7 @@ void ExpressionCompiler::appendExternalFunctionCall( auto funKind = _functionType.kind(); solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), ""); - + bool returnSuccessConditionAndReturndata = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::BareStaticCall; bool isCallCode = funKind == FunctionType::Kind::BareCallCode; bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall; -- cgit v1.2.3 From 624dbbe142fb04fdcdd83d843a00138eed296763 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 4 Sep 2018 16:24:21 +0200 Subject: Fix abi.decode returning single value. --- libsolidity/codegen/ExpressionCompiler.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 3e8b7337..aa9e438f 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1074,7 +1074,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) { arguments.front()->accept(*this); TypePointer firstArgType = arguments.front()->annotation().type; - TypePointers const& targetTypes = dynamic_cast(*_functionCall.annotation().type).components(); + TypePointers targetTypes; + if (TupleType const* targetTupleType = dynamic_cast(_functionCall.annotation().type.get())) + targetTypes = targetTupleType->components(); + else + targetTypes = TypePointers{_functionCall.annotation().type}; if ( *firstArgType == ArrayType(DataLocation::CallData) || *firstArgType == ArrayType(DataLocation::CallData, true) -- cgit v1.2.3 From 87804b6419a5894601441efe511015adda5fb119 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 3 Sep 2018 17:45:58 +0200 Subject: Split IntegerType into IntegerType and AddressType. --- libsolidity/codegen/ABIFunctions.cpp | 27 ++++++++++++++++++++++----- libsolidity/codegen/CompilerUtils.cpp | 27 ++++++++++++++++++++------- libsolidity/codegen/ExpressionCompiler.cpp | 15 ++++++++++----- 3 files changed, 52 insertions(+), 17 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index dda77958..5e5fe84a 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -197,6 +197,9 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure) templ("functionName", functionName); switch (_type.category()) { + case Type::Category::Address: + templ("body", "cleaned := " + cleanupFunction(IntegerType(160)) + "(value)"); + break; case Type::Category::Integer: { IntegerType const& type = dynamic_cast(_type); @@ -239,7 +242,7 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure) break; } case Type::Category::Contract: - templ("body", "cleaned := " + cleanupFunction(IntegerType(160, IntegerType::Modifier::Address)) + "(value)"); + templ("body", "cleaned := " + cleanupFunction(AddressType()) + "(value)"); break; case Type::Category::Enum: { @@ -284,6 +287,12 @@ string ABIFunctions::conversionFunction(Type const& _from, Type const& _to) auto fromCategory = _from.category(); switch (fromCategory) { + case Type::Category::Address: + body = + Whiskers("converted := (value)") + ("convert", conversionFunction(IntegerType(160), _to)) + .render(); + break; case Type::Category::Integer: case Type::Category::RationalNumber: case Type::Category::Contract: @@ -314,16 +323,19 @@ string ABIFunctions::conversionFunction(Type const& _from, Type const& _to) .render(); } else if (toCategory == Type::Category::FixedPoint) - { solUnimplemented("Not yet implemented - FixedPointType."); - } + else if (toCategory == Type::Category::Address) + body = + Whiskers("converted := (value)") + ("convert", conversionFunction(_from, IntegerType(160))) + .render(); else { solAssert( toCategory == Type::Category::Integer || toCategory == Type::Category::Contract, ""); - IntegerType const addressType(160, IntegerType::Modifier::Address); + IntegerType const addressType(160); IntegerType const& to = toCategory == Type::Category::Integer ? dynamic_cast(_to) : @@ -375,6 +387,11 @@ string ABIFunctions::conversionFunction(Type const& _from, Type const& _to) ("shift", shiftRightFunction(256 - from.numBytes() * 8)) ("convert", conversionFunction(IntegerType(from.numBytes() * 8), _to)) .render(); + else if (toCategory == Type::Category::Address) + body = + Whiskers("converted := (value)") + ("convert", conversionFunction(_from, IntegerType(160))) + .render(); else { // clear for conversion to longer bytes @@ -410,7 +427,7 @@ string ABIFunctions::conversionFunction(Type const& _from, Type const& _to) solAssert(false, ""); } - solAssert(!body.empty(), ""); + solAssert(!body.empty(), _from.canonicalName() + " to " + _to.canonicalName()); templ("body", body); return templ.render(); }); diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index b30851fb..e6ad6d9c 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -657,6 +657,11 @@ void CompilerUtils::convertType( if (targetIntegerType.numBits() < typeOnStack.numBytes() * 8) convertType(IntegerType(typeOnStack.numBytes() * 8), _targetType, _cleanupNeeded); } + else if (targetTypeCategory == Type::Category::Address) + { + solAssert(typeOnStack.numBytes() * 8 == 160, ""); + rightShiftNumberOnStack(256 - 160); + } else { // clear for conversion to longer bytes @@ -690,23 +695,33 @@ void CompilerUtils::convertType( break; case Type::Category::FixedPoint: solUnimplemented("Not yet implemented - FixedPointType."); + case Type::Category::Address: case Type::Category::Integer: case Type::Category::Contract: case Type::Category::RationalNumber: if (targetTypeCategory == Type::Category::FixedBytes) { - solAssert(stackTypeCategory == Type::Category::Integer || stackTypeCategory == Type::Category::RationalNumber, - "Invalid conversion to FixedBytesType requested."); + solAssert( + stackTypeCategory == Type::Category::Address || + stackTypeCategory == Type::Category::Integer || + stackTypeCategory == Type::Category::RationalNumber, + "Invalid conversion to FixedBytesType requested." + ); // conversion from bytes to string. no need to clean the high bit // only to shift left because of opposite alignment FixedBytesType const& targetBytesType = dynamic_cast(_targetType); if (auto typeOnStack = dynamic_cast(&_typeOnStack)) + { if (targetBytesType.numBytes() * 8 > typeOnStack->numBits()) cleanHigherOrderBits(*typeOnStack); + } + else if (stackTypeCategory == Type::Category::Address) + solAssert(targetBytesType.numBytes() * 8 == 160, ""); leftShiftNumberOnStack(256 - targetBytesType.numBytes() * 8); } else if (targetTypeCategory == Type::Category::Enum) { + solAssert(stackTypeCategory != Type::Category::Address, "Invalid conversion to EnumType requested."); solAssert(_typeOnStack.mobileType(), ""); // just clean convertType(_typeOnStack, *_typeOnStack.mobileType(), true); @@ -733,8 +748,8 @@ void CompilerUtils::convertType( } else { - solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Contract, ""); - IntegerType addressType(160, IntegerType::Modifier::Address); + solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Contract || targetTypeCategory == Type::Category::Address, ""); + IntegerType addressType(160); IntegerType const& targetType = targetTypeCategory == Type::Category::Integer ? dynamic_cast(_targetType) : addressType; if (stackTypeCategory == Type::Category::RationalNumber) @@ -996,10 +1011,8 @@ void CompilerUtils::convertType( m_context << Instruction::ISZERO << Instruction::ISZERO; break; default: - if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Integer) + if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Address) { - IntegerType const& targetType = dynamic_cast(_targetType); - solAssert(targetType.isAddress(), "Function type can only be converted to address."); FunctionType const& typeOnStack = dynamic_cast(_typeOnStack); solAssert(typeOnStack.kind() == FunctionType::Kind::External, "Only external function type can be converted."); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 4cc4ba53..4150bc11 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1259,7 +1259,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) identifier = FunctionType(*function).externalIdentifier(); else solAssert(false, "Contract member is neither variable nor function."); - utils().convertType(type, IntegerType(160, IntegerType::Modifier::Address), true); + utils().convertType(type, AddressType(), true); m_context << identifier; } else @@ -1267,12 +1267,17 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) break; } case Type::Category::Integer: + { + solAssert(false, "Invalid member access to integer"); + break; + } + case Type::Category::Address: { if (member == "balance") { utils().convertType( *_memberAccess.expression().annotation().type, - IntegerType(160, IntegerType::Modifier::Address), + AddressType(), true ); m_context << Instruction::BALANCE; @@ -1280,11 +1285,11 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) else if ((set{"send", "transfer", "call", "callcode", "delegatecall", "staticcall"}).count(member)) utils().convertType( *_memberAccess.expression().annotation().type, - IntegerType(160, IntegerType::Modifier::Address), + AddressType(), true ); else - solAssert(false, "Invalid member access to integer"); + solAssert(false, "Invalid member access to address"); break; } case Type::Category::Function: @@ -1578,7 +1583,7 @@ void ExpressionCompiler::endVisit(Literal const& _literal) { case Type::Category::RationalNumber: case Type::Category::Bool: - case Type::Category::Integer: + case Type::Category::Address: m_context << type->literalValue(&_literal); break; case Type::Category::StringLiteral: -- cgit v1.2.3 From 120438c0cf7abc506ca90221bafa2a9cbbb12994 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 4 Sep 2018 16:51:22 +0200 Subject: Always perform cleanup for EXP. --- libsolidity/codegen/ExpressionCompiler.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 4150bc11..45e58bd0 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -2138,7 +2138,9 @@ bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token::Value _ { if (Token::isCompareOp(_op) || Token::isShiftOp(_op)) return true; - else if (_type == Type::Category::Integer && (_op == Token::Div || _op == Token::Mod)) + else if (_type == Type::Category::Integer && (_op == Token::Div || _op == Token::Mod || _op == Token::Exp)) + // We need cleanup for EXP because 0**0 == 1, but 0**0x100 == 0 + // It would suffice to clean the exponent, though. return true; else return false; -- cgit v1.2.3 From b86cea033bc3a31c15356b46e28e0f303490d52d Mon Sep 17 00:00:00 2001 From: Anurag Dashputre Date: Thu, 13 Sep 2018 15:40:06 +0530 Subject: Removed default case from "ExpressionCompiler::visit(FunctionCall...)". --- libsolidity/codegen/ExpressionCompiler.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 45e58bd0..23faeef5 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1098,8 +1098,6 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) case FunctionType::Kind::GasLeft: m_context << Instruction::GAS; break; - default: - solAssert(false, "Invalid function type."); } } return false; -- cgit v1.2.3 From 12aaca16458861e9b622818d49a82c1a7026594e Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 5 Sep 2018 17:59:55 +0200 Subject: Add payable and non-payable state mutability to AddressType. --- libsolidity/codegen/ABIFunctions.cpp | 8 +++++++- libsolidity/codegen/ExpressionCompiler.cpp | 17 +++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 5e5fe84a..6c27533c 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -242,8 +242,14 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure) break; } case Type::Category::Contract: - templ("body", "cleaned := " + cleanupFunction(AddressType()) + "(value)"); + { + AddressType addressType(dynamic_cast(_type).isPayable() ? + StateMutability::Payable : + StateMutability::NonPayable + ); + templ("body", "cleaned := " + cleanupFunction(addressType) + "(value)"); break; + } case Type::Category::Enum: { size_t members = dynamic_cast(_type).numberOfMembers(); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 45e58bd0..bd863e05 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1259,7 +1259,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) identifier = FunctionType(*function).externalIdentifier(); else solAssert(false, "Contract member is neither variable nor function."); - utils().convertType(type, AddressType(), true); + utils().convertType(type, AddressType(type.isPayable() ? StateMutability::Payable : StateMutability::NonPayable), true); m_context << identifier; } else @@ -1277,15 +1277,24 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) { utils().convertType( *_memberAccess.expression().annotation().type, - AddressType(), + AddressType(StateMutability::NonPayable), true ); m_context << Instruction::BALANCE; } - else if ((set{"send", "transfer", "call", "callcode", "delegatecall", "staticcall"}).count(member)) + else if ((set{"send", "transfer"}).count(member)) + { + solAssert(dynamic_cast(*_memberAccess.expression().annotation().type).stateMutability() == StateMutability::Payable, ""); + utils().convertType( + *_memberAccess.expression().annotation().type, + AddressType(StateMutability::Payable), + true + ); + } + else if ((set{"call", "callcode", "delegatecall", "staticcall"}).count(member)) utils().convertType( *_memberAccess.expression().annotation().type, - AddressType(), + AddressType(StateMutability::NonPayable), true ); else -- cgit v1.2.3 From d0497aacc06524749c20f169dc59d2123f410581 Mon Sep 17 00:00:00 2001 From: Jordan Last Date: Thu, 13 Sep 2018 14:29:12 -0600 Subject: fixing rebase conflicts add ElementaryTypes::BytesMemory and ElementaryTypes::StringMemory fix rebase conflicts fixing rebase conflicts use make_shared instead of new fix tabs and StateMutability parameter create address and addressType functions, fix spaces in comment fix typo and switch nonpayable to payable fix spaces fix comment again --- libsolidity/codegen/ExpressionCompiler.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index bd863e05..8645f653 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -710,9 +710,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) arguments.front()->accept(*this); // Optimization: If type is bytes or string, then do not encode, // but directly compute keccak256 on memory. - if (*argType == ArrayType(DataLocation::Memory) || *argType == ArrayType(DataLocation::Memory, true)) + if (*argType == ArrayType::bytesMemory() || *argType == ArrayType::stringMemory()) { - ArrayUtils(m_context).retrieveLength(ArrayType(DataLocation::Memory)); + ArrayUtils(m_context).retrieveLength(ArrayType::bytesMemory()); m_context << Instruction::SWAP1 << u256(0x20) << Instruction::ADD; } else @@ -1086,7 +1086,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) utils().abiDecode(targetTypes, false); else { - utils().convertType(*firstArgType, ArrayType(DataLocation::Memory)); + utils().convertType(*firstArgType, ArrayType::bytesMemory()); m_context << Instruction::DUP1 << u256(32) << Instruction::ADD; m_context << Instruction::SWAP1 << Instruction::MLOAD; // stack now: @@ -1259,7 +1259,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) identifier = FunctionType(*function).externalIdentifier(); else solAssert(false, "Contract member is neither variable nor function."); - utils().convertType(type, AddressType(type.isPayable() ? StateMutability::Payable : StateMutability::NonPayable), true); + utils().convertType(type, type.isPayable() ? AddressType::addressPayable() : AddressType::address(), true); m_context << identifier; } else @@ -1277,7 +1277,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) { utils().convertType( *_memberAccess.expression().annotation().type, - AddressType(StateMutability::NonPayable), + AddressType::address(), true ); m_context << Instruction::BALANCE; @@ -1294,7 +1294,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) else if ((set{"call", "callcode", "delegatecall", "staticcall"}).count(member)) utils().convertType( *_memberAccess.expression().annotation().type, - AddressType(StateMutability::NonPayable), + AddressType::address(), true ); else -- cgit v1.2.3 From 44e8dfd3931f24202ee4a718242451ed990c3ff6 Mon Sep 17 00:00:00 2001 From: liangdzou Date: Thu, 20 Sep 2018 22:54:57 +0800 Subject: fix typo --- libsolidity/codegen/ExpressionCompiler.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 8645f653..587cf34a 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1230,7 +1230,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) else solAssert(false, "Contract member is neither variable nor function."); m_context << identifier; - /// need to store store it as bytes4 + /// need to store it as bytes4 utils().leftShiftNumberOnStack(224); return false; } @@ -1305,7 +1305,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) if (member == "selector") { m_context << Instruction::SWAP1 << Instruction::POP; - /// need to store store it as bytes4 + /// need to store it as bytes4 utils().leftShiftNumberOnStack(224); } else @@ -1975,7 +1975,7 @@ void ExpressionCompiler::appendExternalFunctionCall( m_context << dupInstruction(m_context.baseToCurrentStackOffset(contractStackPos)); bool existenceChecked = false; - // Check the the target contract exists (has code) for non-low-level calls. + // Check the target contract exists (has code) for non-low-level calls. if (funKind == FunctionType::Kind::External || funKind == FunctionType::Kind::DelegateCall) { m_context << Instruction::DUP1 << Instruction::EXTCODESIZE << Instruction::ISZERO; -- 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 -- libsolidity/codegen/CompilerUtils.cpp | 9 --------- 2 files changed, 11 deletions(-) (limited to 'libsolidity/codegen') 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, ""); } } diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index e6ad6d9c..2bdf88e3 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -895,15 +895,6 @@ void CompilerUtils::convertType( typeOnStack.location() == DataLocation::CallData, "Invalid conversion to calldata type."); break; - default: - solAssert( - false, - "Invalid type conversion " + - _typeOnStack.toString(false) + - " to " + - _targetType.toString(false) + - " requested." - ); } break; } -- cgit v1.2.3 From d76bfcd935407e7249cfb8480a29da24615667cf Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 4 Oct 2018 13:03:55 +0200 Subject: Fix typos. --- libsolidity/codegen/CompilerUtils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h index ad3d7327..bd8170ad 100644 --- a/libsolidity/codegen/CompilerUtils.h +++ b/libsolidity/codegen/CompilerUtils.h @@ -260,7 +260,7 @@ public: /// Stack post: void rightShiftNumberOnStack(unsigned _bits); - /// Appends code that computes tha Keccak-256 hash of the topmost stack element of 32 byte type. + /// Appends code that computes the Keccak-256 hash of the topmost stack element of 32 byte type. void computeHashStatic(); /// Bytes we need to the start of call data. -- cgit v1.2.3 From fa0ce6a7e7abd5bbc9bad1dd15f54ea4e9b11f85 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 9 Oct 2018 04:29:37 +0100 Subject: Use empty() instead of size() == 0 --- libsolidity/codegen/ContractCompiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index e26bc13a..3a0fccfb 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -965,7 +965,7 @@ void ContractCompiler::popScopedVariables(ASTNode const* _node) unsigned stackDiff = m_context.stackHeight() - blockHeight; CompilerUtils(m_context).popStackSlots(stackDiff); m_scopeStackHeight[m_modifierDepth].erase(_node); - if (m_scopeStackHeight[m_modifierDepth].size() == 0) + if (m_scopeStackHeight[m_modifierDepth].empty()) m_scopeStackHeight.erase(m_modifierDepth); } -- cgit v1.2.3 From 1304361b9c48438d5c55903492b5f11c3dac73e5 Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Mon, 15 Oct 2018 11:58:51 +0200 Subject: Renaming namespace dev::julia to dev::yul. --- libsolidity/codegen/CompilerContext.cpp | 12 ++++++------ libsolidity/codegen/ContractCompiler.cpp | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 71b615b8..089386b5 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -318,10 +318,10 @@ void CompilerContext::appendInlineAssembly( { int startStackHeight = stackHeight(); - julia::ExternalIdentifierAccess identifierAccess; + yul::ExternalIdentifierAccess identifierAccess; identifierAccess.resolve = [&]( assembly::Identifier const& _identifier, - julia::IdentifierContext, + yul::IdentifierContext, bool ) { @@ -330,15 +330,15 @@ void CompilerContext::appendInlineAssembly( }; identifierAccess.generateCode = [&]( assembly::Identifier const& _identifier, - julia::IdentifierContext _context, - julia::AbstractAssembly& _assembly + yul::IdentifierContext _context, + yul::AbstractAssembly& _assembly ) { auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name); solAssert(it != _localVariables.end(), ""); int stackDepth = _localVariables.end() - it; int stackDiff = _assembly.stackHeight() - startStackHeight + stackDepth; - if (_context == julia::IdentifierContext::LValue) + if (_context == yul::IdentifierContext::LValue) stackDiff -= 1; if (stackDiff < 1 || stackDiff > 16) BOOST_THROW_EXCEPTION( @@ -346,7 +346,7 @@ void CompilerContext::appendInlineAssembly( errinfo_sourceLocation(_identifier.location) << errinfo_comment("Stack too deep (" + to_string(stackDiff) + "), try removing local variables.") ); - if (_context == julia::IdentifierContext::RValue) + if (_context == yul::IdentifierContext::RValue) _assembly.appendInstruction(dupInstruction(stackDiff)); else { diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 3a0fccfb..c845da8f 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -494,21 +494,21 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) { unsigned startStackHeight = m_context.stackHeight(); - julia::ExternalIdentifierAccess identifierAccess; - identifierAccess.resolve = [&](assembly::Identifier const& _identifier, julia::IdentifierContext, bool) + yul::ExternalIdentifierAccess identifierAccess; + identifierAccess.resolve = [&](assembly::Identifier const& _identifier, yul::IdentifierContext, bool) { auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); if (ref == _inlineAssembly.annotation().externalReferences.end()) return size_t(-1); return ref->second.valueSize; }; - identifierAccess.generateCode = [&](assembly::Identifier const& _identifier, julia::IdentifierContext _context, julia::AbstractAssembly& _assembly) + identifierAccess.generateCode = [&](assembly::Identifier const& _identifier, yul::IdentifierContext _context, yul::AbstractAssembly& _assembly) { auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); solAssert(ref != _inlineAssembly.annotation().externalReferences.end(), ""); Declaration const* decl = ref->second.declaration; solAssert(!!decl, ""); - if (_context == julia::IdentifierContext::RValue) + if (_context == yul::IdentifierContext::RValue) { int const depositBefore = _assembly.stackHeight(); solAssert(!!decl->type(), "Type of declaration required but not yet determined."); -- cgit v1.2.3 From 5e01d767d02d064a064a67dcf95ee299c46f741f Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 17 Jan 2018 12:05:43 +0100 Subject: Prevent externally used functions from being removed. --- libsolidity/codegen/ABIFunctions.cpp | 15 +++++++++++---- libsolidity/codegen/ABIFunctions.h | 15 ++++++++++++--- libsolidity/codegen/CompilerContext.cpp | 1 + libsolidity/codegen/CompilerContext.h | 2 ++ libsolidity/codegen/ContractCompiler.cpp | 6 +++--- 5 files changed, 29 insertions(+), 10 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 6c27533c..bd29b382 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -49,7 +49,7 @@ string ABIFunctions::tupleEncoder( if (_encodeAsLibraryTypes) functionName += "_library"; - return createFunction(functionName, [&]() { + return createExternallyUsedFunction(functionName, [&]() { solAssert(!_givenTypes.empty(), ""); // Note that the values are in reverse due to the difference in calling semantics. @@ -113,7 +113,7 @@ string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMemory) solAssert(!_types.empty(), ""); - return createFunction(functionName, [&]() { + return createExternallyUsedFunction(functionName, [&]() { TypePointers decodingTypes; for (auto const& t: _types) decodingTypes.emplace_back(t->decodingType()); @@ -176,13 +176,13 @@ string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMemory) }); } -string ABIFunctions::requestedFunctions() +pair> ABIFunctions::requestedFunctions() { string result; for (auto const& f: m_requestedFunctions) result += f.second; m_requestedFunctions.clear(); - return result; + return make_pair(result, std::move(m_externallyUsedFunctions)); } string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure) @@ -1697,6 +1697,13 @@ string ABIFunctions::createFunction(string const& _name, function con return _name; } +string ABIFunctions::createExternallyUsedFunction(string const& _name, function const& _creator) +{ + string name = createFunction(_name, _creator); + m_externallyUsedFunctions.insert(name); + return name; +} + size_t ABIFunctions::headSize(TypePointers const& _targetTypes) { size_t headSize = 0; diff --git a/libsolidity/codegen/ABIFunctions.h b/libsolidity/codegen/ABIFunctions.h index 3caaa1d9..e9ffe4fb 100644 --- a/libsolidity/codegen/ABIFunctions.h +++ b/libsolidity/codegen/ABIFunctions.h @@ -28,6 +28,7 @@ #include #include +#include #include namespace dev { @@ -80,8 +81,11 @@ public: /// stack slot, it takes exactly that number of values. std::string tupleDecoder(TypePointers const& _types, bool _fromMemory = false); - /// @returns concatenation of all generated functions. - std::string requestedFunctions(); + /// @returns concatenation of all generated functions and a set of the + /// externally used functions. + /// Clears the internal list, i.e. calling it again will result in an + /// empty return value. + std::pair> requestedFunctions(); private: /// @returns the name of the cleanup function for the given type and @@ -224,12 +228,17 @@ private: /// cases. std::string createFunction(std::string const& _name, std::function const& _creator); + /// Helper function that uses @a _creator to create a function and add it to + /// @a m_requestedFunctions if it has not been created yet and returns @a _name in both + /// cases. Also adds it to the list of externally used functions. + std::string createExternallyUsedFunction(std::string const& _name, std::function const& _creator); + /// @returns the size of the static part of the encoding of the given types. static size_t headSize(TypePointers const& _targetTypes); /// Map from function name to code for a multi-use function. std::map m_requestedFunctions; - + std::set m_externallyUsedFunctions; EVMVersion m_evmVersion; }; diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 089386b5..210b613d 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -313,6 +313,7 @@ void CompilerContext::resetVisitedNodes(ASTNode const* _node) void CompilerContext::appendInlineAssembly( string const& _assembly, vector const& _localVariables, + set const&, bool _system ) { diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 3f357821..5bdc1d19 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -206,10 +206,12 @@ public: /// Appends inline assembly (strict mode). /// @a _replacements are string-matching replacements that are performed prior to parsing the inline assembly. /// @param _localVariables assigns stack positions to variables with the last one being the stack top + /// @param _externallyUsedFunctions a set of function names that are not to be renamed or removed. /// @param _system if true, this is a "system-level" assembly where all functions use named labels. void appendInlineAssembly( std::string const& _assembly, std::vector const& _localVariables = std::vector(), + std::set const& _externallyUsedFunctions = std::set(), bool _system = false ); diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index c845da8f..1fdf3483 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -874,9 +874,9 @@ void ContractCompiler::appendMissingFunctions() solAssert(m_context.nextFunctionToCompile() != function, "Compiled the wrong function?"); } m_context.appendMissingLowLevelFunctions(); - string abiFunctions = m_context.abiFunctions().requestedFunctions(); - if (!abiFunctions.empty()) - m_context.appendInlineAssembly("{" + move(abiFunctions) + "}", {}, true); + auto abiFunctions = m_context.abiFunctions().requestedFunctions(); + if (!abiFunctions.first.empty()) + m_context.appendInlineAssembly("{" + move(abiFunctions.first) + "}", {}, abiFunctions.second, true); } void ContractCompiler::appendModifierOrFunctionCode() -- cgit v1.2.3 From c14dfeb8c5ffcc15cff1014a39ffa425aee1430a Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 17 Oct 2018 22:17:33 +0200 Subject: Removed unreachable cases in LValue.cpp. --- libsolidity/codegen/LValue.cpp | 49 ++++++------------------------------------ 1 file changed, 7 insertions(+), 42 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index 77684683..790ab309 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -134,8 +134,7 @@ void MemoryItem::storeValue(Type const& _sourceType, SourceLocation const&, bool void MemoryItem::setToZero(SourceLocation const&, bool _removeReference) const { CompilerUtils utils(m_context); - if (!_removeReference) - m_context << Instruction::DUP1; + solAssert(_removeReference, ""); utils.pushZeroValue(*m_dataType); utils.storeInMemoryDynamic(*m_dataType, m_padded); m_context << Instruction::POP; @@ -460,8 +459,7 @@ void StorageByteArrayElement::storeValue(Type const&, SourceLocation const&, boo void StorageByteArrayElement::setToZero(SourceLocation const&, bool _removeReference) const { // stack: ref byte_number - if (!_removeReference) - m_context << Instruction::DUP2 << Instruction::DUP2; + solAssert(_removeReference, ""); m_context << u256(31) << Instruction::SUB << u256(0x100) << Instruction::EXP; // stack: ref (1<<(8*(31-byte_number))) m_context << Instruction::DUP2 << Instruction::SLOAD; @@ -498,8 +496,7 @@ void StorageArrayLength::storeValue(Type const&, SourceLocation const&, bool _mo void StorageArrayLength::setToZero(SourceLocation const&, bool _removeReference) const { - if (!_removeReference) - m_context << Instruction::DUP1; + solAssert(_removeReference, ""); ArrayUtils(m_context).clearDynamicArray(m_arrayType); } @@ -521,24 +518,9 @@ unsigned TupleObject::sizeOnStack() const return size; } -void TupleObject::retrieveValue(SourceLocation const& _location, bool _remove) const +void TupleObject::retrieveValue(SourceLocation const&, bool) const { - unsigned initialDepth = sizeOnStack(); - unsigned initialStack = m_context.stackHeight(); - for (auto const& lv: m_lvalues) - if (lv) - { - solAssert(initialDepth + m_context.stackHeight() >= initialStack, ""); - unsigned depth = initialDepth + m_context.stackHeight() - initialStack; - if (lv->sizeOnStack() > 0) - { - if (_remove && depth > lv->sizeOnStack()) - CompilerUtils(m_context).moveToStackTop(depth, depth - lv->sizeOnStack()); - else if (!_remove && depth > 0) - CompilerUtils(m_context).copyToStackTop(depth, lv->sizeOnStack()); - } - lv->retrieveValue(_location, true); - } + solAssert(false, "Tried to retrieve value of tuple."); } void TupleObject::storeValue(Type const& _sourceType, SourceLocation const& _location, bool) const @@ -569,24 +551,7 @@ void TupleObject::storeValue(Type const& _sourceType, SourceLocation const& _loc CompilerUtils(m_context).popStackElement(_sourceType); } -void TupleObject::setToZero(SourceLocation const& _location, bool _removeReference) const +void TupleObject::setToZero(SourceLocation const&, bool) const { - if (_removeReference) - { - for (size_t i = 0; i < m_lvalues.size(); ++i) - if (m_lvalues[m_lvalues.size() - i]) - m_lvalues[m_lvalues.size() - i]->setToZero(_location, true); - } - else - { - unsigned depth = sizeOnStack(); - for (auto const& val: m_lvalues) - if (val) - { - if (val->sizeOnStack() > 0) - CompilerUtils(m_context).copyToStackTop(depth, val->sizeOnStack()); - val->setToZero(_location, false); - depth -= val->sizeOnStack(); - } - } + solAssert(false, "Tried to delete tuple."); } -- cgit v1.2.3 From 97d01d9b47acf6a0383872fab81d27bc75773b48 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 17 Oct 2018 22:26:10 +0200 Subject: Assert about some removed language concepts in the code generator. --- libsolidity/codegen/ExpressionCompiler.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 27440289..749739ce 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -568,12 +568,13 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) case FunctionType::Kind::External: case FunctionType::Kind::DelegateCall: case FunctionType::Kind::BareCall: - case FunctionType::Kind::BareCallCode: case FunctionType::Kind::BareDelegateCall: case FunctionType::Kind::BareStaticCall: _functionCall.expression().accept(*this); appendExternalFunctionCall(function, arguments); break; + case FunctionType::Kind::BareCallCode: + solAssert(false, "Callcode has been removed."); case FunctionType::Kind::Creation: { _functionCall.expression().accept(*this); @@ -1328,8 +1329,6 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) m_context << Instruction::CALLVALUE; else if (member == "origin") m_context << Instruction::ORIGIN; - else if (member == "gas") - m_context << Instruction::GAS; else if (member == "gasprice") m_context << Instruction::GASPRICE; else if (member == "data") @@ -1337,9 +1336,10 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) else if (member == "sig") m_context << u256(0) << Instruction::CALLDATALOAD << (u256(0xffffffff) << (256 - 32)) << Instruction::AND; + else if (member == "gas") + solAssert(false, "Gas has been removed."); else if (member == "blockhash") - { - } + solAssert(false, "Blockhash has been removed."); else solAssert(false, "Unknown magic member."); break; @@ -1844,8 +1844,9 @@ void ExpressionCompiler::appendExternalFunctionCall( solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), ""); - bool returnSuccessConditionAndReturndata = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::BareStaticCall; - bool isCallCode = funKind == FunctionType::Kind::BareCallCode; + solAssert(funKind != FunctionType::Kind::BareCallCode, "Callcode has been removed."); + + bool returnSuccessConditionAndReturndata = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::BareStaticCall; bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall; bool useStaticCall = funKind == FunctionType::Kind::BareStaticCall || (_functionType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall()); @@ -1930,7 +1931,7 @@ void ExpressionCompiler::appendExternalFunctionCall( parameterTypes, _functionType.padArguments(), _functionType.takesArbitraryParameters() || _functionType.isBareCall(), - isCallCode || isDelegateCall + isDelegateCall ); // Stack now: @@ -2001,8 +2002,6 @@ void ExpressionCompiler::appendExternalFunctionCall( // Order is important here, STATICCALL might overlap with DELEGATECALL. if (isDelegateCall) m_context << Instruction::DELEGATECALL; - else if (isCallCode) - m_context << Instruction::CALLCODE; else if (useStaticCall) m_context << Instruction::STATICCALL; else -- cgit v1.2.3 From e78b95d9d4ecb6d8d56ca0f04a6f9b4f7d974fbb Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 18 Oct 2018 13:35:20 +0200 Subject: Renamed SHA3.{h,cpp} files. --- libsolidity/codegen/ExpressionCompiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 27440289..3383d8ae 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From f112377dd44e8281bff092639bb546ec8a6a39ac Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Mon, 22 Oct 2018 16:48:21 +0200 Subject: Refactor `solidity::Token` into an `enum class` with `TokenTraits` helper namespace --- libsolidity/codegen/ExpressionCompiler.cpp | 40 +++++++++++++++--------------- libsolidity/codegen/ExpressionCompiler.h | 12 ++++----- 2 files changed, 26 insertions(+), 26 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 749739ce..63faddd3 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -206,8 +206,8 @@ bool ExpressionCompiler::visit(Conditional const& _condition) bool ExpressionCompiler::visit(Assignment const& _assignment) { CompilerContext::LocationSetter locationSetter(m_context, _assignment); - Token::Value op = _assignment.assignmentOperator(); - Token::Value binOp = op == Token::Assign ? op : Token::AssignmentToBinaryOp(op); + Token op = _assignment.assignmentOperator(); + Token binOp = op == Token::Assign ? op : TokenTraits::AssignmentToBinaryOp(op); Type const& leftType = *_assignment.leftHandSide().annotation().type; if (leftType.category() == Type::Category::Tuple) { @@ -223,7 +223,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) // Perform some conversion already. This will convert storage types to memory and literals // to their actual type, but will not convert e.g. memory to storage. TypePointer rightIntermediateType; - if (op != Token::Assign && Token::isShiftOp(binOp)) + if (op != Token::Assign && TokenTraits::isShiftOp(binOp)) rightIntermediateType = _assignment.rightHandSide().annotation().type->mobileType(); else rightIntermediateType = _assignment.rightHandSide().annotation().type->closestTemporaryType( @@ -251,7 +251,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) m_currentLValue->retrieveValue(_assignment.location(), true); utils().convertType(leftType, leftType, cleanupNeeded); - if (Token::isShiftOp(binOp)) + if (TokenTraits::isShiftOp(binOp)) appendShiftOperatorCode(binOp, leftType, *rightIntermediateType); else { @@ -384,7 +384,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) m_context << u256(0) << Instruction::SUB; break; default: - solAssert(false, "Invalid unary operator: " + string(Token::toString(_unaryOperation.getOperator()))); + solAssert(false, "Invalid unary operator: " + string(TokenTraits::toString(_unaryOperation.getOperator()))); } return false; } @@ -396,7 +396,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) Expression const& rightExpression = _binaryOperation.rightExpression(); solAssert(!!_binaryOperation.annotation().commonType, ""); TypePointer const& commonType = _binaryOperation.annotation().commonType; - Token::Value const c_op = _binaryOperation.getOperator(); + Token const c_op = _binaryOperation.getOperator(); if (c_op == Token::And || c_op == Token::Or) // special case: short-circuiting appendAndOrOperatorCode(_binaryOperation); @@ -407,7 +407,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) bool cleanupNeeded = cleanupNeededForOp(commonType->category(), c_op); TypePointer leftTargetType = commonType; - TypePointer rightTargetType = Token::isShiftOp(c_op) ? rightExpression.annotation().type->mobileType() : commonType; + TypePointer rightTargetType = TokenTraits::isShiftOp(c_op) ? rightExpression.annotation().type->mobileType() : commonType; solAssert(rightTargetType, ""); // for commutative operators, push the literal as late as possible to allow improved optimization @@ -415,7 +415,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) { return dynamic_cast(&_e) || _e.annotation().type->category() == Type::Category::RationalNumber; }; - bool swap = m_optimize && Token::isCommutativeOp(c_op) && isLiteral(rightExpression) && !isLiteral(leftExpression); + bool swap = m_optimize && TokenTraits::isCommutativeOp(c_op) && isLiteral(rightExpression) && !isLiteral(leftExpression); if (swap) { leftExpression.accept(*this); @@ -430,10 +430,10 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) leftExpression.accept(*this); utils().convertType(*leftExpression.annotation().type, *leftTargetType, cleanupNeeded); } - if (Token::isShiftOp(c_op)) + if (TokenTraits::isShiftOp(c_op)) // shift only cares about the signedness of both sides appendShiftOperatorCode(c_op, *leftTargetType, *rightTargetType); - else if (Token::isCompareOp(c_op)) + else if (TokenTraits::isCompareOp(c_op)) appendCompareOperatorCode(c_op, *commonType); else appendOrdinaryBinaryOperatorCode(c_op, *commonType); @@ -1602,7 +1602,7 @@ void ExpressionCompiler::endVisit(Literal const& _literal) void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryOperation) { - Token::Value const c_op = _binaryOperation.getOperator(); + Token const c_op = _binaryOperation.getOperator(); solAssert(c_op == Token::Or || c_op == Token::And, ""); _binaryOperation.leftExpression().accept(*this); @@ -1615,7 +1615,7 @@ void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryO m_context << endLabel; } -void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type const& _type) +void ExpressionCompiler::appendCompareOperatorCode(Token _operator, Type const& _type) { solAssert(_type.sizeOnStack() == 1, "Comparison of multi-slot types."); if (_operator == Token::Equal || _operator == Token::NotEqual) @@ -1665,17 +1665,17 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type } } -void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type) +void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token _operator, Type const& _type) { - if (Token::isArithmeticOp(_operator)) + if (TokenTraits::isArithmeticOp(_operator)) appendArithmeticOperatorCode(_operator, _type); - else if (Token::isBitOp(_operator)) + else if (TokenTraits::isBitOp(_operator)) appendBitOperatorCode(_operator); else solAssert(false, "Unknown binary operator."); } -void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type) +void ExpressionCompiler::appendArithmeticOperatorCode(Token _operator, Type const& _type) { if (_type.category() == Type::Category::FixedPoint) solUnimplemented("Not yet implemented - FixedPointType."); @@ -1715,7 +1715,7 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty } } -void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) +void ExpressionCompiler::appendBitOperatorCode(Token _operator) { switch (_operator) { @@ -1733,7 +1733,7 @@ void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) } } -void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator, Type const& _valueType, Type const& _shiftAmountType) +void ExpressionCompiler::appendShiftOperatorCode(Token _operator, Type const& _valueType, Type const& _shiftAmountType) { // stack: shift_amount value_to_shift @@ -2140,9 +2140,9 @@ void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression) setLValue(_expression, *_expression.annotation().type); } -bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token::Value _op) +bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token _op) { - if (Token::isCompareOp(_op) || Token::isShiftOp(_op)) + if (TokenTraits::isCompareOp(_op) || TokenTraits::isShiftOp(_op)) return true; else if (_type == Type::Category::Integer && (_op == Token::Div || _op == Token::Mod || _op == Token::Exp)) // We need cleanup for EXP because 0**0 == 1, but 0**0x100 == 0 diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h index cdfa096e..3d8e8682 100644 --- a/libsolidity/codegen/ExpressionCompiler.h +++ b/libsolidity/codegen/ExpressionCompiler.h @@ -86,12 +86,12 @@ private: ///@{ ///@name Append code for various operator types void appendAndOrOperatorCode(BinaryOperation const& _binaryOperation); - void appendCompareOperatorCode(Token::Value _operator, Type const& _type); - void appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type); + void appendCompareOperatorCode(Token _operator, Type const& _type); + void appendOrdinaryBinaryOperatorCode(Token _operator, Type const& _type); - void appendArithmeticOperatorCode(Token::Value _operator, Type const& _type); - void appendBitOperatorCode(Token::Value _operator); - void appendShiftOperatorCode(Token::Value _operator, Type const& _valueType, Type const& _shiftAmountType); + void appendArithmeticOperatorCode(Token _operator, Type const& _type); + void appendBitOperatorCode(Token _operator); + void appendShiftOperatorCode(Token _operator, Type const& _valueType, Type const& _shiftAmountType); /// @} /// Appends code to call a function of the given type with the given arguments. @@ -119,7 +119,7 @@ private: /// @returns true if the operator applied to the given type requires a cleanup prior to the /// operation. - static bool cleanupNeededForOp(Type::Category _type, Token::Value _op); + static bool cleanupNeededForOp(Type::Category _type, Token _op); /// @returns the CompilerUtils object containing the current context. CompilerUtils utils(); -- cgit v1.2.3 From cab8dea7fe676ded3d7d682db0a2233012333e5f Mon Sep 17 00:00:00 2001 From: Lazaridis Date: Thu, 11 Oct 2018 08:25:27 +0300 Subject: refine memory-store assertions, closes #4891 --- libsolidity/codegen/CompilerUtils.cpp | 58 ++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 21 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 2bdf88e3..d89d023e 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -142,9 +142,13 @@ void CompilerUtils::storeInMemory(unsigned _offset) void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries) { + // process special types (Reference, StringLiteral, Function) if (auto ref = dynamic_cast(&_type)) { - solUnimplementedAssert(ref->location() == DataLocation::Memory, "Only in-memory reference type can be stored."); + solUnimplementedAssert( + ref->location() == DataLocation::Memory, + "Only in-memory reference type can be stored." + ); storeInMemoryDynamic(IntegerType(256), _padToWordBoundaries); } else if (auto str = dynamic_cast(&_type)) @@ -166,18 +170,18 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound m_context << Instruction::DUP2 << Instruction::MSTORE; m_context << u256(_padToWordBoundaries ? 32 : 24) << Instruction::ADD; } - else + else if (_type.isValueType()) { unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries); - if (numBytes > 0) - { - solUnimplementedAssert( - _type.sizeOnStack() == 1, - "Memory store of types with stack size != 1 not implemented." - ); - m_context << Instruction::DUP2 << Instruction::MSTORE; - m_context << u256(numBytes) << Instruction::ADD; - } + m_context << Instruction::DUP2 << Instruction::MSTORE; + m_context << u256(numBytes) << Instruction::ADD; + } + else // Should never happen + { + solAssert( + false, + "Memory store of type " + _type.toString(true) + " not allowed." + ); } } @@ -1266,18 +1270,30 @@ void CompilerUtils::rightShiftNumberOnStack(unsigned _bits) unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWords) { + solAssert( + _type.sizeOnStack() == 1, + "Memory store of types with stack size != 1 not allowed (Type: " + _type.toString(true) + ")." + ); + unsigned numBytes = _type.calldataEncodedSize(_padToWords); + + solAssert( + numBytes > 0, + "Memory store of 0 bytes requested (Type: " + _type.toString(true) + ")." + ); + + solAssert( + numBytes <= 32, + "Memory store of more than 32 bytes requested (Type: " + _type.toString(true) + ")." + ); + bool leftAligned = _type.category() == Type::Category::FixedBytes; - if (numBytes == 0) - m_context << Instruction::POP; - else - { - solAssert(numBytes <= 32, "Memory store of more than 32 bytes requested."); - convertType(_type, _type, true); - if (numBytes != 32 && !leftAligned && !_padToWords) - // shift the value accordingly before storing - leftShiftNumberOnStack((32 - numBytes) * 8); - } + + convertType(_type, _type, true); + if (numBytes != 32 && !leftAligned && !_padToWords) + // shift the value accordingly before storing + leftShiftNumberOnStack((32 - numBytes) * 8); + return numBytes; } -- cgit v1.2.3 From a3e37a9d5aa2039255783ffba4629574c4acf4c6 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 6 Nov 2018 13:22:33 +0100 Subject: Relax identity requirement of function type conversions during code generation. --- libsolidity/codegen/CompilerUtils.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index d89d023e..22f97dfa 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1014,6 +1014,8 @@ void CompilerUtils::convertType( // stack:
m_context << Instruction::POP; } + else if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Function) + solAssert(_typeOnStack.isImplicitlyConvertibleTo(_targetType), "Invalid function type conversion requested."); else { // All other types should not be convertible to non-equal types. -- cgit v1.2.3 From 674e17c2a895eff6729357d8c10db709ac368b79 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 29 Oct 2018 15:12:02 +0100 Subject: Performance: Replace string by special single-copy YulString class. --- libsolidity/codegen/CompilerContext.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 210b613d..6e14d68a 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -326,7 +327,7 @@ void CompilerContext::appendInlineAssembly( bool ) { - auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name); + auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str()); return it == _localVariables.end() ? size_t(-1) : 1; }; identifierAccess.generateCode = [&]( @@ -335,7 +336,7 @@ void CompilerContext::appendInlineAssembly( yul::AbstractAssembly& _assembly ) { - auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name); + auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str()); solAssert(it != _localVariables.end(), ""); int stackDepth = _localVariables.end() - it; int stackDiff = _assembly.stackHeight() - startStackHeight + stackDepth; -- cgit v1.2.3 From b16a3644fe7d54ed5fa6d7a7dac40b4aab641e76 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 6 Nov 2018 13:29:49 +0100 Subject: Function type conversion test cases. --- libsolidity/codegen/CompilerUtils.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'libsolidity/codegen') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 22f97dfa..90eb74fe 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1014,12 +1014,24 @@ void CompilerUtils::convertType( // stack:
m_context << Instruction::POP; } - else if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Function) - solAssert(_typeOnStack.isImplicitlyConvertibleTo(_targetType), "Invalid function type conversion requested."); else { - // All other types should not be convertible to non-equal types. - solAssert(_typeOnStack == _targetType, "Invalid type conversion requested."); + if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Function) + { + FunctionType const& typeOnStack = dynamic_cast(_typeOnStack); + FunctionType const& targetType = dynamic_cast(_targetType); + solAssert( + typeOnStack.isImplicitlyConvertibleTo(targetType) && + typeOnStack.sizeOnStack() == targetType.sizeOnStack() && + (typeOnStack.kind() == FunctionType::Kind::Internal || typeOnStack.kind() == FunctionType::Kind::External) && + typeOnStack.kind() == targetType.kind(), + "Invalid function type conversion requested." + ); + } + 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) -- cgit v1.2.3