diff options
author | chriseth <c@ethdev.com> | 2015-11-17 22:15:00 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2015-11-26 20:10:12 +0800 |
commit | 879844dd0a9137602373c8f67f283a5895913732 (patch) | |
tree | ea084fcbf268c0a1644f62364c6d9713ed119604 /libsolidity/codegen | |
parent | bf55aa6ae2b9aeec09bb8cf1e3715afd7dd59b7e (diff) | |
download | dexon-solidity-879844dd0a9137602373c8f67f283a5895913732.tar.gz dexon-solidity-879844dd0a9137602373c8f67f283a5895913732.tar.zst dexon-solidity-879844dd0a9137602373c8f67f283a5895913732.zip |
Code generation for creating arrays.
Diffstat (limited to 'libsolidity/codegen')
-rw-r--r-- | libsolidity/codegen/CompilerUtils.cpp | 24 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerUtils.h | 5 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 47 |
3 files changed, 67 insertions, 9 deletions
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 2ebf5b64..357013e6 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -266,6 +266,19 @@ void CompilerUtils::encodeToMemory( popStackSlots(argSize + dynPointers + 1); } +void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type) +{ + auto repeat = m_context.newTag(); + m_context << repeat; + pushZeroValue(*_type.baseType()); + storeInMemoryDynamic(*_type.baseType()); + m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::SWAP1; + m_context << eth::Instruction::SUB << eth::Instruction::SWAP1; + m_context << eth::Instruction::DUP2; + m_context.appendConditionalJumpTo(repeat); + m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; +} + void CompilerUtils::memoryCopy() { // Stack here: size target source @@ -646,15 +659,8 @@ void CompilerUtils::pushZeroValue(Type const& _type) { m_context << arrayType->length() << eth::Instruction::SWAP1; // stack: items_to_do memory_pos - auto repeat = m_context.newTag(); - m_context << repeat; - pushZeroValue(*arrayType->baseType()); - storeInMemoryDynamic(*arrayType->baseType()); - m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::SWAP1; - m_context << eth::Instruction::SUB << eth::Instruction::SWAP1; - m_context << eth::Instruction::DUP2; - m_context.appendConditionalJumpTo(repeat); - m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; + zeroInitialiseMemoryArray(*arrayType); + // stack: updated_memory_pos } } else diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h index 6292e5c7..134afd78 100644 --- a/libsolidity/codegen/CompilerUtils.h +++ b/libsolidity/codegen/CompilerUtils.h @@ -103,6 +103,11 @@ public: bool _encodeAsLibraryTypes = false ); + /// Zero-initialises (the data part of) an already allocated memory array. + /// Stack pre: <length> <memptr> + /// Stack post: <updated_memptr> + void zeroInitialiseMemoryArray(ArrayType const& _type); + /// Uses a CALL to the identity contract to perform a memory-to-memory copy. /// Stack pre: <size> <target> <source> /// Stack post: diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 1a089d63..c94c988b 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -703,6 +703,53 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) StorageByteArrayElement(m_context).storeValue(*type, _functionCall.location(), true); break; } + case Location::ObjectCreation: + { + // Will allocate at the end of memory (MSIZE) and not write at all unless the base + // type is dynamically sized. + ArrayType const& arrayType = dynamic_cast<ArrayType const&>(*_functionCall.annotation().type); + _functionCall.expression().accept(*this); + solAssert(arguments.size() == 1, ""); + + // Fetch requested length. + arguments[0]->accept(*this); + utils().convertType(*arguments[0]->annotation().type, IntegerType(256)); + + // Stack: requested_length + // Allocate at max(MSIZE, freeMemoryPointer) + utils().fetchFreeMemoryPointer(); + m_context << eth::Instruction::DUP1 << eth::Instruction::MSIZE; + m_context << eth::Instruction::LT; + auto initialise = m_context.appendConditionalJump(); + // Free memory pointer does not point to empty memory, use MSIZE. + m_context << eth::Instruction::POP; + m_context << eth::Instruction::MSIZE; + m_context << initialise; + + // Stack: requested_length memptr + m_context << eth::Instruction::SWAP1; + // Stack: memptr requested_length + // store length + m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::MSTORE; + // Stack: memptr requested_length + // update free memory pointer + m_context << eth::Instruction::DUP1 << arrayType.baseType()->memoryHeadSize(); + m_context << eth::Instruction::MUL << u256(32) << eth::Instruction::ADD; + m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; + utils().storeFreeMemoryPointer(); + // Stack: memptr requested_length + + // We only have to initialise if the base type is a not a value type. + if (dynamic_cast<ReferenceType const*>(arrayType.baseType().get())) + { + m_context << eth::Instruction::DUP2 << u256(32) << eth::Instruction::ADD; + utils().zeroInitialiseMemoryArray(arrayType); + m_context << eth::Instruction::POP; + } + else + m_context << eth::Instruction::POP; + break; + } default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid function type.")); } |