diff options
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/codegen/ArrayUtils.cpp | 2 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerContext.cpp | 35 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerContext.h | 14 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerUtils.cpp | 8 | ||||
-rw-r--r-- | libsolidity/codegen/ContractCompiler.cpp | 8 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 12 |
6 files changed, 61 insertions, 18 deletions
diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 4d100d1d..bdd29abd 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -901,7 +901,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck) c // check out-of-bounds access m_context << Instruction::DUP2 << Instruction::LT << Instruction::ISZERO; // out-of-bounds access throws exception - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); } if (location == DataLocation::CallData && _arrayType.isDynamicallySized()) // remove length if present diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index e26f96e8..a8316109 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -70,19 +70,30 @@ void CompilerContext::callLowLevelFunction( eth::AssemblyItem retTag = pushNewTag(); CompilerUtils(*this).moveIntoStack(_inArgs); + *this << lowLevelFunctionTag(_name, _inArgs, _outArgs, _generator); + + appendJump(eth::AssemblyItem::JumpType::IntoFunction); + adjustStackOffset(int(_outArgs) - 1 - _inArgs); + *this << retTag.tag(); +} + +eth::AssemblyItem CompilerContext::lowLevelFunctionTag( + string const& _name, + unsigned _inArgs, + unsigned _outArgs, + function<void(CompilerContext&)> const& _generator +) +{ auto it = m_lowLevelFunctions.find(_name); if (it == m_lowLevelFunctions.end()) { eth::AssemblyItem tag = newTag().pushTag(); m_lowLevelFunctions.insert(make_pair(_name, tag)); m_lowLevelFunctionGenerationQueue.push(make_tuple(_name, _inArgs, _outArgs, _generator)); - *this << tag; + return tag; } else - *this << it->second; - appendJump(eth::AssemblyItem::JumpType::IntoFunction); - adjustStackOffset(int(_outArgs) - 1 - _inArgs); - *this << retTag.tag(); + return it->second; } void CompilerContext::appendMissingLowLevelFunctions() @@ -215,6 +226,20 @@ CompilerContext& CompilerContext::appendJump(eth::AssemblyItem::JumpType _jumpTy return *this << item; } +CompilerContext& CompilerContext::appendInvalid() +{ + return *this << Instruction::INVALID; +} + +CompilerContext& CompilerContext::appendConditionalInvalid() +{ + *this << Instruction::ISZERO; + eth::AssemblyItem afterTag = appendConditionalJump(); + *this << Instruction::INVALID; + *this << afterTag; + return *this; +} + void CompilerContext::resetVisitedNodes(ASTNode const* _node) { stack<ASTNode const*> newStack; diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index f024b010..c37142c9 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -104,6 +104,16 @@ public: unsigned _outArgs, std::function<void(CompilerContext&)> const& _generator ); + /// Returns the tag of the named low-level function and inserts the generator into the + /// list of low-level-functions to be generated, unless it already exists. + /// Note that the generator should not assume that objects are still alive when it is called, + /// unless they are guaranteed to be alive for the whole run of the compiler (AST nodes, for example). + eth::AssemblyItem lowLevelFunctionTag( + std::string const& _name, + unsigned _inArgs, + unsigned _outArgs, + std::function<void(CompilerContext&)> const& _generator + ); /// Generates the code for missing low-level functions, i.e. calls the generators passed above. void appendMissingLowLevelFunctions(); @@ -127,6 +137,10 @@ public: eth::AssemblyItem appendJumpToNew() { return m_asm->appendJump().tag(); } /// Appends a JUMP to a tag already on the stack CompilerContext& appendJump(eth::AssemblyItem::JumpType _jumpType = eth::AssemblyItem::JumpType::Ordinary); + /// Appends an INVALID instruction + CompilerContext& appendInvalid(); + /// Appends a conditional INVALID instruction + CompilerContext& appendConditionalInvalid(); /// Returns an "ErrorTag" eth::AssemblyItem errorTag() { return m_asm->errorTag(); } /// Appends a JUMP to a specific tag diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index caf3b1ac..477f021a 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -468,7 +468,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp EnumType const& enumType = dynamic_cast<decltype(enumType)>(_typeOnStack); solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error."); m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT; - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); enumOverflowCheckPending = false; } break; @@ -497,7 +497,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp EnumType const& enumType = dynamic_cast<decltype(enumType)>(_targetType); solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error."); m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT; - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); enumOverflowCheckPending = false; } else if (targetTypeCategory == Type::Category::FixedPoint) @@ -807,7 +807,9 @@ void CompilerUtils::pushZeroValue(Type const& _type) { if (funType->location() == FunctionType::Location::Internal) { - m_context << m_context.errorTag(); + m_context << m_context.lowLevelFunctionTag("$invalidFunction", 0, 0, [](CompilerContext& _context) { + _context.appendInvalid(); + }); return; } } diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 9dc1fb37..4d33927d 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -106,7 +106,7 @@ void ContractCompiler::appendCallValueCheck() { // Throw if function is not payable but call contained ether. m_context << Instruction::CALLVALUE; - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); } void ContractCompiler::appendInitAndConstructorCode(ContractDefinition const& _contract) @@ -271,7 +271,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac appendReturnValuePacker(FunctionType(*fallback).returnParameterTypes(), _contract.isLibrary()); } else - m_context.appendJumpTo(m_context.errorTag()); + m_context.appendInvalid(); for (auto const& it: interfaceFunctions) { @@ -918,7 +918,9 @@ eth::AssemblyPointer ContractCompiler::cloneRuntime() a << Instruction::DELEGATECALL; //Propagate error condition (if DELEGATECALL pushes 0 on stack). a << Instruction::ISZERO; - a.appendJumpI(a.errorTag()); + a << Instruction::ISZERO; + eth::AssemblyItem afterTag = a.appendJumpI().tag(); + a << Instruction::INVALID << afterTag; //@todo adjust for larger return values, make this dynamic. a << u256(0x20) << u256(0) << Instruction::RETURN; return make_shared<eth::Assembly>(a); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index bda4e04d..b66a3e12 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -585,7 +585,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << Instruction::CREATE; // Check if zero (out of stack or not enough balance). m_context << Instruction::DUP1 << Instruction::ISZERO; - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); if (function.valueSet()) m_context << swapInstruction(1) << Instruction::POP; break; @@ -1234,7 +1234,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) m_context << u256(fixedBytesType.numBytes()); m_context << Instruction::DUP2 << Instruction::LT << Instruction::ISZERO; // out-of-bounds access throws exception - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); m_context << Instruction::BYTE; m_context << (u256(1) << (256 - 8)) << Instruction::MUL; @@ -1416,7 +1416,7 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty { // Test for division by zero m_context << Instruction::DUP2 << Instruction::ISZERO; - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); if (_operator == Token::Div) m_context << (c_isSigned ? Instruction::SDIV : Instruction::DIV); @@ -1477,7 +1477,7 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator, Type co if (c_amountSigned) { m_context << u256(0) << Instruction::DUP3 << Instruction::SLT; - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); } switch (_operator) @@ -1663,7 +1663,7 @@ void ExpressionCompiler::appendExternalFunctionCall( if (funKind == FunctionKind::External || funKind == FunctionKind::CallCode || funKind == FunctionKind::DelegateCall) { m_context << Instruction::DUP1 << Instruction::EXTCODESIZE << Instruction::ISZERO; - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); existenceChecked = true; } @@ -1699,7 +1699,7 @@ void ExpressionCompiler::appendExternalFunctionCall( { //Propagate error condition (if CALL pushes 0 on stack). m_context << Instruction::ISZERO; - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); } utils().popStackSlots(remainsSize); |