From 879844dd0a9137602373c8f67f283a5895913732 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 17 Nov 2015 15:15:00 +0100 Subject: Code generation for creating arrays. --- libsolidity/codegen/CompilerUtils.cpp | 24 +++++++++------ libsolidity/codegen/CompilerUtils.h | 5 ++++ libsolidity/codegen/ExpressionCompiler.cpp | 47 ++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 9 deletions(-) (limited to 'libsolidity/codegen') 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: + /// Stack post: + void zeroInitialiseMemoryArray(ArrayType const& _type); + /// Uses a CALL to the identity contract to perform a memory-to-memory copy. /// Stack pre: /// 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(*_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(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.")); } -- cgit