| 2730 | } |
| 2731 | |
| 2732 | void ExpressionCompiler::appendExternalFunctionCall( |
| 2733 | FunctionType const& _functionType, |
| 2734 | std::vector<ASTPointer<Expression const>> const& _arguments, |
| 2735 | bool _tryCall |
| 2736 | ) |
| 2737 | { |
| 2738 | solAssert( |
| 2739 | _functionType.takesArbitraryParameters() || |
| 2740 | _arguments.size() == _functionType.parameterTypes().size(), "" |
| 2741 | ); |
| 2742 | |
| 2743 | // Assumed stack content here: |
| 2744 | // <stack top> |
| 2745 | // value [if _functionType.valueSet()] |
| 2746 | // gas [if _functionType.gasSet()] |
| 2747 | // self object [if bound - moved to top right away] |
| 2748 | // function identifier [unless bare] |
| 2749 | // contract address |
| 2750 | |
| 2751 | unsigned selfSize = _functionType.hasBoundFirstArgument() ? _functionType.selfType()->sizeOnStack() : 0; |
| 2752 | unsigned gasValueSize = (_functionType.gasSet() ? 1u : 0u) + (_functionType.valueSet() ? 1u : 0u); |
| 2753 | unsigned contractStackPos = m_context.currentToBaseStackOffset(1 + gasValueSize + selfSize + (_functionType.isBareCall() ? 0 : 1)); |
| 2754 | unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize); |
| 2755 | unsigned valueStackPos = m_context.currentToBaseStackOffset(1); |
| 2756 | |
| 2757 | // move self object to top |
| 2758 | if (_functionType.hasBoundFirstArgument()) |
| 2759 | utils().moveToStackTop(gasValueSize, _functionType.selfType()->sizeOnStack()); |
| 2760 | |
| 2761 | auto funKind = _functionType.kind(); |
| 2762 | |
| 2763 | solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), ""); |
| 2764 | |
| 2765 | solAssert(funKind != FunctionType::Kind::BareCallCode, "Callcode has been removed."); |
| 2766 | |
| 2767 | bool returnSuccessConditionAndReturndata = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::BareStaticCall; |
| 2768 | bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall; |
| 2769 | bool useStaticCall = funKind == FunctionType::Kind::BareStaticCall || (_functionType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall()); |
| 2770 | |
| 2771 | if (_tryCall) |
| 2772 | { |
| 2773 | solAssert(!returnSuccessConditionAndReturndata, ""); |
| 2774 | solAssert(!_functionType.isBareCall(), ""); |
| 2775 | } |
| 2776 | |
| 2777 | ReturnInfo const returnInfo{m_context.evmVersion(), _functionType}; |
| 2778 | bool const haveReturndatacopy = m_context.evmVersion().supportsReturndata(); |
| 2779 | unsigned const retSize = returnInfo.estimatedReturnSize; |
| 2780 | bool const dynamicReturnSize = returnInfo.dynamicReturnSize; |
| 2781 | TypePointers const& returnTypes = returnInfo.returnTypes; |
| 2782 | |
| 2783 | // Evaluate arguments. |
| 2784 | TypePointers argumentTypes; |
| 2785 | TypePointers parameterTypes = _functionType.parameterTypes(); |
| 2786 | if (_functionType.hasBoundFirstArgument()) |
| 2787 | { |
| 2788 | argumentTypes.push_back(_functionType.selfType()); |
| 2789 | parameterTypes.insert(parameterTypes.begin(), _functionType.selfType()); |
nothing calls this directly
no test coverage detected