diff options
Diffstat (limited to 'libsolidity/codegen/ExpressionCompiler.cpp')
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 83 |
1 files changed, 52 insertions, 31 deletions
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 53a06090..a13b3e6c 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<ArrayType const&>(*_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 @@ -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: @@ -1571,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: @@ -1829,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 isCallCode = funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::CallCode; + + 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; @@ -1959,7 +1958,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? @@ -1999,7 +1998,7 @@ void ExpressionCompiler::appendExternalFunctionCall( (_functionType.gasSet() ? 1 : 0) + (!_functionType.isBareCall() ? 1 : 0); - if (returnSuccessCondition) + if (returnSuccessConditionAndReturndata) m_context << swapInstruction(remainsSize); else { @@ -2010,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) { |