aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Compiler.cpp16
-rw-r--r--ExpressionCompiler.cpp39
-rw-r--r--Types.cpp6
3 files changed, 45 insertions, 16 deletions
diff --git a/Compiler.cpp b/Compiler.cpp
index 6dc72840..40ed1fd8 100644
--- a/Compiler.cpp
+++ b/Compiler.cpp
@@ -178,6 +178,16 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
map<FixedHash<4>, FunctionTypePointer> interfaceFunctions = _contract.getInterfaceFunctions();
map<FixedHash<4>, const eth::AssemblyItem> callDataUnpackerEntryPoints;
+ FunctionDefinition const* fallback = _contract.getFallbackFunction();
+ eth::AssemblyItem notFound = m_context.newTag();
+ // shortcut messages without data if we have many functions in order to be able to receive
+ // ether with constant gas
+ if (interfaceFunctions.size() > 5 || fallback)
+ {
+ m_context << eth::Instruction::CALLDATASIZE << eth::Instruction::ISZERO;
+ m_context.appendConditionalJumpTo(notFound);
+ }
+
// retrieve the function signature hash from the calldata
if (!interfaceFunctions.empty())
CompilerUtils(m_context).loadFromMemory(0, IntegerType(CompilerUtils::dataStartOffset * 8), true);
@@ -189,7 +199,10 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
m_context << eth::dupInstruction(1) << u256(FixedHash<4>::Arith(it.first)) << eth::Instruction::EQ;
m_context.appendConditionalJumpTo(callDataUnpackerEntryPoints.at(it.first));
}
- if (FunctionDefinition const* fallback = _contract.getFallbackFunction())
+ m_context.appendJumpTo(notFound);
+
+ m_context << notFound;
+ if (fallback)
{
eth::AssemblyItem returnTag = m_context.pushNewTag();
fallback->accept(*this);
@@ -198,6 +211,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
}
else
m_context << eth::Instruction::STOP; // function not found
+
for (auto const& it: interfaceFunctions)
{
FunctionTypePointer const& functionType = it.second;
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp
index 62df9205..bac967d8 100644
--- a/ExpressionCompiler.cpp
+++ b/ExpressionCompiler.cpp
@@ -521,6 +521,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
break;
case Location::Send:
_functionCall.getExpression().accept(*this);
+ m_context << u256(0); // do not send gas (there still is the stipend)
arguments.front()->accept(*this);
appendTypeConversion(*arguments.front()->getType(),
*function.getParameterTypes().front(), true);
@@ -532,7 +533,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
strings(),
Location::Bare,
false,
- false,
+ true,
true
),
{}
@@ -1057,10 +1058,15 @@ void ExpressionCompiler::appendExternalFunctionCall(
unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize);
unsigned valueStackPos = m_context.currentToBaseStackOffset(1);
+ bool returnSuccessCondition =
+ _functionType.getLocation() == FunctionType::Location::Bare ||
+ _functionType.getLocation() == FunctionType::Location::BareCallCode;
//@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 (returnSuccessCondition)
+ retSize = 0; // return value actually is success condition
m_context << u256(retSize) << u256(0);
if (_functionType.isBareCall())
@@ -1111,19 +1117,28 @@ void ExpressionCompiler::appendExternalFunctionCall(
else
m_context << eth::Instruction::CALL;
- //Propagate error condition (if CALL pushes 0 on stack).
- m_context << eth::Instruction::ISZERO;
- m_context.appendConditionalJumpTo(m_context.errorTag());
+ unsigned remainsSize =
+ 1 + // contract address
+ _functionType.valueSet() +
+ _functionType.gasSet() +
+ !_functionType.isBareCall();
- if (_functionType.valueSet())
- m_context << eth::Instruction::POP;
- if (_functionType.gasSet())
- m_context << eth::Instruction::POP;
- if (!_functionType.isBareCall())
- m_context << eth::Instruction::POP;
- m_context << eth::Instruction::POP; // pop contract address
+ if (returnSuccessCondition)
+ m_context << eth::swapInstruction(remainsSize);
+ else
+ {
+ //Propagate error condition (if CALL pushes 0 on stack).
+ m_context << eth::Instruction::ISZERO;
+ m_context.appendConditionalJumpTo(m_context.errorTag());
+ }
- if (_functionType.getLocation() == FunctionType::Location::RIPEMD160)
+ CompilerUtils(m_context).popStackSlots(remainsSize);
+
+ if (returnSuccessCondition)
+ {
+ // already there
+ }
+ else if (_functionType.getLocation() == FunctionType::Location::RIPEMD160)
{
// fix: built-in contract returns right-aligned data
CompilerUtils(m_context).loadFromMemory(0, IntegerType(160), false, true);
diff --git a/Types.cpp b/Types.cpp
index 03e8e4ee..1316bbc3 100644
--- a/Types.cpp
+++ b/Types.cpp
@@ -317,9 +317,9 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
const MemberList IntegerType::AddressMemberList({
{"balance", make_shared<IntegerType >(256)},
- {"call", make_shared<FunctionType>(strings(), strings(), FunctionType::Location::Bare, true)},
- {"callcode", make_shared<FunctionType>(strings(), strings(), FunctionType::Location::BareCallCode, true)},
- {"send", make_shared<FunctionType>(strings{"uint"}, strings{}, FunctionType::Location::Send)}
+ {"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::Bare, true)},
+ {"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::BareCallCode, true)},
+ {"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Location::Send)}
});
IntegerConstantType::IntegerConstantType(Literal const& _literal)