diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 81d3409ea..fe0eeb1cd 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -556,20 +556,24 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) arg->accept(*this); argumentTypes.push_back(arg->annotation().type); } - ContractDefinition const& contract = - dynamic_cast(*function.returnParameterTypes().front()).contractDefinition(); - // copy the contract's code into memory - eth::Assembly const& assembly = m_context.compiledContract(contract); - utils().fetchFreeMemoryPointer(); - // TODO we create a copy here, which is actually what we want. - // This should be revisited at the point where we fix - // https://github.com/ethereum/solidity/issues/1092 - // pushes size - auto subroutine = m_context.addSubroutine(make_shared(assembly)); - m_context << Instruction::DUP1 << subroutine; - m_context << Instruction::DUP4 << Instruction::CODECOPY; - - m_context << Instruction::ADD; + ContractDefinition const* contract = + &dynamic_cast(*function.returnParameterTypes().front()).contractDefinition(); + m_context.callLowLevelFunction( + "$copyContractCreationCodeToMemory_" + contract->type()->identifier(), + 0, + 1, + [contract](CompilerContext& _context) + { + // copy the contract's code into memory + eth::Assembly const& assembly = _context.compiledContract(*contract); + CompilerUtils(_context).fetchFreeMemoryPointer(); + // pushes size + auto subroutine = _context.addSubroutine(make_shared(assembly)); + _context << Instruction::DUP1 << subroutine; + _context << Instruction::DUP4 << Instruction::CODECOPY; + _context << Instruction::ADD; + } + ); utils().encodeToMemory(argumentTypes, function.parameterTypes()); // now on stack: memory_end_ptr // need: size, offset, endowment diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index e8e5ced1a..646017fbf 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -8992,6 +8992,35 @@ BOOST_AUTO_TEST_CASE(contracts_separated_with_comment) compileAndRun(sourceCode, 0, "C2"); } +BOOST_AUTO_TEST_CASE(include_creation_bytecode_only_once) +{ + char const* sourceCode = R"( + contract D { + bytes a = hex"1237651237125387136581271652831736512837126583171583712358126123765123712538713658127165283173651283712658317158371235812612376512371253871365812716528317365128371265831715837123581261237651237125387136581271652831736512837126583171583712358126"; + bytes b = hex"1237651237125327136581271252831736512837126583171383712358126123765125712538713658127165253173651283712658357158371235812612376512371a5387136581271652a317365128371265a317158371235812612a765123712538a13658127165a83173651283712a58317158371235a126"; + function D(uint) {} + } + contract Double { + function f() { + new D(2); + } + function g() { + new D(3); + } + } + contract Single { + function f() { + new D(2); + } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK_LE( + double(m_compiler.object("Double").bytecode.size()), + 1.1 * double(m_compiler.object("Single").bytecode.size()) + ); +} + BOOST_AUTO_TEST_CASE(recursive_structs) { char const* sourceCode = R"(