diff options
author | Christian <c@ethdev.com> | 2015-01-12 19:47:37 +0800 |
---|---|---|
committer | Christian <c@ethdev.com> | 2015-01-14 01:12:30 +0800 |
commit | ec022783c4ba2a319ce60dc818e4f0e0e8872093 (patch) | |
tree | 2aeae1ab591ca84bd4c83ab31ed5b72a33a79422 /ExpressionCompiler.cpp | |
parent | 80eec8b308e8af3b742e3da47ded927e4e4b388d (diff) | |
download | dexon-solidity-ec022783c4ba2a319ce60dc818e4f0e0e8872093.tar.gz dexon-solidity-ec022783c4ba2a319ce60dc818e4f0e0e8872093.tar.zst dexon-solidity-ec022783c4ba2a319ce60dc818e4f0e0e8872093.zip |
Modify gas and value for external function call.
Diffstat (limited to 'ExpressionCompiler.cpp')
-rw-r--r-- | ExpressionCompiler.cpp | 98 |
1 files changed, 66 insertions, 32 deletions
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 1c02f4f3..8cecbb1b 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -232,27 +232,41 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) } case Location::EXTERNAL: case Location::BARE: + _functionCall.getExpression().accept(*this); + appendExternalFunctionCall(function, arguments, function.getLocation() == Location::BARE); + break; + case Location::SET_GAS: { - FunctionCallOptions options; - options.bare = function.getLocation() == Location::BARE; - options.obtainAddress = [&]() { _functionCall.getExpression().accept(*this); }; - appendExternalFunctionCall(function, arguments, options); + // stack layout: contract_address function_id [gas] [value] + _functionCall.getExpression().accept(*this); + arguments.front()->accept(*this); + appendTypeConversion(*arguments.front()->getType(), IntegerType(256), true); + // Note that function is not the original function, but the ".gas" function. + // Its values of gasSet and valueSet is equal to the original function's though. + unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0); + if (stackDepth > 0) + m_context << eth::swapInstruction(stackDepth); + if (function.gasSet()) + m_context << eth::Instruction::POP; break; } + case Location::SET_VALUE: + // stack layout: contract_address function_id [gas] [value] + _functionCall.getExpression().accept(*this); + // Note that function is not the original function, but the ".value" function. + // Its values of gasSet and valueSet is equal to the original function's though. + if (function.valueSet()) + m_context << eth::Instruction::POP; + arguments.front()->accept(*this); + break; case Location::SEND: - { - FunctionCallOptions options; - options.bare = true; - options.obtainAddress = [&]() { _functionCall.getExpression().accept(*this); }; - options.obtainValue = [&]() - { - arguments.front()->accept(*this); - appendTypeConversion(*arguments.front()->getType(), - *function.getParameterTypes().front(), true); - }; - appendExternalFunctionCall(FunctionType(TypePointers{}, TypePointers{}, Location::EXTERNAL), {}, options); + // TODO set gas to min + _functionCall.getExpression().accept(*this); + arguments.front()->accept(*this); + appendTypeConversion(*arguments.front()->getType(), + *function.getParameterTypes().front(), true); + appendExternalFunctionCall(FunctionType(TypePointers{}, TypePointers{}, Location::EXTERNAL, false, true), {}, true); break; - } case Location::SUICIDE: arguments.front()->accept(*this); appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); @@ -289,11 +303,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) static const map<Location, u256> contractAddresses{{Location::ECRECOVER, 1}, {Location::SHA256, 2}, {Location::RIPEMD160, 3}}; - u256 contractAddress = contractAddresses.find(function.getLocation())->second; - FunctionCallOptions options; - options.bare = true; - options.obtainAddress = [&]() { m_context << contractAddress; }; - appendExternalFunctionCall(function, arguments, options); + m_context << contractAddresses.find(function.getLocation())->second; + appendExternalFunctionCall(function, arguments, true); break; } default: @@ -370,6 +381,10 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer.")); break; + case Type::Category::FUNCTION: + solAssert(!!_memberAccess.getExpression().getType()->getMemberType(member), + "Invalid member access to function."); + break; case Type::Category::MAGIC: // we can ignore the kind of magic and only look at the name of the member if (member == "coinbase") @@ -646,15 +661,25 @@ void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functionType, vector<ASTPointer<Expression const>> const& _arguments, - FunctionCallOptions const& _options) + bool bare) { solAssert(_arguments.size() == _functionType.getParameterTypes().size(), ""); - _options.obtainAddress(); - if (!_options.bare) + // Assumed stack content here: + // <stack top> + // value [if _functionType.valueSet()] + // gas [if _functionType.gasSet()] + // function identifier [unless options.bare] + // contract address + + unsigned gasValueSize = (_functionType.gasSet() ? 1 : 0) + (_functionType.valueSet() ? 1 : 0); + if (!bare) + { + m_context << eth::dupInstruction(gasValueSize + 1); CompilerUtils(m_context).storeInMemory(0, CompilerUtils::dataStartOffset); + } - unsigned dataOffset = _options.bare ? 0 : CompilerUtils::dataStartOffset; // reserve 4 bytes for the function's hash identifier + unsigned dataOffset = bare ? 0 : CompilerUtils::dataStartOffset; // reserve 4 bytes for the function's hash identifier for (unsigned i = 0; i < _arguments.size(); ++i) { _arguments[i]->accept(*this); @@ -676,16 +701,25 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio unsigned retSize = firstType ? CompilerUtils::getPaddedSize(firstType->getCalldataEncodedSize()) : 0; // CALL arguments: outSize, outOff, inSize, inOff, value, addr, gas (stack top) m_context << u256(retSize) << u256(0) << u256(dataOffset) << u256(0); - if (_options.obtainValue) - _options.obtainValue(); + if (_functionType.valueSet()) + m_context << eth::dupInstruction(5); else m_context << u256(0); - m_context << eth::dupInstruction(6); //copy contract address + m_context << eth::dupInstruction(6 + gasValueSize + (bare ? 0 : 1)); //copy contract address - m_context << u256(25) << eth::Instruction::GAS << eth::Instruction::SUB - << eth::Instruction::CALL - << eth::Instruction::POP // @todo do not ignore failure indicator - << eth::Instruction::POP; // pop contract address + if (_functionType.gasSet()) + m_context << eth::dupInstruction(7 + (_functionType.valueSet() ? 1 : 0)); + else + m_context << u256(25) << eth::Instruction::GAS << eth::Instruction::SUB; + m_context << eth::Instruction::CALL + << eth::Instruction::POP; // @todo do not ignore failure indicator + if (_functionType.valueSet()) + m_context << eth::Instruction::POP; + if (_functionType.gasSet()) + m_context << eth::Instruction::POP; + if (!bare) + m_context << eth::Instruction::POP; + m_context << eth::Instruction::POP; // pop contract address if (retSize > 0) { |