aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian <c@ethdev.com>2014-12-11 00:15:17 +0800
committerChristian <c@ethdev.com>2014-12-11 00:15:17 +0800
commit373f0da2675f298984f265672d7414a58c061512 (patch)
tree72cf9741f01020410d10d07103d82714a4383bd0
parent130ff85e85de3ea8a9666f84843428a3a09b1aab (diff)
downloaddexon-solidity-373f0da2675f298984f265672d7414a58c061512.tar
dexon-solidity-373f0da2675f298984f265672d7414a58c061512.tar.gz
dexon-solidity-373f0da2675f298984f265672d7414a58c061512.tar.bz2
dexon-solidity-373f0da2675f298984f265672d7414a58c061512.tar.lz
dexon-solidity-373f0da2675f298984f265672d7414a58c061512.tar.xz
dexon-solidity-373f0da2675f298984f265672d7414a58c061512.tar.zst
dexon-solidity-373f0da2675f298984f265672d7414a58c061512.zip
Helper functions to access memory.
-rw-r--r--Compiler.cpp17
-rw-r--r--CompilerUtils.cpp30
-rw-r--r--CompilerUtils.h12
-rw-r--r--ExpressionCompiler.cpp36
4 files changed, 61 insertions, 34 deletions
diff --git a/Compiler.cpp b/Compiler.cpp
index 781f3680..578d63bb 100644
--- a/Compiler.cpp
+++ b/Compiler.cpp
@@ -130,7 +130,6 @@ unsigned Compiler::appendCalldataUnpacker(FunctionDefinition const& _function, b
{
// We do not check the calldata size, everything is zero-padded.
unsigned dataOffset = 1;
- eth::Instruction load = _fromMemory ? eth::Instruction::MLOAD : eth::Instruction::CALLDATALOAD;
//@todo this can be done more efficiently, saving some CALLDATALOAD calls
for (ASTPointer<VariableDeclaration> const& var: _function.getParameters())
@@ -140,14 +139,8 @@ unsigned Compiler::appendCalldataUnpacker(FunctionDefinition const& _function, b
BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(var->getLocation())
<< errinfo_comment("Type " + var->getType()->toString() + " not yet supported."));
- if (numBytes == 32)
- m_context << u256(dataOffset) << load;
- else if (var->getType()->getCategory() == Type::Category::STRING)
- m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::DUP1
- << u256(dataOffset) << load << eth::Instruction::DIV << eth::Instruction::MUL;
- else
- m_context << (u256(1) << ((32 - numBytes) * 8)) << u256(dataOffset)
- << load << eth::Instruction::DIV;
+ bool leftAligned = var->getType()->getCategory() == Type::Category::STRING;
+ CompilerUtils(m_context).loadFromMemory(dataOffset, numBytes, leftAligned, !_fromMemory);
dataOffset += numBytes;
}
return dataOffset;
@@ -168,10 +161,8 @@ void Compiler::appendReturnValuePacker(FunctionDefinition const& _function)
<< errinfo_sourceLocation(parameters[i]->getLocation())
<< errinfo_comment("Type " + paramType.toString() + " not yet supported."));
CompilerUtils(m_context).copyToStackTop(stackDepth, paramType);
- if (numBytes != 32)
- if (paramType.getCategory() != Type::Category::STRING)
- m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL;
- m_context << u256(dataOffset) << eth::Instruction::MSTORE;
+ bool const leftAligned = paramType.getCategory() == Type::Category::STRING;
+ CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned);
stackDepth -= paramType.getSizeOnStack();
dataOffset += numBytes;
}
diff --git a/CompilerUtils.cpp b/CompilerUtils.cpp
index d4dfbe3c..0ee4a53c 100644
--- a/CompilerUtils.cpp
+++ b/CompilerUtils.cpp
@@ -31,6 +31,36 @@ namespace dev
namespace solidity
{
+void CompilerUtils::loadFromMemory(unsigned _offset, unsigned _bytes, bool _leftAligned, bool _fromCalldata)
+{
+ eth::Instruction load = _fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD;
+ if (asserts(0 < _bytes && _bytes <= 32))
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Memory load of 0 or more than 32 bytes requested."));
+ if (_bytes == 32)
+ m_context << u256(_offset) << load;
+ else
+ {
+ // load data and add leading or trailing zeros by dividing/multiplying depending on alignment
+ u256 shiftFactor = u256(1) << ((32 - _bytes) * 8);
+ m_context << shiftFactor;
+ if (_leftAligned)
+ m_context << eth::Instruction::DUP1;
+ m_context << u256(_offset) << load << eth::Instruction::DIV;
+ if (_leftAligned)
+ m_context << eth::Instruction::MUL;
+ }
+}
+
+void CompilerUtils::storeInMemory(unsigned _offset, unsigned _bytes, bool _leftAligned)
+{
+ if (asserts(0 < _bytes && _bytes <= 32))
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Memory store of 0 or more than 32 bytes requested."));
+ if (_bytes != 32 && !_leftAligned)
+ // shift the value accordingly before storing
+ m_context << (u256(1) << ((32 - _bytes) * 8)) << eth::Instruction::MUL;
+ m_context << u256(_offset) << eth::Instruction::MSTORE;
+}
+
void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable)
{
unsigned const stackPosition = m_context.baseToCurrentStackOffset(m_context.getBaseStackOffsetOfVariable(_variable));
diff --git a/CompilerUtils.h b/CompilerUtils.h
index 4da53375..928f0e2d 100644
--- a/CompilerUtils.h
+++ b/CompilerUtils.h
@@ -35,6 +35,18 @@ class CompilerUtils
public:
CompilerUtils(CompilerContext& _context): m_context(_context) {}
+ /// Loads data from memory to the stack.
+ /// @param _offset offset in memory (or calldata)
+ /// @param _bytes number of bytes to load
+ /// @param _leftAligned if true, store left aligned on stack (otherwise right aligned)
+ /// @param _fromCalldata if true, load from calldata, not from memory
+ void loadFromMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false, bool _fromCalldata = false);
+ /// Stores data from stack in memory.
+ /// @param _offset offset in memory
+ /// @param _bytes number of bytes to store
+ /// @param _leftAligned if true, data is left aligned on stack (otherwise right aligned)
+ void storeInMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false);
+
/// Moves the value that is at the top of the stack to a stack variable.
void moveToStackVariable(VariableDeclaration const& _variable);
/// Copies a variable of type @a _type from a stack depth of @a _stackDepth to the top of the stack.
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp
index 5e688f6b..d71d98cd 100644
--- a/ExpressionCompiler.cpp
+++ b/ExpressionCompiler.cpp
@@ -225,15 +225,14 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(arguments[i]->getLocation())
<< errinfo_comment("Type " + type.toString() + " not yet supported."));
- if (numBytes != 32)
- if (type.getCategory() != Type::Category::STRING)
- m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL;
- m_context << u256(dataOffset) << eth::Instruction::MSTORE;
+ 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
- unsigned retSize = function.getReturnParameterTypes().empty() ? 0
- : function.getReturnParameterTypes().front()->getCalldataEncodedSize();
+ 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
@@ -241,17 +240,10 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
<< u256(25) << eth::Instruction::GAS << eth::Instruction::SUB
<< eth::Instruction::CALL
<< eth::Instruction::POP; // @todo do not ignore failure indicator
- if (retSize == 32)
- m_context << u256(0) << eth::Instruction::MLOAD;
- else if (retSize > 0)
+ if (retSize > 0)
{
- if (function.getReturnParameterTypes().front()->getCategory() == Type::Category::STRING)
- m_context << (u256(1) << ((32 - retSize) * 8)) << eth::Instruction::DUP1
- << u256(0) << eth::Instruction::MLOAD
- << eth::Instruction::DIV << eth::Instruction::MUL;
- else
- m_context << (u256(1) << ((32 - retSize) * 8))
- << u256(0) << eth::Instruction::MLOAD << eth::Instruction::DIV;
+ bool const leftAligned = firstType->getCategory() == Type::Category::STRING;
+ CompilerUtils(m_context).loadFromMemory(0, retSize, leftAligned);
}
break;
}
@@ -275,7 +267,8 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
arguments.front()->accept(*this);
appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true);
// @todo move this once we actually use memory
- m_context << u256(0) << eth::Instruction::MSTORE << u256(32) << u256(0) << eth::Instruction::SHA3;
+ CompilerUtils(m_context).storeInMemory(0);
+ m_context << u256(32) << u256(0) << eth::Instruction::SHA3;
break;
case Location::ECRECOVER:
case Location::SHA256:
@@ -291,13 +284,13 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
arguments[i]->accept(*this);
appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i], true);
// @todo move this once we actually use memory
- m_context << u256(i * 32) << eth::Instruction::MSTORE;
+ 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
- << u256(0) << eth::Instruction::MLOAD;
+ << eth::Instruction::POP;
+ CompilerUtils(m_context).loadFromMemory(0);
break;
}
default:
@@ -381,7 +374,8 @@ bool ExpressionCompiler::visit(IndexAccess& _indexAccess)
*dynamic_cast<MappingType const&>(*_indexAccess.getBaseExpression().getType()).getKeyType(),
true);
// @todo move this once we actually use memory
- m_context << u256(32) << eth::Instruction::MSTORE << u256(0) << eth::Instruction::MSTORE;
+ CompilerUtils(m_context).storeInMemory(0);
+ CompilerUtils(m_context).storeInMemory(32);
m_context << u256(64) << u256(0) << eth::Instruction::SHA3;
m_currentLValue = LValue(m_context, LValue::STORAGE, *_indexAccess.getType());