From e0849f2f3bbb23ebddb37cd770f46266967e789d Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 14 Mar 2017 15:41:23 +0100 Subject: Split external identifier access into resolving and code generation. --- libsolidity/codegen/ContractCompiler.cpp | 152 ++++++++++++++++--------------- 1 file changed, 80 insertions(+), 72 deletions(-) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 6524bd03..a583f8b4 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -522,91 +522,99 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) ErrorList errors; assembly::CodeGenerator codeGen(_inlineAssembly.operations(), errors); unsigned startStackHeight = m_context.stackHeight(); - codeGen.assemble( - m_context.nonConstAssembly(), - [&](assembly::Identifier const& _identifier, eth::Assembly& _assembly, assembly::CodeGenerator::IdentifierContext _context) { - auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); - if (ref == _inlineAssembly.annotation().externalReferences.end()) - return false; - Declaration const* decl = ref->second; - solAssert(!!decl, ""); - if (_context == assembly::CodeGenerator::IdentifierContext::RValue) + assembly::ExternalIdentifierAccess identifierAccess; + identifierAccess.resolve = [&](assembly::Identifier const& _identifier, assembly::IdentifierContext) + { + auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); + if (ref == _inlineAssembly.annotation().externalReferences.end()) + return size_t(-1); + return ref->second.valueSize; + }; + identifierAccess.generateCode = [&](assembly::Identifier const& _identifier, assembly::IdentifierContext _context, eth::Assembly& _assembly) + { + auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); + solAssert(ref != _inlineAssembly.annotation().externalReferences.end(), ""); + Declaration const* decl = ref->second.declaration; + solAssert(!!decl, ""); + if (_context == assembly::IdentifierContext::RValue) + { + solAssert(!!decl->type(), "Type of declaration required but not yet determined."); + if (FunctionDefinition const* functionDef = dynamic_cast(decl)) { - solAssert(!!decl->type(), "Type of declaration required but not yet determined."); - if (FunctionDefinition const* functionDef = dynamic_cast(decl)) + functionDef = &m_context.resolveVirtualFunction(*functionDef); + _assembly.append(m_context.functionEntryLabel(*functionDef).pushTag()); + // If there is a runtime context, we have to merge both labels into the same + // stack slot in case we store it in storage. + if (CompilerContext* rtc = m_context.runtimeContext()) { - functionDef = &m_context.resolveVirtualFunction(*functionDef); - _assembly.append(m_context.functionEntryLabel(*functionDef).pushTag()); - // If there is a runtime context, we have to merge both labels into the same - // stack slot in case we store it in storage. - if (CompilerContext* rtc = m_context.runtimeContext()) - { - _assembly.append(u256(1) << 32); - _assembly.append(Instruction::MUL); - _assembly.append(rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub())); - _assembly.append(Instruction::OR); - } + _assembly.append(u256(1) << 32); + _assembly.append(Instruction::MUL); + _assembly.append(rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub())); + _assembly.append(Instruction::OR); + } + } + else if (auto variable = dynamic_cast(decl)) + { + solAssert(!variable->isConstant(), ""); + if (m_context.isLocalVariable(variable)) + { + int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable); + if (stackDiff < 1 || stackDiff > 16) + BOOST_THROW_EXCEPTION( + CompilerError() << + errinfo_sourceLocation(_inlineAssembly.location()) << + errinfo_comment("Stack too deep, try removing local variables.") + ); + for (unsigned i = 0; i < variable->type()->sizeOnStack(); ++i) + _assembly.append(dupInstruction(stackDiff)); } - else if (auto variable = dynamic_cast(decl)) + else { - solAssert(!variable->isConstant(), ""); - if (m_context.isLocalVariable(variable)) + solAssert(m_context.isStateVariable(variable), "Invalid variable type."); + auto const& location = m_context.storageLocationOfVariable(*variable); + if (!variable->type()->isValueType()) { - int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable); - if (stackDiff < 1 || stackDiff > 16) - BOOST_THROW_EXCEPTION( - CompilerError() << - errinfo_sourceLocation(_inlineAssembly.location()) << - errinfo_comment("Stack too deep, try removing local variables.") - ); - for (unsigned i = 0; i < variable->type()->sizeOnStack(); ++i) - _assembly.append(dupInstruction(stackDiff)); + solAssert(location.second == 0, "Intra-slot offest assumed to be zero."); + _assembly.append(location.first); } else { - solAssert(m_context.isStateVariable(variable), "Invalid variable type."); - auto const& location = m_context.storageLocationOfVariable(*variable); - if (!variable->type()->isValueType()) - { - solAssert(location.second == 0, "Intra-slot offest assumed to be zero."); - _assembly.append(location.first); - } - else - { - _assembly.append(location.first); - _assembly.append(u256(location.second)); - } + _assembly.append(location.first); + _assembly.append(u256(location.second)); } } - else if (auto contract = dynamic_cast(decl)) - { - solAssert(contract->isLibrary(), ""); - _assembly.appendLibraryAddress(contract->fullyQualifiedName()); - } - else - solAssert(false, "Invalid declaration type."); - } else { - // lvalue context - auto variable = dynamic_cast(decl); - solAssert( - !!variable && m_context.isLocalVariable(variable), - "Can only assign to stack variables in inline assembly." + } + else if (auto contract = dynamic_cast(decl)) + { + solAssert(contract->isLibrary(), ""); + _assembly.appendLibraryAddress(contract->fullyQualifiedName()); + } + else + solAssert(false, "Invalid declaration type."); + } else { + // lvalue context + auto variable = dynamic_cast(decl); + solAssert( + !!variable && m_context.isLocalVariable(variable), + "Can only assign to stack variables in inline assembly." + ); + unsigned size = variable->type()->sizeOnStack(); + int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable) - size; + if (stackDiff > 16 || stackDiff < 1) + BOOST_THROW_EXCEPTION( + CompilerError() << + errinfo_sourceLocation(_inlineAssembly.location()) << + errinfo_comment("Stack too deep, try removing local variables.") ); - unsigned size = variable->type()->sizeOnStack(); - int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable) - size; - if (stackDiff > 16 || stackDiff < 1) - BOOST_THROW_EXCEPTION( - CompilerError() << - errinfo_sourceLocation(_inlineAssembly.location()) << - errinfo_comment("Stack too deep, try removing local variables.") - ); - for (unsigned i = 0; i < size; ++i) { - _assembly.append(swapInstruction(stackDiff)); - _assembly.append(Instruction::POP); - } + for (unsigned i = 0; i < size; ++i) { + _assembly.append(swapInstruction(stackDiff)); + _assembly.append(Instruction::POP); } - return true; } + }; + codeGen.assemble( + m_context.nonConstAssembly(), + identifierAccess ); solAssert(Error::containsOnlyWarnings(errors), "Code generation for inline assembly with errors requested."); m_context.setStackOffset(startStackHeight); -- cgit v1.2.3 From 83bf34c571023cb264c56b3bd791a6fd9ebc3bf2 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 22 Mar 2017 19:02:27 +0100 Subject: Review comments and cleanup. --- libsolidity/codegen/ContractCompiler.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index a583f8b4..c035bd1f 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -591,7 +591,9 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } else solAssert(false, "Invalid declaration type."); - } else { + } + else + { // lvalue context auto variable = dynamic_cast(decl); solAssert( @@ -606,7 +608,8 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) errinfo_sourceLocation(_inlineAssembly.location()) << errinfo_comment("Stack too deep, try removing local variables.") ); - for (unsigned i = 0; i < size; ++i) { + for (unsigned i = 0; i < size; ++i) + { _assembly.append(swapInstruction(stackDiff)); _assembly.append(Instruction::POP); } -- cgit v1.2.3 From 34717838da875c5265f005bb92c3349c08063ba5 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 11 Apr 2017 19:24:38 +0200 Subject: Review comments. --- libsolidity/codegen/ContractCompiler.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index c035bd1f..de53f182 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -538,6 +538,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) solAssert(!!decl, ""); if (_context == assembly::IdentifierContext::RValue) { + int const depositBefore = _assembly.deposit(); solAssert(!!decl->type(), "Type of declaration required but not yet determined."); if (FunctionDefinition const* functionDef = dynamic_cast(decl)) { @@ -591,6 +592,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } else solAssert(false, "Invalid declaration type."); + solAssert(_assembly.deposit() - depositBefore == ref->second.valueSize, ""); } else { -- cgit v1.2.3 From dfaab73efe1811848a52a218a207f2d4f007a2d8 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 11 Apr 2017 21:12:17 +0200 Subject: Only allow access to local variables and only if they have a stack size of one. --- libsolidity/codegen/ContractCompiler.cpp | 48 ++++++++++---------------------- 1 file changed, 14 insertions(+), 34 deletions(-) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index de53f182..9bef8a8f 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -557,33 +557,16 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) else if (auto variable = dynamic_cast(decl)) { solAssert(!variable->isConstant(), ""); - if (m_context.isLocalVariable(variable)) - { - int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable); - if (stackDiff < 1 || stackDiff > 16) - BOOST_THROW_EXCEPTION( - CompilerError() << - errinfo_sourceLocation(_inlineAssembly.location()) << - errinfo_comment("Stack too deep, try removing local variables.") - ); - for (unsigned i = 0; i < variable->type()->sizeOnStack(); ++i) - _assembly.append(dupInstruction(stackDiff)); - } - else - { - solAssert(m_context.isStateVariable(variable), "Invalid variable type."); - auto const& location = m_context.storageLocationOfVariable(*variable); - if (!variable->type()->isValueType()) - { - solAssert(location.second == 0, "Intra-slot offest assumed to be zero."); - _assembly.append(location.first); - } - else - { - _assembly.append(location.first); - _assembly.append(u256(location.second)); - } - } + solAssert(m_context.isLocalVariable(variable), ""); + int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable); + if (stackDiff < 1 || stackDiff > 16) + BOOST_THROW_EXCEPTION( + CompilerError() << + errinfo_sourceLocation(_inlineAssembly.location()) << + errinfo_comment("Stack too deep, try removing local variables.") + ); + solAssert(variable->type()->sizeOnStack() == 1, ""); + _assembly.append(dupInstruction(stackDiff)); } else if (auto contract = dynamic_cast(decl)) { @@ -602,19 +585,16 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) !!variable && m_context.isLocalVariable(variable), "Can only assign to stack variables in inline assembly." ); - unsigned size = variable->type()->sizeOnStack(); - int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable) - size; + solAssert(variable->type()->sizeOnStack() == 1, ""); + int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable) - 1; if (stackDiff > 16 || stackDiff < 1) BOOST_THROW_EXCEPTION( CompilerError() << errinfo_sourceLocation(_inlineAssembly.location()) << errinfo_comment("Stack too deep, try removing local variables.") ); - for (unsigned i = 0; i < size; ++i) - { - _assembly.append(swapInstruction(stackDiff)); - _assembly.append(Instruction::POP); - } + _assembly.append(swapInstruction(stackDiff)); + _assembly.append(Instruction::POP); } }; codeGen.assemble( -- cgit v1.2.3 From dfb7d5ebd955d390142241a2abcb95995ef1ba04 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 12 Apr 2017 18:32:25 +0200 Subject: Move analysis out of code generator. --- libsolidity/codegen/ContractCompiler.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 9bef8a8f..5257b1f7 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -520,7 +520,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) { ErrorList errors; - assembly::CodeGenerator codeGen(_inlineAssembly.operations(), errors); + assembly::CodeGenerator codeGen(errors); unsigned startStackHeight = m_context.stackHeight(); assembly::ExternalIdentifierAccess identifierAccess; identifierAccess.resolve = [&](assembly::Identifier const& _identifier, assembly::IdentifierContext) @@ -598,6 +598,8 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } }; codeGen.assemble( + _inlineAssembly.operations(), + _inlineAssembly.annotation().scopes, m_context.nonConstAssembly(), identifierAccess ); -- cgit v1.2.3 From 478f2997ea8b233882d33e693a0e8df176a0c222 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 21 Apr 2017 19:13:46 +0200 Subject: Storage access from inline assembly. --- libsolidity/codegen/ContractCompiler.cpp | 45 +++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 10 deletions(-) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 5257b1f7..7e0be4cb 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -542,6 +542,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) solAssert(!!decl->type(), "Type of declaration required but not yet determined."); if (FunctionDefinition const* functionDef = dynamic_cast(decl)) { + solAssert(!ref->second.isOffset && !ref->second.isSlot, ""); functionDef = &m_context.resolveVirtualFunction(*functionDef); _assembly.append(m_context.functionEntryLabel(*functionDef).pushTag()); // If there is a runtime context, we have to merge both labels into the same @@ -557,19 +558,42 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) else if (auto variable = dynamic_cast(decl)) { solAssert(!variable->isConstant(), ""); - solAssert(m_context.isLocalVariable(variable), ""); - int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable); - if (stackDiff < 1 || stackDiff > 16) - BOOST_THROW_EXCEPTION( - CompilerError() << - errinfo_sourceLocation(_inlineAssembly.location()) << - errinfo_comment("Stack too deep, try removing local variables.") - ); - solAssert(variable->type()->sizeOnStack() == 1, ""); - _assembly.append(dupInstruction(stackDiff)); + if (m_context.isStateVariable(decl)) + { + auto const& location = m_context.storageLocationOfVariable(*decl); + if (ref->second.isSlot) + m_context << location.first; + else if (ref->second.isOffset) + m_context << u256(location.second); + else + solAssert(false, ""); + } + else if (m_context.isLocalVariable(decl)) + { + int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable); + if (ref->second.isSlot || ref->second.isOffset) + { + solAssert(variable->type()->sizeOnStack() == 2, ""); + if (ref->second.isOffset) + stackDiff--; + } + else + solAssert(variable->type()->sizeOnStack() == 1, ""); + if (stackDiff < 1 || stackDiff > 16) + BOOST_THROW_EXCEPTION( + CompilerError() << + errinfo_sourceLocation(_inlineAssembly.location()) << + errinfo_comment("Stack too deep, try removing local variables.") + ); + solAssert(variable->type()->sizeOnStack() == 1, ""); + _assembly.append(dupInstruction(stackDiff)); + } + else + solAssert(false, ""); } else if (auto contract = dynamic_cast(decl)) { + solAssert(!ref->second.isOffset && !ref->second.isSlot, ""); solAssert(contract->isLibrary(), ""); _assembly.appendLibraryAddress(contract->fullyQualifiedName()); } @@ -580,6 +604,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) else { // lvalue context + solAssert(!ref->second.isOffset && !ref->second.isSlot, ""); auto variable = dynamic_cast(decl); solAssert( !!variable && m_context.isLocalVariable(variable), -- cgit v1.2.3 From 978884d9cacb7a31cffb46ee1d9aab5ab39a9e24 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 21 Apr 2017 19:28:52 +0200 Subject: Build fix. --- libsolidity/codegen/ContractCompiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 7e0be4cb..1794cc23 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -599,7 +599,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } else solAssert(false, "Invalid declaration type."); - solAssert(_assembly.deposit() - depositBefore == ref->second.valueSize, ""); + solAssert(_assembly.deposit() - depositBefore == int(ref->second.valueSize), ""); } else { -- cgit v1.2.3 From e841b23bfd57607511d620ed34ef96188bbadec6 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 25 Apr 2017 12:56:34 +0200 Subject: Special case for storage types with offset zero. --- libsolidity/codegen/ContractCompiler.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 1794cc23..6cff9d0b 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -573,9 +573,24 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable); if (ref->second.isSlot || ref->second.isOffset) { - solAssert(variable->type()->sizeOnStack() == 2, ""); - if (ref->second.isOffset) - stackDiff--; + solAssert(variable->type()->dataStoredIn(DataLocation::Storage), ""); + unsigned size = variable->type()->sizeOnStack(); + if (size == 2) + { + // slot plus offset + if (ref->second.isOffset) + stackDiff--; + } + else + { + solAssert(size == 1, ""); + // only slot, offset is zero + if (ref->second.isOffset) + { + _assembly.append(u256(0)); + return; + } + } } else solAssert(variable->type()->sizeOnStack() == 1, ""); -- cgit v1.2.3 From f3ec2ba39e7f4b85d148a7b696ef5af499fbb6fb Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 26 Apr 2017 15:41:08 +0200 Subject: Refactor to combined scope and stack height info. --- libsolidity/codegen/ContractCompiler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 6cff9d0b..34ef13c0 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -637,9 +637,10 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) _assembly.append(Instruction::POP); } }; + solAssert(_inlineAssembly.annotation().analysisInfo, ""); codeGen.assemble( _inlineAssembly.operations(), - _inlineAssembly.annotation().scopes, + *_inlineAssembly.annotation().analysisInfo, m_context.nonConstAssembly(), identifierAccess ); -- cgit v1.2.3