mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Sending ether.
This commit is contained in:
parent
a2715c5f34
commit
f30dc68cdd
@ -325,7 +325,7 @@ bool Compiler::visit(ExpressionStatement& _expressionStatement)
|
|||||||
Expression& expression = _expressionStatement.getExpression();
|
Expression& expression = _expressionStatement.getExpression();
|
||||||
ExpressionCompiler::compileExpression(m_context, expression);
|
ExpressionCompiler::compileExpression(m_context, expression);
|
||||||
Type::Category category = expression.getType()->getCategory();
|
Type::Category category = expression.getType()->getCategory();
|
||||||
if (category != Type::Category::VOID && category != Type::Category::MAGIC)
|
for (unsigned i = 0; i < expression.getType()->getSizeOnStack(); ++i)
|
||||||
m_context << eth::Instruction::POP;
|
m_context << eth::Instruction::POP;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -179,33 +179,62 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//@todo: check for "external call" (to be stored in type)
|
|
||||||
|
|
||||||
// Calling convention: Caller pushes return address and arguments
|
|
||||||
// Callee removes them and pushes return values
|
|
||||||
FunctionType const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType());
|
FunctionType const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType());
|
||||||
|
|
||||||
eth::AssemblyItem returnLabel = m_context.pushNewTag();
|
|
||||||
std::vector<ASTPointer<Expression>> const& arguments = _functionCall.getArguments();
|
std::vector<ASTPointer<Expression>> const& arguments = _functionCall.getArguments();
|
||||||
if (asserts(arguments.size() == function.getParameterTypes().size()))
|
if (asserts(arguments.size() == function.getParameterTypes().size()))
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError());
|
BOOST_THROW_EXCEPTION(InternalCompilerError());
|
||||||
for (unsigned i = 0; i < arguments.size(); ++i)
|
|
||||||
|
if (function.getLocation() == FunctionType::Location::INTERNAL)
|
||||||
{
|
{
|
||||||
arguments[i]->accept(*this);
|
// Calling convention: Caller pushes return address and arguments
|
||||||
appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i]);
|
// Callee removes them and pushes return values
|
||||||
|
|
||||||
|
eth::AssemblyItem returnLabel = m_context.pushNewTag();
|
||||||
|
for (unsigned i = 0; i < arguments.size(); ++i)
|
||||||
|
{
|
||||||
|
arguments[i]->accept(*this);
|
||||||
|
appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i]);
|
||||||
|
}
|
||||||
|
_functionCall.getExpression().accept(*this);
|
||||||
|
|
||||||
|
m_context.appendJump();
|
||||||
|
m_context << returnLabel;
|
||||||
|
|
||||||
|
// callee adds return parameters, but removes arguments and return label
|
||||||
|
m_context.adjustStackOffset(function.getReturnParameterTypes().size() - arguments.size() - 1);
|
||||||
|
|
||||||
|
// @todo for now, the return value of a function is its first return value, so remove
|
||||||
|
// all others
|
||||||
|
for (unsigned i = 1; i < function.getReturnParameterTypes().size(); ++i)
|
||||||
|
m_context << eth::Instruction::POP;
|
||||||
|
}
|
||||||
|
else if (function.getLocation() == FunctionType::Location::EXTERNAL)
|
||||||
|
{
|
||||||
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("External function calls not implemented yet."));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (function.getLocation())
|
||||||
|
{
|
||||||
|
case FunctionType::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());
|
||||||
|
_functionCall.getExpression().accept(*this);
|
||||||
|
m_context << u256(25) << eth::Instruction::GAS << eth::Instruction::SUB
|
||||||
|
<< eth::Instruction::CALL
|
||||||
|
<< eth::Instruction::POP;
|
||||||
|
break;
|
||||||
|
case FunctionType::Location::SUICIDE:
|
||||||
|
arguments.front()->accept(*this);
|
||||||
|
//@todo might not be necessary
|
||||||
|
appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front());
|
||||||
|
m_context << eth::Instruction::SUICIDE;
|
||||||
|
default:
|
||||||
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Function not yet implemented."));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_functionCall.getExpression().accept(*this);
|
|
||||||
|
|
||||||
m_context.appendJump();
|
|
||||||
m_context << returnLabel;
|
|
||||||
|
|
||||||
// callee adds return parameters, but removes arguments and return label
|
|
||||||
m_context.adjustStackOffset(function.getReturnParameterTypes().size() - arguments.size() - 1);
|
|
||||||
|
|
||||||
// @todo for now, the return value of a function is its first return value, so remove
|
|
||||||
// all others
|
|
||||||
for (unsigned i = 1; i < function.getReturnParameterTypes().size(); ++i)
|
|
||||||
m_context << eth::Instruction::POP;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -216,9 +245,13 @@ void ExpressionCompiler::endVisit(MemberAccess& _memberAccess)
|
|||||||
switch (_memberAccess.getExpression().getType()->getCategory())
|
switch (_memberAccess.getExpression().getType()->getCategory())
|
||||||
{
|
{
|
||||||
case Type::Category::INTEGER:
|
case Type::Category::INTEGER:
|
||||||
if (asserts(member == "balance"))
|
if (member == "balance")
|
||||||
|
m_context << eth::Instruction::BALANCE;
|
||||||
|
else if (member == "send")
|
||||||
|
{ // no modification
|
||||||
|
}
|
||||||
|
else
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer."));
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer."));
|
||||||
m_context << eth::Instruction::BALANCE;
|
|
||||||
break;
|
break;
|
||||||
case Type::Category::CONTRACT:
|
case Type::Category::CONTRACT:
|
||||||
// call function
|
// call function
|
||||||
|
@ -132,6 +132,10 @@ private:
|
|||||||
|
|
||||||
CompilerContext& m_context;
|
CompilerContext& m_context;
|
||||||
LValue m_currentLValue;
|
LValue m_currentLValue;
|
||||||
|
/// If a "virtual" function (i.e. a bulit-in function without jump tag) is encountered, the
|
||||||
|
/// actual function is stored here. @todo prevent assignment or store it with assignment
|
||||||
|
enum class SpecialFunction { NONE, SEND, SHA3, SUICIDE, ECRECOVER, SHA256, RIPEMD160 };
|
||||||
|
SpecialFunction m_currentSpecialFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
16
Types.cpp
16
Types.cpp
@ -192,7 +192,7 @@ u256 IntegerType::literalValue(Literal const& _literal) const
|
|||||||
const MemberList IntegerType::AddressMemberList =
|
const MemberList IntegerType::AddressMemberList =
|
||||||
MemberList({{"balance", make_shared<IntegerType const>(256)},
|
MemberList({{"balance", make_shared<IntegerType const>(256)},
|
||||||
{"send", make_shared<FunctionType const>(TypePointers({make_shared<IntegerType const>(256)}),
|
{"send", make_shared<FunctionType const>(TypePointers({make_shared<IntegerType const>(256)}),
|
||||||
TypePointers())}});
|
TypePointers(), FunctionType::Location::SEND)}});
|
||||||
|
|
||||||
bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||||
{
|
{
|
||||||
@ -314,6 +314,7 @@ FunctionType::FunctionType(FunctionDefinition const& _function)
|
|||||||
retParams.push_back(var->getType());
|
retParams.push_back(var->getType());
|
||||||
swap(params, m_parameterTypes);
|
swap(params, m_parameterTypes);
|
||||||
swap(retParams, m_returnParameterTypes);
|
swap(retParams, m_returnParameterTypes);
|
||||||
|
m_location = Location::INTERNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FunctionType::operator==(Type const& _other) const
|
bool FunctionType::operator==(Type const& _other) const
|
||||||
@ -347,6 +348,19 @@ string FunctionType::toString() const
|
|||||||
return name + ")";
|
return name + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned FunctionType::getSizeOnStack() const
|
||||||
|
{
|
||||||
|
switch (m_location)
|
||||||
|
{
|
||||||
|
case Location::INTERNAL:
|
||||||
|
return 1;
|
||||||
|
case Location::EXTERNAL:
|
||||||
|
return 2;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool MappingType::operator==(Type const& _other) const
|
bool MappingType::operator==(Type const& _other) const
|
||||||
{
|
{
|
||||||
if (_other.getCategory() != getCategory())
|
if (_other.getCategory() != getCategory())
|
||||||
|
19
Types.h
19
Types.h
@ -115,6 +115,7 @@ public:
|
|||||||
/// Returns true if the type can be stored as a value (as opposed to a reference) on the stack,
|
/// Returns true if the type can be stored as a value (as opposed to a reference) on the stack,
|
||||||
/// i.e. it behaves differently in lvalue context and in value context.
|
/// i.e. it behaves differently in lvalue context and in value context.
|
||||||
virtual bool isValueType() const { return false; }
|
virtual bool isValueType() const { return false; }
|
||||||
|
virtual unsigned getSizeOnStack() const { return 1; }
|
||||||
|
|
||||||
/// Returns the list of all members of this type. Default implementation: no members.
|
/// Returns the list of all members of this type. Default implementation: no members.
|
||||||
virtual MemberList const& getMembers() const { return EmptyMemberList; }
|
virtual MemberList const& getMembers() const { return EmptyMemberList; }
|
||||||
@ -235,6 +236,7 @@ public:
|
|||||||
virtual bool operator==(Type const& _other) const override;
|
virtual bool operator==(Type const& _other) const override;
|
||||||
virtual u256 getStorageSize() const override;
|
virtual u256 getStorageSize() const override;
|
||||||
virtual bool canLiveOutsideStorage() const override;
|
virtual bool canLiveOutsideStorage() const override;
|
||||||
|
virtual unsigned getSizeOnStack() const override { return 1; /*@todo*/ }
|
||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
|
|
||||||
virtual MemberList const& getMembers() const override;
|
virtual MemberList const& getMembers() const override;
|
||||||
@ -255,10 +257,17 @@ private:
|
|||||||
class FunctionType: public Type
|
class FunctionType: public Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// The meaning of the value(s) on the stack referencing the function:
|
||||||
|
/// INTERNAL: jump tag, EXTERNAL: contract address + function index,
|
||||||
|
/// OTHERS: special virtual function, nothing on the stack
|
||||||
|
enum class Location { INTERNAL, EXTERNAL, SEND, SHA3, SUICIDE, ECRECOVER, SHA256, RIPEMD160 };
|
||||||
|
|
||||||
virtual Category getCategory() const override { return Category::FUNCTION; }
|
virtual Category getCategory() const override { return Category::FUNCTION; }
|
||||||
explicit FunctionType(FunctionDefinition const& _function);
|
explicit FunctionType(FunctionDefinition const& _function);
|
||||||
FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes):
|
FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes,
|
||||||
m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes) {}
|
Location _location = Location::INTERNAL):
|
||||||
|
m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes),
|
||||||
|
m_location(_location) {}
|
||||||
|
|
||||||
TypePointers const& getParameterTypes() const { return m_parameterTypes; }
|
TypePointers const& getParameterTypes() const { return m_parameterTypes; }
|
||||||
TypePointers const& getReturnParameterTypes() const { return m_returnParameterTypes; }
|
TypePointers const& getReturnParameterTypes() const { return m_returnParameterTypes; }
|
||||||
@ -268,10 +277,14 @@ public:
|
|||||||
virtual bool canBeStored() const override { return false; }
|
virtual bool canBeStored() const override { return false; }
|
||||||
virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable function type requested.")); }
|
virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable function type requested.")); }
|
||||||
virtual bool canLiveOutsideStorage() const override { return false; }
|
virtual bool canLiveOutsideStorage() const override { return false; }
|
||||||
|
virtual unsigned getSizeOnStack() const override;
|
||||||
|
|
||||||
|
Location getLocation() const { return m_location; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TypePointers m_parameterTypes;
|
TypePointers m_parameterTypes;
|
||||||
TypePointers m_returnParameterTypes;
|
TypePointers m_returnParameterTypes;
|
||||||
|
Location m_location;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -310,6 +323,7 @@ public:
|
|||||||
virtual bool canBeStored() const override { return false; }
|
virtual bool canBeStored() const override { return false; }
|
||||||
virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable void type requested.")); }
|
virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable void type requested.")); }
|
||||||
virtual bool canLiveOutsideStorage() const override { return false; }
|
virtual bool canLiveOutsideStorage() const override { return false; }
|
||||||
|
virtual unsigned getSizeOnStack() const override { return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -349,6 +363,7 @@ public:
|
|||||||
virtual bool operator==(Type const& _other) const;
|
virtual bool operator==(Type const& _other) const;
|
||||||
virtual bool canBeStored() const override { return false; }
|
virtual bool canBeStored() const override { return false; }
|
||||||
virtual bool canLiveOutsideStorage() const override { return true; }
|
virtual bool canLiveOutsideStorage() const override { return true; }
|
||||||
|
virtual unsigned getSizeOnStack() const override { return 0; }
|
||||||
virtual MemberList const& getMembers() const override { return m_members; }
|
virtual MemberList const& getMembers() const override { return m_members; }
|
||||||
|
|
||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
|
Loading…
Reference in New Issue
Block a user