diff options
author | Christian <c@ethdev.com> | 2014-12-11 06:01:40 +0800 |
---|---|---|
committer | Christian <c@ethdev.com> | 2014-12-13 00:26:19 +0800 |
commit | c0bba438b1d93b3ebba46e03935dbdf8b1ba6bd5 (patch) | |
tree | b3fa2b6b006b6d1b9799abe9e2ed25ddc685d370 /ExpressionCompiler.cpp | |
parent | 6893d4d4557e9968feaa162c8fc5ea3859aa0565 (diff) | |
download | dexon-solidity-c0bba438b1d93b3ebba46e03935dbdf8b1ba6bd5.tar.gz dexon-solidity-c0bba438b1d93b3ebba46e03935dbdf8b1ba6bd5.tar.zst dexon-solidity-c0bba438b1d93b3ebba46e03935dbdf8b1ba6bd5.zip |
Calls to bare contracts.
Diffstat (limited to 'ExpressionCompiler.cpp')
-rw-r--r-- | ExpressionCompiler.cpp | 122 |
1 files changed, 66 insertions, 56 deletions
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 3beb423d..add5f73b 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -194,7 +194,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) else { FunctionType const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType()); - std::vector<ASTPointer<Expression const>> arguments = _functionCall.getArguments(); + vector<ASTPointer<Expression const>> arguments = _functionCall.getArguments(); if (asserts(arguments.size() == function.getParameterTypes().size())) BOOST_THROW_EXCEPTION(InternalCompilerError()); @@ -227,50 +227,23 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) break; } case Location::EXTERNAL: + case Location::BARE: { - unsigned dataOffset = 1; // reserve one byte for the function index - for (unsigned i = 0; i < arguments.size(); ++i) - { - arguments[i]->accept(*this); - Type const& type = *function.getParameterTypes()[i]; - appendTypeConversion(*arguments[i]->getType(), type); - unsigned const numBytes = type.getCalldataEncodedSize(); - if (numBytes == 0 || numBytes > 32) - BOOST_THROW_EXCEPTION(CompilerError() - << errinfo_sourceLocation(arguments[i]->getLocation()) - << errinfo_comment("Type " + type.toString() + " not yet supported.")); - bool const leftAligned = type.getCategory() == Type::Category::STRING; - CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned); - dataOffset += numBytes; - } - //@todo only return the first return value for now - Type const* firstType = function.getReturnParameterTypes().empty() ? nullptr : - function.getReturnParameterTypes().front().get(); - unsigned retSize = firstType ? firstType->getCalldataEncodedSize() : 0; - // CALL arguments: outSize, outOff, inSize, inOff, value, addr, gas (stack top) - m_context << u256(retSize) << u256(0) << u256(dataOffset) << u256(0) << u256(0); - _functionCall.getExpression().accept(*this); // pushes addr and function index - m_context << u256(0) << eth::Instruction::MSTORE8 - << u256(25) << eth::Instruction::GAS << eth::Instruction::SUB - << eth::Instruction::CALL - << eth::Instruction::POP; // @todo do not ignore failure indicator - if (retSize > 0) - { - bool const leftAligned = firstType->getCategory() == Type::Category::STRING; - CompilerUtils(m_context).loadFromMemory(0, retSize, leftAligned); - } + FunctionCallOptions options; + options.bare = function.getLocation() == Location::BARE; + options.obtainAddress = [&]() { _functionCall.getExpression().accept(*this); }; + appendExternalFunctionCall(function, arguments, options); break; } case Location::SEND: - m_context << u256(0) << u256(0) << u256(0) << u256(0); - arguments.front()->accept(*this); - //@todo might not be necessary - appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); - _functionCall.getExpression().accept(*this); - m_context << u256(25) << eth::Instruction::GAS << eth::Instruction::SUB - << eth::Instruction::CALL - << eth::Instruction::POP; + { + FunctionCallOptions options; + options.bare = true; + options.obtainAddress = [&]() { _functionCall.getExpression().accept(*this); }; + options.obtainValue = [&]() { arguments.front()->accept(*this); }; + appendExternalFunctionCall(FunctionType({}, {}, Location::EXTERNAL), {}, options); break; + } case Location::SUICIDE: arguments.front()->accept(*this); //@todo might not be necessary @@ -292,19 +265,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) {Location::SHA256, 2}, {Location::RIPEMD160, 3}}; u256 contractAddress = contractAddresses.find(function.getLocation())->second; - // @todo later, combine this code with external function call - for (unsigned i = 0; i < arguments.size(); ++i) - { - arguments[i]->accept(*this); - appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i], true); - // @todo move this once we actually use memory - CompilerUtils(m_context).storeInMemory(i * 32); - } - m_context << u256(32) << u256(0) << u256(arguments.size() * 32) << u256(0) << u256(0) - << contractAddress << u256(500) //@todo determine actual gas requirement - << eth::Instruction::CALL - << eth::Instruction::POP; - CompilerUtils(m_context).loadFromMemory(0); + FunctionCallOptions options; + options.bare = true; + options.obtainAddress = [&]() { m_context << contractAddress; }; + options.packDensely = false; + appendExternalFunctionCall(function, arguments, options); break; } default: @@ -326,11 +291,9 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) IntegerType(0, IntegerType::Modifier::ADDRESS), true); m_context << eth::Instruction::BALANCE; } - else if (member == "send") - { + else if (member == "send" || member.substr(0, 4) == "call") appendTypeConversion(*_memberAccess.getExpression().getType(), IntegerType(0, IntegerType::Modifier::ADDRESS), true); - } else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer.")); break; @@ -587,6 +550,53 @@ void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND; } +void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functionType, + vector<ASTPointer<Expression const>> const& _arguments, + FunctionCallOptions const& _options) +{ + if (asserts(_arguments.size() == _functionType.getParameterTypes().size())) + BOOST_THROW_EXCEPTION(InternalCompilerError()); + + unsigned dataOffset = _options.bare ? 0 : 1; // reserve one byte for the function index + for (unsigned i = 0; i < _arguments.size(); ++i) + { + _arguments[i]->accept(*this); + Type const& type = *_functionType.getParameterTypes()[i]; + appendTypeConversion(*_arguments[i]->getType(), type); + unsigned const numBytes = _options.packDensely ? type.getCalldataEncodedSize() : 32; + if (numBytes == 0 || numBytes > 32) + BOOST_THROW_EXCEPTION(CompilerError() + << errinfo_sourceLocation(_arguments[i]->getLocation()) + << errinfo_comment("Type " + type.toString() + " not yet supported.")); + bool const leftAligned = type.getCategory() == Type::Category::STRING; + CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned); + dataOffset += numBytes; + } + //@todo only return the first return value for now + Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr : + _functionType.getReturnParameterTypes().front().get(); + unsigned retSize = firstType ? firstType->getCalldataEncodedSize() : 0; + if (!_options.packDensely && retSize > 0) + retSize = 32; + // CALL arguments: outSize, outOff, inSize, inOff, value, addr, gas (stack top) + m_context << u256(retSize) << u256(0) << u256(dataOffset) << u256(0); + if (_options.obtainValue) + _options.obtainValue(); + else + m_context << u256(0); + _options.obtainAddress(); + if (!_options.bare) + m_context << u256(0) << eth::Instruction::MSTORE8; + m_context << u256(25) << eth::Instruction::GAS << eth::Instruction::SUB + << eth::Instruction::CALL + << eth::Instruction::POP; // @todo do not ignore failure indicator + if (retSize > 0) + { + bool const leftAligned = firstType->getCategory() == Type::Category::STRING; + CompilerUtils(m_context).loadFromMemory(0, retSize, leftAligned); + } +} + ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType, unsigned _baseStackOffset): m_context(&_compilerContext), m_type(_type), m_baseStackOffset(_baseStackOffset), |