Browse Source

loadFromMemoryDynamic

cl-refactor
Christian 10 years ago
parent
commit
9111abbc8a
  1. 61
      libsolidity/CompilerUtils.cpp
  2. 9
      libsolidity/CompilerUtils.h
  3. 10
      test/SolidityCompiler.cpp

61
libsolidity/CompilerUtils.cpp

@ -37,32 +37,22 @@ unsigned CompilerUtils::loadFromMemory(unsigned _offset, Type const& _type,
bool _fromCalldata, bool _padToWordBoundaries) bool _fromCalldata, bool _padToWordBoundaries)
{ {
solAssert(_type.getCategory() != Type::Category::ByteArray, "Unable to statically load dynamic type."); solAssert(_type.getCategory() != Type::Category::ByteArray, "Unable to statically load dynamic type.");
unsigned _encodedSize = _type.getCalldataEncodedSize(); m_context << u256(_offset);
unsigned numBytes = _padToWordBoundaries ? getPaddedSize(_encodedSize) : _encodedSize; return loadFromMemoryHelper(_type, _fromCalldata, _padToWordBoundaries);
bool leftAligned = _type.getCategory() == Type::Category::String; }
if (numBytes == 0)
m_context << u256(0); void CompilerUtils::loadFromMemoryDynamic(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
else {
{ solAssert(_type.getCategory() != Type::Category::ByteArray, "Byte arrays not yet implemented.");
eth::Instruction load = _fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD;
solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested.");
if (numBytes == 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 - numBytes) * 8);
m_context << shiftFactor;
if (leftAligned)
m_context << eth::Instruction::DUP1; m_context << eth::Instruction::DUP1;
m_context << u256(_offset) << load << eth::Instruction::DIV; unsigned numBytes = loadFromMemoryHelper(_type, _fromCalldata, _padToWordBoundaries);
if (leftAligned) // update memory counter
m_context << eth::Instruction::MUL; for (unsigned i = 0; i < _type.getSizeOnStack(); ++i)
} m_context << eth::swapInstruction(1 + i);
} m_context << u256(numBytes) << eth::Instruction::ADD;
return numBytes;
} }
unsigned CompilerUtils::storeInMemory(unsigned _offset, Type const& _type, bool _padToWordBoundaries) unsigned CompilerUtils::storeInMemory(unsigned _offset, Type const& _type, bool _padToWordBoundaries)
{ {
solAssert(_type.getCategory() != Type::Category::ByteArray, "Unable to statically store dynamic type."); solAssert(_type.getCategory() != Type::Category::ByteArray, "Unable to statically store dynamic type.");
@ -121,6 +111,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries); unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries);
if (numBytes > 0) if (numBytes > 0)
{ {
solAssert(_type.getSizeOnStack() == 1, "Memory store of types with stack size != 1 not implemented.");
m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE; m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE;
m_context << u256(numBytes) << eth::Instruction::ADD; m_context << u256(numBytes) << eth::Instruction::ADD;
} }
@ -290,6 +281,30 @@ void CompilerUtils::copyByteArrayToStorage(ByteArrayType const& _targetType,
} }
} }
unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
{
unsigned _encodedSize = _type.getCalldataEncodedSize();
unsigned numBytes = _padToWordBoundaries ? getPaddedSize(_encodedSize) : _encodedSize;
bool leftAligned = _type.getCategory() == Type::Category::String;
if (numBytes == 0)
m_context << eth::Instruction::POP << u256(0);
else
{
solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested.");
m_context << (_fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD);
if (numBytes != 32)
{
// add leading or trailing zeros by dividing/multiplying depending on alignment
u256 shiftFactor = u256(1) << ((32 - numBytes) * 8);
m_context << shiftFactor << eth::Instruction::SWAP1 << eth::Instruction::DIV;
if (leftAligned)
m_context << shiftFactor << eth::Instruction::MUL;
}
}
return numBytes;
}
void CompilerUtils::clearByteArray(ByteArrayType const& _type) const void CompilerUtils::clearByteArray(ByteArrayType const& _type) const
{ {
solAssert(_type.getLocation() == ByteArrayType::Location::Storage, ""); solAssert(_type.getLocation() == ByteArrayType::Location::Storage, "");

9
libsolidity/CompilerUtils.h

@ -40,10 +40,13 @@ public:
/// @param _type data type to load /// @param _type data type to load
/// @param _fromCalldata if true, load from calldata, not from memory /// @param _fromCalldata if true, load from calldata, not from memory
/// @param _padToWordBoundaries if true, assume the data is padded to word (32 byte) boundaries /// @param _padToWordBoundaries if true, assume the data is padded to word (32 byte) boundaries
/// @returns the number of bytes consumed in memory (can be different from _bytes if /// @returns the number of bytes consumed in memory.
/// _padToWordBoundaries is true)
unsigned loadFromMemory(unsigned _offset, Type const& _type = IntegerType(256), unsigned loadFromMemory(unsigned _offset, Type const& _type = IntegerType(256),
bool _fromCalldata = false, bool _padToWordBoundaries = false); bool _fromCalldata = false, bool _padToWordBoundaries = false);
/// Dynamic version of @see loadFromMemory, expects the memory offset on the stack.
/// Stack pre: memory_offset
/// Stack post: value... (memory_offset+length)
void loadFromMemoryDynamic(Type const& _type, bool _fromCalldata = false, bool _padToWordBoundaries = true);
/// Stores data from stack in memory. /// Stores data from stack in memory.
/// @param _offset offset in memory /// @param _offset offset in memory
/// @param _type type of the data on the stack /// @param _type type of the data on the stack
@ -92,6 +95,8 @@ public:
private: private:
/// Prepares the given type for storing in memory by shifting it if necessary. /// Prepares the given type for storing in memory by shifting it if necessary.
unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const; unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const;
/// Loads type from memory assuming memory offset is on stack top.
unsigned loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries);
/// Appends a loop that clears a sequence of storage slots (excluding end). /// Appends a loop that clears a sequence of storage slots (excluding end).
/// Stack pre: end_ref start_ref /// Stack pre: end_ref start_ref
/// Stack post: end_ref /// Stack post: end_ref

10
test/SolidityCompiler.cpp

@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned boilerplateSize = 69; unsigned boilerplateSize = 70;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x0, // initialize local variable x byte(Instruction::PUSH1), 0x0, // initialize local variable x
byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0x2,
@ -114,8 +114,8 @@ BOOST_AUTO_TEST_CASE(ifStatement)
" function f() { bool x; if (x) 77; else if (!x) 78; else 79; }" " function f() { bool x; if (x) 77; else if (!x) 78; else 79; }"
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned shift = 56; unsigned shift = 57;
unsigned boilerplateSize = 69; unsigned boilerplateSize = 70;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x0, byte(Instruction::PUSH1), 0x0,
byte(Instruction::DUP1), byte(Instruction::DUP1),
@ -155,8 +155,8 @@ BOOST_AUTO_TEST_CASE(loops)
" function f() { while(true){1;break;2;continue;3;return;4;} }" " function f() { while(true){1;break;2;continue;3;return;4;} }"
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned shift = 56; unsigned shift = 57;
unsigned boilerplateSize = 69; unsigned boilerplateSize = 70;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x1,

Loading…
Cancel
Save