aboutsummaryrefslogtreecommitdiffstats
path: root/ExpressionCompiler.cpp
diff options
context:
space:
mode:
authorChristian <c@ethdev.com>2014-12-11 06:01:40 +0800
committerChristian <c@ethdev.com>2014-12-13 00:26:19 +0800
commitc0bba438b1d93b3ebba46e03935dbdf8b1ba6bd5 (patch)
treeb3fa2b6b006b6d1b9799abe9e2ed25ddc685d370 /ExpressionCompiler.cpp
parent6893d4d4557e9968feaa162c8fc5ea3859aa0565 (diff)
downloaddexon-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.cpp122
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),