From e2b21e1c9611fd94f8e7b91b0ecbb0ec39145758 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 28 Apr 2017 18:15:18 +0200 Subject: Refactor to abstract assembly to JULIA. --- libsolidity/codegen/ContractCompiler.cpp | 36 ++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 34ef13c0..41940e1a 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -530,7 +530,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) return size_t(-1); return ref->second.valueSize; }; - identifierAccess.generateCode = [&](assembly::Identifier const& _identifier, assembly::IdentifierContext _context, eth::Assembly& _assembly) + identifierAccess.generateCode = [&](assembly::Identifier const& _identifier, assembly::IdentifierContext _context, julia::AbstractAssembly& _assembly) { auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); solAssert(ref != _inlineAssembly.annotation().externalReferences.end(), ""); @@ -538,21 +538,25 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) solAssert(!!decl, ""); if (_context == assembly::IdentifierContext::RValue) { - int const depositBefore = _assembly.deposit(); + int const depositBefore = _assembly.stackHeight(); 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()); + auto functionEntryLabel = m_context.functionEntryLabel(*functionDef).pushTag(); + solAssert(functionEntryLabel.data() <= std::numeric_limits::max(), ""); + _assembly.appendLabelReference(size_t(functionEntryLabel.data())); // 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.appendConstant(u256(1) << 32); + _assembly.appendInstruction(Instruction::MUL); + auto runtimeEntryLabel = rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub()); + solAssert(runtimeEntryLabel.data() <= std::numeric_limits::max(), ""); + _assembly.appendLabelReference(size_t(runtimeEntryLabel.data())); + _assembly.appendInstruction(Instruction::OR); } } else if (auto variable = dynamic_cast(decl)) @@ -570,7 +574,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } else if (m_context.isLocalVariable(decl)) { - int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable); + int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable); if (ref->second.isSlot || ref->second.isOffset) { solAssert(variable->type()->dataStoredIn(DataLocation::Storage), ""); @@ -587,7 +591,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) // only slot, offset is zero if (ref->second.isOffset) { - _assembly.append(u256(0)); + _assembly.appendConstant(u256(0)); return; } } @@ -601,7 +605,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) errinfo_comment("Stack too deep, try removing local variables.") ); solAssert(variable->type()->sizeOnStack() == 1, ""); - _assembly.append(dupInstruction(stackDiff)); + _assembly.appendInstruction(dupInstruction(stackDiff)); } else solAssert(false, ""); @@ -610,11 +614,11 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) { solAssert(!ref->second.isOffset && !ref->second.isSlot, ""); solAssert(contract->isLibrary(), ""); - _assembly.appendLibraryAddress(contract->fullyQualifiedName()); + _assembly.appendLinkerSymbol(contract->fullyQualifiedName()); } else solAssert(false, "Invalid declaration type."); - solAssert(_assembly.deposit() - depositBefore == int(ref->second.valueSize), ""); + solAssert(_assembly.stackHeight() - depositBefore == int(ref->second.valueSize), ""); } else { @@ -626,15 +630,15 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) "Can only assign to stack variables in inline assembly." ); solAssert(variable->type()->sizeOnStack() == 1, ""); - int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable) - 1; + int stackDiff = _assembly.stackHeight() - 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.") + errinfo_comment("Stack too deep(" + to_string(stackDiff) + "), try removing local variables.") ); - _assembly.append(swapInstruction(stackDiff)); - _assembly.append(Instruction::POP); + _assembly.appendInstruction(swapInstruction(stackDiff)); + _assembly.appendInstruction(Instruction::POP); } }; solAssert(_inlineAssembly.annotation().analysisInfo, ""); -- cgit v1.2.3 From 261731f7eea48902983c55163d377e26bbca07da Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 23 May 2017 19:21:14 +0200 Subject: Adapt EVM codegen to new namespace. --- libsolidity/codegen/ContractCompiler.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 41940e1a..e79bb6dc 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -522,21 +522,21 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) ErrorList errors; assembly::CodeGenerator codeGen(errors); unsigned startStackHeight = m_context.stackHeight(); - assembly::ExternalIdentifierAccess identifierAccess; - identifierAccess.resolve = [&](assembly::Identifier const& _identifier, assembly::IdentifierContext) + julia::ExternalIdentifierAccess identifierAccess; + identifierAccess.resolve = [&](assembly::Identifier const& _identifier, julia::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, julia::AbstractAssembly& _assembly) + identifierAccess.generateCode = [&](assembly::Identifier const& _identifier, julia::IdentifierContext _context, julia::AbstractAssembly& _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) + if (_context == julia::IdentifierContext::RValue) { int const depositBefore = _assembly.stackHeight(); solAssert(!!decl->type(), "Type of declaration required but not yet determined."); -- cgit v1.2.3 From 89b60ffbd4c2dde26fa5e9f1d750729b5c89373e Mon Sep 17 00:00:00 2001 From: Rhett Aultman Date: Thu, 11 May 2017 06:26:35 -0700 Subject: Refactor error reporting This commit introduces ErrorReporter, a utility class which consolidates all of the error logging functionality into a common set of functions. It also replaces all direct interactions with an ErrorList with calls to an ErrorReporter. This commit resolves issue #2209 --- libsolidity/codegen/ContractCompiler.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index e79bb6dc..1fc06333 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -520,7 +520,8 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) { ErrorList errors; - assembly::CodeGenerator codeGen(errors); + ErrorReporter errorReporter(errors); + assembly::CodeGenerator codeGen(errorReporter); unsigned startStackHeight = m_context.stackHeight(); julia::ExternalIdentifierAccess identifierAccess; identifierAccess.resolve = [&](assembly::Identifier const& _identifier, julia::IdentifierContext) @@ -648,7 +649,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) m_context.nonConstAssembly(), identifierAccess ); - solAssert(Error::containsOnlyWarnings(errors), "Code generation for inline assembly with errors requested."); + solAssert(Error::containsOnlyWarnings(errorReporter.errors()), "Code generation for inline assembly with errors requested."); m_context.setStackOffset(startStackHeight); return false; } -- cgit v1.2.3 From 97cc968a133247e729ed1d189d35ef2b7b53b3d4 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 24 May 2017 18:34:19 +0200 Subject: Initial EVM1.5 assembly implementation. --- libsolidity/codegen/ContractCompiler.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 1fc06333..03926350 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -21,15 +21,20 @@ */ #include -#include -#include -#include -#include -#include #include #include +#include #include #include + +#include +#include +#include + +#include + +#include + using namespace std; using namespace dev; using namespace dev::solidity; @@ -524,7 +529,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) assembly::CodeGenerator codeGen(errorReporter); unsigned startStackHeight = m_context.stackHeight(); julia::ExternalIdentifierAccess identifierAccess; - identifierAccess.resolve = [&](assembly::Identifier const& _identifier, julia::IdentifierContext) + identifierAccess.resolve = [&](assembly::Identifier const& _identifier, julia::IdentifierContext, bool) { auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); if (ref == _inlineAssembly.annotation().externalReferences.end()) -- cgit v1.2.3 From ef3d5874fefa6a86a30d4afdcfd269d599edda5d Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 6 Jun 2017 15:37:43 +0200 Subject: Remove error reporter from code generation phase. --- libsolidity/codegen/ContractCompiler.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 03926350..dc090634 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -524,9 +524,6 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) { - ErrorList errors; - ErrorReporter errorReporter(errors); - assembly::CodeGenerator codeGen(errorReporter); unsigned startStackHeight = m_context.stackHeight(); julia::ExternalIdentifierAccess identifierAccess; identifierAccess.resolve = [&](assembly::Identifier const& _identifier, julia::IdentifierContext, bool) @@ -648,13 +645,12 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } }; solAssert(_inlineAssembly.annotation().analysisInfo, ""); - codeGen.assemble( + assembly::CodeGenerator::assemble( _inlineAssembly.operations(), *_inlineAssembly.annotation().analysisInfo, m_context.nonConstAssembly(), identifierAccess ); - solAssert(Error::containsOnlyWarnings(errorReporter.errors()), "Code generation for inline assembly with errors requested."); m_context.setStackOffset(startStackHeight); return false; } -- cgit v1.2.3 From 831ed083875b73faf91f9d3335e2599540366712 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 24 May 2017 11:47:43 +0200 Subject: Change invalid opcode to revert for input validation. --- libsolidity/codegen/ContractCompiler.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index dc090634..ace82ad4 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -111,7 +111,7 @@ void ContractCompiler::appendCallValueCheck() { // Throw if function is not payable but call contained ether. m_context << Instruction::CALLVALUE; - m_context.appendConditionalInvalid(); + m_context.appendConditionalRevert(); } void ContractCompiler::appendInitAndConstructorCode(ContractDefinition const& _contract) @@ -276,7 +276,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac appendReturnValuePacker(FunctionType(*fallback).returnParameterTypes(), _contract.isLibrary()); } else - m_context.appendInvalid(); + m_context.appendRevert(); for (auto const& it: interfaceFunctions) { @@ -368,7 +368,7 @@ void ContractCompiler::appendCalldataUnpacker(TypePointers const& _typeParameter // copy to memory // move calldata type up again CompilerUtils(m_context).moveIntoStack(calldataType->sizeOnStack()); - CompilerUtils(m_context).convertType(*calldataType, arrayType); + CompilerUtils(m_context).convertType(*calldataType, arrayType, false, false, true); // fetch next pointer again CompilerUtils(m_context).moveToStackTop(arrayType.sizeOnStack()); } @@ -805,8 +805,7 @@ bool ContractCompiler::visit(Throw const& _throw) { CompilerContext::LocationSetter locationSetter(m_context, _throw); // Do not send back an error detail. - m_context << u256(0) << u256(0); - m_context << Instruction::REVERT; + m_context.appendRevert(); return false; } -- cgit v1.2.3 From 5a75581f6643a229ab12a861d0b0663ea3e5158e Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 23 Jun 2017 18:55:47 +0200 Subject: Disallow invoking the same modifier multiple times. --- libsolidity/codegen/ContractCompiler.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index dc090634..8724521b 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -879,6 +879,7 @@ void ContractCompiler::appendModifierOrFunctionCode() solAssert(m_currentFunction, ""); unsigned stackSurplus = 0; Block const* codeBlock = nullptr; + vector addedVariables; m_modifierDepth++; @@ -902,6 +903,7 @@ void ContractCompiler::appendModifierOrFunctionCode() for (unsigned i = 0; i < modifier.parameters().size(); ++i) { m_context.addVariable(*modifier.parameters()[i]); + addedVariables.push_back(modifier.parameters()[i].get()); compileExpression( *modifierInvocation->arguments()[i], modifier.parameters()[i]->annotation().type @@ -928,6 +930,8 @@ void ContractCompiler::appendModifierOrFunctionCode() m_returnTags.pop_back(); CompilerUtils(m_context).popStackSlots(stackSurplus); + for (auto var: addedVariables) + m_context.removeVariable(*var); } m_modifierDepth--; } -- cgit v1.2.3 From 168f64f4cb55a7055261a4c66ca54f496e96b503 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 23 Jun 2017 17:20:07 +0200 Subject: Fix negative stack size checks. --- libsolidity/codegen/ContractCompiler.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 977a2c7c..61a90050 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -267,12 +267,16 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac m_context << notFound; if (fallback) { + m_context.setStackOffset(0); if (!fallback->isPayable()) appendCallValueCheck(); eth::AssemblyItem returnTag = m_context.pushNewTag(); fallback->accept(*this); m_context << returnTag; + m_context.adjustStackOffset( + CompilerUtils(m_context).sizeOnStack(FunctionType(*fallback).returnParameterTypes()) - 1 + ); appendReturnValuePacker(FunctionType(*fallback).returnParameterTypes(), _contract.isLibrary()); } else @@ -285,6 +289,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac CompilerContext::LocationSetter locationSetter(m_context, functionType->declaration()); m_context << callDataUnpackerEntryPoints.at(it.first); + m_context.setStackOffset(0); // We have to allow this for libraries, because value of the previous // call is still visible in the delegatecall. if (!functionType->isPayable() && !_contract.isLibrary()) @@ -295,6 +300,11 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac appendCalldataUnpacker(functionType->parameterTypes()); m_context.appendJumpTo(m_context.functionEntryLabel(functionType->declaration())); m_context << returnTag; + m_context.adjustStackOffset( + CompilerUtils(m_context).sizeOnStack(functionType->returnParameterTypes()) - + CompilerUtils(m_context).sizeOnStack(functionType->parameterTypes()) - + 1 + ); appendReturnValuePacker(functionType->returnParameterTypes(), _contract.isLibrary()); } } -- cgit v1.2.3 From ef9a7b2144993e097da6bde7675abd5651bf64cc Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 27 Jun 2017 14:29:04 +0200 Subject: Stack adjustment and code generation for fallback function. This assumes that the fallback function does not have return parameters. --- libsolidity/codegen/ContractCompiler.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 61a90050..b6352b39 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -271,13 +271,15 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac if (!fallback->isPayable()) appendCallValueCheck(); + // Return tag is used to jump out of the function. eth::AssemblyItem returnTag = m_context.pushNewTag(); fallback->accept(*this); m_context << returnTag; - m_context.adjustStackOffset( - CompilerUtils(m_context).sizeOnStack(FunctionType(*fallback).returnParameterTypes()) - 1 - ); - appendReturnValuePacker(FunctionType(*fallback).returnParameterTypes(), _contract.isLibrary()); + solAssert(FunctionType(*fallback).parameterTypes().empty(), ""); + solAssert(FunctionType(*fallback).returnParameterTypes().empty(), ""); + // Return tag gets consumed. + m_context.adjustStackOffset(-1); + m_context << Instruction::STOP; } else m_context.appendRevert(); -- cgit v1.2.3 From 6a708b0cfe245499f85f7260f7267b399c9a7fcb Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 28 Jun 2017 16:55:20 +0100 Subject: Document appendFunctionSelector --- libsolidity/codegen/ContractCompiler.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index b6352b39..74b07d4d 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -297,16 +297,20 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac if (!functionType->isPayable() && !_contract.isLibrary()) appendCallValueCheck(); + // Return tag is used to jump out of the function. eth::AssemblyItem returnTag = m_context.pushNewTag(); + // Parameter for calldataUnpacker m_context << CompilerUtils::dataStartOffset; appendCalldataUnpacker(functionType->parameterTypes()); m_context.appendJumpTo(m_context.functionEntryLabel(functionType->declaration())); m_context << returnTag; + // Return tag and input parameters get consumed. m_context.adjustStackOffset( CompilerUtils(m_context).sizeOnStack(functionType->returnParameterTypes()) - CompilerUtils(m_context).sizeOnStack(functionType->parameterTypes()) - 1 ); + // Consumes the return parameters. appendReturnValuePacker(functionType->returnParameterTypes(), _contract.isLibrary()); } } -- cgit v1.2.3 From 71d866cd7ab8013f36ab5b01d849a74b9908aae0 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 30 Jun 2017 14:09:35 +0200 Subject: Abort early if there is nothing to encode or decode. --- libsolidity/codegen/ContractCompiler.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'libsolidity/codegen/ContractCompiler.cpp') diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 74b07d4d..c358a519 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -299,9 +299,12 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac // Return tag is used to jump out of the function. eth::AssemblyItem returnTag = m_context.pushNewTag(); - // Parameter for calldataUnpacker - m_context << CompilerUtils::dataStartOffset; - appendCalldataUnpacker(functionType->parameterTypes()); + if (!functionType->parameterTypes().empty()) + { + // Parameter for calldataUnpacker + m_context << CompilerUtils::dataStartOffset; + appendCalldataUnpacker(functionType->parameterTypes()); + } m_context.appendJumpTo(m_context.functionEntryLabel(functionType->declaration())); m_context << returnTag; // Return tag and input parameters get consumed. -- cgit v1.2.3