vector<ContractDefinition const*>::const_iterator CompilerContext::superContract(ContractDefinition const& _contract) const { solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set."); auto it = find(m_inheritanceHierarchy.begin(), m_inheritanceHierarchy.end(), &_contract); solAssert(it != m_inheritanceHierarchy.end(), "Base not found in inheritance hierarchy."); return ++it; }
ModifierDefinition const& CompilerContext::functionModifier(string const& _name) const { solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set."); for (ContractDefinition const* contract: m_inheritanceHierarchy) for (ModifierDefinition const* modifier: contract->functionModifiers()) if (modifier->name() == _name) return *modifier; BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Function modifier " + _name + " not found.")); }
eth::AssemblyItem CompilerContext::virtualFunctionEntryLabel(FunctionDefinition const& _function) { // Libraries do not allow inheritance and their functions can be inlined, so we should not // search the inheritance hierarchy (which will be the wrong one in case the function // is inlined). if (auto scope = dynamic_cast<ContractDefinition const*>(_function.scope())) if (scope->isLibrary()) return functionEntryLabel(_function); solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set."); return virtualFunctionEntryLabel(_function, m_inheritanceHierarchy.begin()); }
void ElementaryTypeNameToken::assertDetails(Token::Value _baseType, unsigned const& _first, unsigned const& _second) { solAssert(Token::isElementaryTypeName(_baseType), ""); if (_baseType == Token::BytesM) { solAssert(_second == 0, "There should not be a second size argument to type bytesM."); solAssert(_first <= 32, "No elementary type bytes" + to_string(_first) + "."); } else if (_baseType == Token::UIntM || _baseType == Token::IntM) { solAssert(_second == 0, "There should not be a second size argument to type " + string(Token::toString(_baseType)) + "."); solAssert( _first <= 256 && _first % 8 == 0, "No elementary type " + string(Token::toString(_baseType)) + to_string(_first) + "." ); } else if (_baseType == Token::UFixedMxN || _baseType == Token::FixedMxN) { solAssert( _first + _second <= 256 && _first % 8 == 0 && _second % 8 == 0, "No elementary type " + string(Token::toString(_baseType)) + to_string(_first) + "x" + to_string(_second) + "." ); } m_token = _baseType; m_firstNumber = _first; m_secondNumber = _second; }
void CompilerContext::appendInlineAssembly( string const& _assembly, vector<string> const& _localVariables, map<string, string> const& _replacements ) { string replacedAssembly; string const* assembly = &_assembly; if (!_replacements.empty()) { replacedAssembly = _assembly; for (auto const& replacement: _replacements) replacedAssembly = boost::algorithm::replace_all_copy(replacedAssembly, replacement.first, replacement.second); assembly = &replacedAssembly; } unsigned startStackHeight = stackHeight(); auto identifierAccess = [&]( assembly::Identifier const& _identifier, eth::Assembly& _assembly, assembly::CodeGenerator::IdentifierContext _context ) { auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name); if (it == _localVariables.end()) return false; unsigned stackDepth = _localVariables.end() - it; int stackDiff = _assembly.deposit() - startStackHeight + stackDepth; if (stackDiff < 1 || stackDiff > 16) BOOST_THROW_EXCEPTION( CompilerError() << errinfo_comment("Stack too deep, try removing local variables.") ); if (_context == assembly::CodeGenerator::IdentifierContext::RValue) _assembly.append(dupInstruction(stackDiff)); else { _assembly.append(swapInstruction(stackDiff)); _assembly.append(Instruction::POP); } return true; }; solAssert(assembly::InlineAssemblyStack().parseAndAssemble(*assembly, m_asm, identifierAccess), ""); }
eth::AssemblyItem CompilerContext::virtualFunctionEntryLabel( FunctionDefinition const& _function, vector<ContractDefinition const*>::const_iterator _searchStart ) { string name = _function.name(); FunctionType functionType(_function); auto it = _searchStart; for (; it != m_inheritanceHierarchy.end(); ++it) for (FunctionDefinition const* function: (*it)->definedFunctions()) if ( function->name() == name && !function->isConstructor() && FunctionType(*function).hasEqualArgumentTypes(functionType) ) return functionEntryLabel(*function); solAssert(false, "Super function " + name + " not found."); return m_asm.newTag(); // not reached }
eth::Assembly const& CompilerContext::compiledContract(const ContractDefinition& _contract) const { auto ret = m_compiledContracts.find(&_contract); solAssert(ret != m_compiledContracts.end(), "Compiled contract not found."); return *ret->second; }
void CompilerContext::removeVariable(VariableDeclaration const& _declaration) { solAssert(!!m_localVariables.count(&_declaration), ""); m_localVariables.erase(&_declaration); }
void CompilerContext::addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent) { solAssert(m_asm.deposit() >= 0 && unsigned(m_asm.deposit()) >= _offsetToCurrent, ""); m_localVariables[&_declaration] = unsigned(m_asm.deposit()) - _offsetToCurrent; }
pair<u256, unsigned> CompilerContext::storageLocationOfVariable(const Declaration& _declaration) const { auto it = m_stateVariables.find(&_declaration); solAssert(it != m_stateVariables.end(), "Variable not found in storage."); return it->second; }
unsigned CompilerContext::baseStackOffsetOfVariable(Declaration const& _declaration) const { auto res = m_localVariables.find(&_declaration); solAssert(res != m_localVariables.end(), "Variable not found on stack."); return res->second; }
eth::AssemblyItem CompilerContext::superFunctionEntryLabel(FunctionDefinition const& _function, ContractDefinition const& _base) { solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set."); return virtualFunctionEntryLabel(_function, superContract(_base)); }
eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition const& _function) const { auto res = m_functionEntryLabels.find(&_function); solAssert(res != m_functionEntryLabels.end(), "Function entry label not found."); return res->second.tag(); }