aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Compiler.cpp2
-rw-r--r--ExpressionCompiler.cpp79
-rw-r--r--ExpressionCompiler.h4
-rw-r--r--Types.cpp16
-rw-r--r--Types.h19
5 files changed, 93 insertions, 27 deletions
diff --git a/Compiler.cpp b/Compiler.cpp
index a82ecd95..988390d0 100644
--- a/Compiler.cpp
+++ b/Compiler.cpp
@@ -325,7 +325,7 @@ bool Compiler::visit(ExpressionStatement& _expressionStatement)
Expression& expression = _expressionStatement.getExpression();
ExpressionCompiler::compileExpression(m_context, expression);
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;
return false;
}
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp
index 9e396874..f5ab829c 100644
--- a/ExpressionCompiler.cpp
+++ b/ExpressionCompiler.cpp
@@ -179,33 +179,62 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
}
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());
-
- eth::AssemblyItem returnLabel = m_context.pushNewTag();
std::vector<ASTPointer<Expression>> const& arguments = _functionCall.getArguments();
if (asserts(arguments.size() == function.getParameterTypes().size()))
BOOST_THROW_EXCEPTION(InternalCompilerError());
- for (unsigned i = 0; i < arguments.size(); ++i)
+
+ if (function.getLocation() == FunctionType::Location::INTERNAL)
{
- arguments[i]->accept(*this);
- appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i]);
+ // Calling convention: Caller pushes return address and arguments
+ // 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;
}
@@ -216,9 +245,13 @@ void ExpressionCompiler::endVisit(MemberAccess& _memberAccess)
switch (_memberAccess.getExpression().getType()->getCategory())
{
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."));
- m_context << eth::Instruction::BALANCE;
break;
case Type::Category::CONTRACT:
// call function
diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h
index 3ed7848b..83d7cdc6 100644
--- a/ExpressionCompiler.h
+++ b/ExpressionCompiler.h
@@ -132,6 +132,10 @@ private:
CompilerContext& m_context;
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;
};
diff --git a/Types.cpp b/Types.cpp
index a6b18b10..4ab53bf8 100644
--- a/Types.cpp
+++ b/Types.cpp
@@ -192,7 +192,7 @@ u256 IntegerType::literalValue(Literal const& _literal) const
const MemberList IntegerType::AddressMemberList =
MemberList({{"balance", 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
{
@@ -314,6 +314,7 @@ FunctionType::FunctionType(FunctionDefinition const& _function)
retParams.push_back(var->getType());
swap(params, m_parameterTypes);
swap(retParams, m_returnParameterTypes);
+ m_location = Location::INTERNAL;
}
bool FunctionType::operator==(Type const& _other) const
@@ -347,6 +348,19 @@ string FunctionType::toString() const
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
{
if (_other.getCategory() != getCategory())
diff --git a/Types.h b/Types.h
index 17d9053b..630c9c21 100644
--- a/Types.h
+++ b/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,
/// i.e. it behaves differently in lvalue context and in value context.
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.
virtual MemberList const& getMembers() const { return EmptyMemberList; }
@@ -235,6 +236,7 @@ public:
virtual bool operator==(Type const& _other) const override;
virtual u256 getStorageSize() const override;
virtual bool canLiveOutsideStorage() const override;
+ virtual unsigned getSizeOnStack() const override { return 1; /*@todo*/ }
virtual std::string toString() const override;
virtual MemberList const& getMembers() const override;
@@ -255,10 +257,17 @@ private:
class FunctionType: public Type
{
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; }
explicit FunctionType(FunctionDefinition const& _function);
- FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes):
- m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes) {}
+ FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes,
+ Location _location = Location::INTERNAL):
+ m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes),
+ m_location(_location) {}
TypePointers const& getParameterTypes() const { return m_parameterTypes; }
TypePointers const& getReturnParameterTypes() const { return m_returnParameterTypes; }
@@ -268,10 +277,14 @@ public:
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 bool canLiveOutsideStorage() const override { return false; }
+ virtual unsigned getSizeOnStack() const override;
+
+ Location getLocation() const { return m_location; }
private:
TypePointers m_parameterTypes;
TypePointers m_returnParameterTypes;
+ Location m_location;
};
/**
@@ -310,6 +323,7 @@ public:
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 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 canBeStored() const override { return false; }
virtual bool canLiveOutsideStorage() const override { return true; }
+ virtual unsigned getSizeOnStack() const override { return 0; }
virtual MemberList const& getMembers() const override { return m_members; }
virtual std::string toString() const override;