aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/codegen
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2016-03-07 23:55:53 +0800
committerchriseth <c@ethdev.com>2016-03-12 00:49:32 +0800
commite5514becb89c945f59fd440696d0bb3122edbe99 (patch)
tree6358ae151c50802b3cb0c158f7b8b06c53669fd4 /libsolidity/codegen
parent60a21c6487743578af6fd4e1540a36a2b80fcac7 (diff)
downloaddexon-solidity-e5514becb89c945f59fd440696d0bb3122edbe99.tar.gz
dexon-solidity-e5514becb89c945f59fd440696d0bb3122edbe99.tar.zst
dexon-solidity-e5514becb89c945f59fd440696d0bb3122edbe99.zip
BREAKING: Implement delegatecall and make default for library calls.
Diffstat (limited to 'libsolidity/codegen')
-rw-r--r--libsolidity/codegen/Compiler.cpp10
-rw-r--r--libsolidity/codegen/Compiler.h2
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp29
3 files changed, 23 insertions, 18 deletions
diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp
index 18803b71..c7eb71a8 100644
--- a/libsolidity/codegen/Compiler.cpp
+++ b/libsolidity/codegen/Compiler.cpp
@@ -773,15 +773,13 @@ eth::Assembly Compiler::cloneRuntime()
a << u256(0) << eth::Instruction::DUP1 << eth::Instruction::CALLDATACOPY;
//@todo adjust for larger return values, make this dynamic.
a << u256(0x20) << u256(0) << eth::Instruction::CALLDATASIZE;
- // unfortunately, we have to send the value again, so that CALLVALUE returns the correct value
- // in the callcoded contract.
- a << u256(0) << eth::Instruction::CALLVALUE;
+ a << u256(0);
// this is the address which has to be substituted by the linker.
//@todo implement as special "marker" AssemblyItem.
a << u256("0xcafecafecafecafecafecafecafecafecafecafe");
- a << u256(schedule.callGas + schedule.callValueTransferGas + 10) << eth::Instruction::GAS << eth::Instruction::SUB;
- a << eth::Instruction::CALLCODE;
- //Propagate error condition (if CALLCODE pushes 0 on stack).
+ a << u256(schedule.callGas + 10) << eth::Instruction::GAS << eth::Instruction::SUB;
+ a << eth::Instruction::DELEGATECALL;
+ //Propagate error condition (if DELEGATECALL pushes 0 on stack).
a << eth::Instruction::ISZERO;
a.appendJumpI(a.errorTag());
//@todo adjust for larger return values, make this dynamic.
diff --git a/libsolidity/codegen/Compiler.h b/libsolidity/codegen/Compiler.h
index 9d069f7c..fa33bd30 100644
--- a/libsolidity/codegen/Compiler.h
+++ b/libsolidity/codegen/Compiler.h
@@ -44,7 +44,7 @@ public:
ContractDefinition const& _contract,
std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts
);
- /// Compiles a contract that uses CALLCODE to call into a pre-deployed version of the given
+ /// Compiles a contract that uses DELEGATECALL to call into a pre-deployed version of the given
/// contract at runtime, but contains the full creation-time code.
void compileClone(
ContractDefinition const& _contract,
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 58db07b1..e0b2b5f6 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -465,8 +465,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{
FunctionType const& function = *functionType;
if (function.bound())
- // Only callcode functions can be bound, this might be lifted later.
- solAssert(function.location() == Location::CallCode, "");
+ // Only delegatecall functions can be bound, this might be lifted later.
+ solAssert(function.location() == Location::DelegateCall, "");
switch (function.location())
{
case Location::Internal:
@@ -492,8 +492,10 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
}
case Location::External:
case Location::CallCode:
+ case Location::DelegateCall:
case Location::Bare:
case Location::BareCallCode:
+ case Location::BareDelegateCall:
_functionCall.expression().accept(*this);
appendExternalFunctionCall(function, arguments);
break;
@@ -875,7 +877,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
);
m_context << eth::Instruction::BALANCE;
}
- else if ((set<string>{"send", "call", "callcode"}).count(member))
+ else if ((set<string>{"send", "call", "callcode", "delegatecall"}).count(member))
utils().convertType(
*_memberAccess.expression().annotation().type,
IntegerType(0, IntegerType::Modifier::Address),
@@ -1356,6 +1358,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
FunctionKind funKind = _functionType.location();
bool returnSuccessCondition = funKind == FunctionKind::Bare || funKind == FunctionKind::BareCallCode;
bool isCallCode = funKind == FunctionKind::BareCallCode || funKind == FunctionKind::CallCode;
+ bool isDelegateCall = funKind == FunctionKind::BareDelegateCall || funKind == FunctionKind::DelegateCall;
unsigned retSize = 0;
if (returnSuccessCondition)
@@ -1371,13 +1374,13 @@ void ExpressionCompiler::appendExternalFunctionCall(
TypePointers argumentTypes;
TypePointers parameterTypes = _functionType.parameterTypes();
bool manualFunctionId =
- (funKind == FunctionKind::Bare || funKind == FunctionKind::BareCallCode) &&
+ (funKind == FunctionKind::Bare || funKind == FunctionKind::BareCallCode || funKind == FunctionKind::BareDelegateCall) &&
!_arguments.empty() &&
_arguments.front()->annotation().type->mobileType()->calldataEncodedSize(false) ==
CompilerUtils::dataStartOffset;
if (manualFunctionId)
{
- // If we have a BareCall or BareCallCode and the first type has exactly 4 bytes, use it as
+ // If we have a Bare* and the first type has exactly 4 bytes, use it as
// function identifier.
_arguments.front()->accept(*this);
utils().convertType(
@@ -1416,7 +1419,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
parameterTypes,
_functionType.padArguments(),
_functionType.takesArbitraryParameters(),
- isCallCode
+ isCallCode || isDelegateCall
);
// Stack now:
@@ -1435,8 +1438,10 @@ void ExpressionCompiler::appendExternalFunctionCall(
m_context << eth::Instruction::DUP2;
// CALL arguments: outSize, outOff, inSize, inOff (already present up to here)
- // value, addr, gas (stack top)
- if (_functionType.valueSet())
+ // [value,] addr, gas (stack top)
+ if (isDelegateCall)
+ solAssert(!_functionType.valueSet(), "Value set for delegatecall");
+ else if (_functionType.valueSet())
m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(valueStackPos));
else
m_context << u256(0);
@@ -1446,20 +1451,22 @@ void ExpressionCompiler::appendExternalFunctionCall(
m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos));
else
{
- eth::EVMSchedule schedule;// TODO: Make relevant to current suppose context.
+ eth::EVMSchedule schedule;
// send all gas except the amount needed to execute "SUB" and "CALL"
// @todo this retains too much gas for now, needs to be fine-tuned.
u256 gasNeededByCaller = schedule.callGas + 10;
if (_functionType.valueSet())
gasNeededByCaller += schedule.callValueTransferGas;
- if (!isCallCode)
+ if (!isCallCode && !isDelegateCall)
gasNeededByCaller += schedule.callNewAccountGas; // we never know
m_context <<
gasNeededByCaller <<
eth::Instruction::GAS <<
eth::Instruction::SUB;
}
- if (isCallCode)
+ if (isDelegateCall)
+ m_context << eth::Instruction::DELEGATECALL;
+ else if (isCallCode)
m_context << eth::Instruction::CALLCODE;
else
m_context << eth::Instruction::CALL;