aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/codegen')
-rw-r--r--libsolidity/codegen/Compiler.cpp18
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp29
-rw-r--r--libsolidity/codegen/CompilerUtils.h6
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp45
4 files changed, 79 insertions, 19 deletions
diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp
index f1d95980..18803b71 100644
--- a/libsolidity/codegen/Compiler.cpp
+++ b/libsolidity/codegen/Compiler.cpp
@@ -305,11 +305,19 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
// @todo If base type is an array or struct, it is still calldata-style encoded, so
// we would have to convert it like below.
solAssert(arrayType.location() == DataLocation::Memory, "");
- // compute data pointer
- m_context << eth::Instruction::DUP1 << eth::Instruction::MLOAD;
- m_context << eth::Instruction::DUP3 << eth::Instruction::ADD;
- m_context << eth::Instruction::SWAP2 << eth::Instruction::SWAP1;
- m_context << u256(0x20) << eth::Instruction::ADD;
+ if (arrayType.isDynamicallySized())
+ {
+ // compute data pointer
+ m_context << eth::Instruction::DUP1 << eth::Instruction::MLOAD;
+ m_context << eth::Instruction::DUP3 << eth::Instruction::ADD;
+ m_context << eth::Instruction::SWAP2 << eth::Instruction::SWAP1;
+ m_context << u256(0x20) << eth::Instruction::ADD;
+ }
+ else
+ {
+ m_context << eth::Instruction::DUP1;
+ m_context << u256(arrayType.calldataEncodedSize(true)) << eth::Instruction::ADD;
+ }
}
else
{
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index b57f5b29..bd0857f6 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -695,18 +695,31 @@ void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize)
void CompilerUtils::moveToStackTop(unsigned _stackDepth, unsigned _itemSize)
{
- solAssert(_stackDepth <= 15, "Stack too deep, try removing local variables.");
- for (unsigned j = 0; j < _itemSize; ++j)
- for (unsigned i = 0; i < _stackDepth + _itemSize - 1; ++i)
- m_context << eth::swapInstruction(1 + i);
+ moveIntoStack(_itemSize, _stackDepth);
}
void CompilerUtils::moveIntoStack(unsigned _stackDepth, unsigned _itemSize)
{
- solAssert(_stackDepth <= 16, "Stack too deep, try removing local variables.");
- for (unsigned j = 0; j < _itemSize; ++j)
- for (unsigned i = _stackDepth; i > 0; --i)
- m_context << eth::swapInstruction(i + _itemSize - 1);
+ if (_stackDepth <= _itemSize)
+ for (unsigned i = 0; i < _stackDepth; ++i)
+ rotateStackDown(_stackDepth + _itemSize);
+ else
+ for (unsigned i = 0; i < _itemSize; ++i)
+ rotateStackUp(_stackDepth + _itemSize);
+}
+
+void CompilerUtils::rotateStackUp(unsigned _items)
+{
+ solAssert(_items - 1 <= 16, "Stack too deep, try removing local variables.");
+ for (unsigned i = 1; i < _items; ++i)
+ m_context << eth::swapInstruction(_items - i);
+}
+
+void CompilerUtils::rotateStackDown(unsigned _items)
+{
+ solAssert(_items - 1 <= 16, "Stack too deep, try removing local variables.");
+ for (unsigned i = 1; i < _items; ++i)
+ m_context << eth::swapInstruction(i);
}
void CompilerUtils::popStackElement(Type const& _type)
diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h
index 134afd78..55254013 100644
--- a/libsolidity/codegen/CompilerUtils.h
+++ b/libsolidity/codegen/CompilerUtils.h
@@ -134,6 +134,12 @@ public:
void moveToStackTop(unsigned _stackDepth, unsigned _itemSize = 1);
/// Moves @a _itemSize elements past @a _stackDepth other stack elements
void moveIntoStack(unsigned _stackDepth, unsigned _itemSize = 1);
+ /// Rotates the topmost @a _items items on the stack, such that the previously topmost element
+ /// is bottom-most.
+ void rotateStackUp(unsigned _items);
+ /// Rotates the topmost @a _items items on the stack, such that the previously bottom-most element
+ /// is now topmost.
+ void rotateStackDown(unsigned _items);
/// Removes the current value from the top of the stack.
void popStackElement(Type const& _type);
/// Removes element from the top of the stack _amount times.
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 6c288ae7..a090a28c 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -422,6 +422,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
else
{
FunctionType const& function = *functionType;
+ if (function.bound())
+ // Only callcode functions can be bound, this might be lifted later.
+ solAssert(function.location() == Location::CallCode, "");
switch (function.location())
{
case Location::Internal:
@@ -535,7 +538,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{}
);
break;
- case Location::Suicide:
+ case Location::Selfdestruct:
arguments.front()->accept(*this);
utils().convertType(*arguments.front()->annotation().type, *function.parameterTypes().front(), true);
m_context << eth::Instruction::SUICIDE;
@@ -672,7 +675,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
_functionCall.expression().accept(*this);
solAssert(function.parameterTypes().size() == 1, "");
solAssert(!!function.parameterTypes()[0], "");
- TypePointer const& paramType = function.parameterTypes()[0];
+ TypePointer paramType = function.parameterTypes()[0];
shared_ptr<ArrayType> arrayType =
function.location() == Location::ArrayPush ?
make_shared<ArrayType>(DataLocation::Storage, paramType) :
@@ -766,7 +769,26 @@ bool ExpressionCompiler::visit(NewExpression const&)
void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
{
CompilerContext::LocationSetter locationSetter(m_context, _memberAccess);
+
+ // Check whether the member is a bound function.
ASTString const& member = _memberAccess.memberName();
+ if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
+ if (funType->bound())
+ {
+ utils().convertType(
+ *_memberAccess.expression().annotation().type,
+ *funType->selfType(),
+ true
+ );
+ auto contract = dynamic_cast<ContractDefinition const*>(funType->declaration().scope());
+ solAssert(contract && contract->isLibrary(), "");
+ //@TODO library name might not be unique
+ m_context.appendLibraryAddress(contract->name());
+ m_context << funType->externalIdentifier();
+ utils().moveIntoStack(funType->selfType()->sizeOnStack(), 2);
+ return;
+ }
+
switch (_memberAccess.expression().annotation().type->category())
{
case Type::Category::Contract:
@@ -1239,7 +1261,6 @@ void ExpressionCompiler::appendExternalFunctionCall(
vector<ASTPointer<Expression const>> const& _arguments
)
{
- eth::EVMSchedule schedule;// TODO: Make relevant to current suppose context.
solAssert(
_functionType.takesArbitraryParameters() ||
_arguments.size() == _functionType.parameterTypes().size(), ""
@@ -1249,15 +1270,20 @@ void ExpressionCompiler::appendExternalFunctionCall(
// <stack top>
// value [if _functionType.valueSet()]
// gas [if _functionType.gasSet()]
+ // self object [if bound - moved to top right away]
// function identifier [unless bare]
// contract address
+ unsigned selfSize = _functionType.bound() ? _functionType.selfType()->sizeOnStack() : 0;
unsigned gasValueSize = (_functionType.gasSet() ? 1 : 0) + (_functionType.valueSet() ? 1 : 0);
-
- unsigned contractStackPos = m_context.currentToBaseStackOffset(1 + gasValueSize + (_functionType.isBareCall() ? 0 : 1));
+ unsigned contractStackPos = m_context.currentToBaseStackOffset(1 + gasValueSize + selfSize + (_functionType.isBareCall() ? 0 : 1));
unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize);
unsigned valueStackPos = m_context.currentToBaseStackOffset(1);
+ // move self object to top
+ if (_functionType.bound())
+ utils().moveToStackTop(gasValueSize, _functionType.selfType()->sizeOnStack());
+
using FunctionKind = FunctionType::Location;
FunctionKind funKind = _functionType.location();
bool returnSuccessCondition = funKind == FunctionKind::Bare || funKind == FunctionKind::BareCallCode;
@@ -1275,6 +1301,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
// Evaluate arguments.
TypePointers argumentTypes;
+ TypePointers parameterTypes = _functionType.parameterTypes();
bool manualFunctionId =
(funKind == FunctionKind::Bare || funKind == FunctionKind::BareCallCode) &&
!_arguments.empty() &&
@@ -1295,6 +1322,11 @@ void ExpressionCompiler::appendExternalFunctionCall(
gasStackPos++;
valueStackPos++;
}
+ if (_functionType.bound())
+ {
+ argumentTypes.push_back(_functionType.selfType());
+ parameterTypes.insert(parameterTypes.begin(), _functionType.selfType());
+ }
for (size_t i = manualFunctionId ? 1 : 0; i < _arguments.size(); ++i)
{
_arguments[i]->accept(*this);
@@ -1313,7 +1345,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
// pointer on the stack).
utils().encodeToMemory(
argumentTypes,
- _functionType.parameterTypes(),
+ parameterTypes,
_functionType.padArguments(),
_functionType.takesArbitraryParameters(),
isCallCode
@@ -1346,6 +1378,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos));
else
{
+ eth::EVMSchedule schedule;// TODO: Make relevant to current suppose context.
// send all gas except the amount needed to execute "SUB" and "CALL"
// @todo this retains too much gas for now, needs to be fine-tuned.
u256 gasNeededByCaller = schedule.callGas + 10;