mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[Sol2Yul] Adding support for constructors with parameters in case of inheritance
This commit is contained in:
parent
d0fcd468f6
commit
5329da93fb
@ -2334,3 +2334,39 @@ string YulUtilFunctions::extractReturndataFunction()
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::copyConstructorArgumentsToMemoryFunction(
|
||||
ContractDefinition const& _contract,
|
||||
string const& _creationObjectName
|
||||
)
|
||||
{
|
||||
string functionName = "copy_arguments_for_constructor_" +
|
||||
toString(_contract.constructor()->id()) +
|
||||
"_object_" +
|
||||
_contract.name() +
|
||||
"_" +
|
||||
toString(_contract.id());
|
||||
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
string returnParams = suffixedVariableNameList("ret_param_",0, _contract.constructor()->parameters().size());
|
||||
ABIFunctions abiFunctions(m_evmVersion, m_revertStrings, m_functionCollector);
|
||||
|
||||
return util::Whiskers(R"(
|
||||
function <functionName>() -> <retParams> {
|
||||
let programSize := datasize("<object>")
|
||||
let argSize := sub(codesize(), programSize)
|
||||
|
||||
let memoryDataOffset := <allocate>(argSize)
|
||||
codecopy(memoryDataOffset, programSize, argSize)
|
||||
|
||||
<retParams> := <abiDecode>(memoryDataOffset, add(memoryDataOffset, argSize))
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("retParams", returnParams)
|
||||
("object", _creationObjectName)
|
||||
("allocate", allocationFunction())
|
||||
("abiDecode", abiFunctions.tupleDecoder(FunctionType(*_contract.constructor()).parameterTypes(), true))
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -337,6 +337,13 @@ public:
|
||||
/// If returndatacopy() is not supported by the underlying target, a empty array will be returned instead.
|
||||
std::string extractReturndataFunction();
|
||||
|
||||
/// @returns function name that returns constructor arguments copied to memory
|
||||
/// signature: () -> arguments
|
||||
std::string copyConstructorArgumentsToMemoryFunction(
|
||||
ContractDefinition const& _contract,
|
||||
std::string const& _creationObjectName
|
||||
);
|
||||
|
||||
private:
|
||||
/// Special case of conversionFunction - handles everything that does not
|
||||
/// use exactly one variable to hold the value.
|
||||
|
@ -81,7 +81,9 @@ string IRGenerator::generate(ContractDefinition const& _contract)
|
||||
object "<CreationObject>" {
|
||||
code {
|
||||
<memoryInit>
|
||||
<constructor>
|
||||
<callValueCheck>
|
||||
<?constructorHasParams> let <constructorParams> := <copyConstructorArguments>() </constructorHasParams>
|
||||
<implicitConstructor>(<constructorParams>)
|
||||
<deploy>
|
||||
<functions>
|
||||
}
|
||||
@ -99,8 +101,25 @@ string IRGenerator::generate(ContractDefinition const& _contract)
|
||||
|
||||
t("CreationObject", creationObjectName(_contract));
|
||||
t("memoryInit", memoryInit());
|
||||
t("constructor", constructorCode(_contract));
|
||||
|
||||
FunctionDefinition const* constructor = _contract.constructor();
|
||||
t("callValueCheck", !constructor || !constructor->isPayable() ? callValueCheck() : "");
|
||||
vector<string> constructorParams;
|
||||
if (constructor && !constructor->parameters().empty())
|
||||
{
|
||||
for (size_t i = 0; i < constructor->parameters().size(); ++i)
|
||||
constructorParams.emplace_back(m_context.newYulVariable());
|
||||
t(
|
||||
"copyConstructorArguments",
|
||||
m_utils.copyConstructorArgumentsToMemoryFunction(_contract, creationObjectName(_contract))
|
||||
);
|
||||
}
|
||||
t("constructorParams", joinHumanReadable(constructorParams));
|
||||
t("constructorHasParams", !constructorParams.empty());
|
||||
t("implicitConstructor", implicitConstructorName(_contract));
|
||||
|
||||
t("deploy", deployCode(_contract));
|
||||
generateImplicitConstructors(_contract);
|
||||
generateQueuedFunctions();
|
||||
t("functions", m_context.functionCollector().requestedFunctions());
|
||||
|
||||
@ -238,64 +257,115 @@ string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDec
|
||||
return generator.code();
|
||||
}
|
||||
|
||||
string IRGenerator::constructorCode(ContractDefinition const& _contract)
|
||||
pair<string, map<ContractDefinition const*, string>> IRGenerator::evaluateConstructorArguments(
|
||||
ContractDefinition const& _contract
|
||||
)
|
||||
{
|
||||
// Initialization of state variables in base-to-derived order.
|
||||
solAssert(!_contract.isLibrary(), "Tried to initialize state variables of library.");
|
||||
map<ContractDefinition const*, string> constructorParams;
|
||||
vector<pair<ContractDefinition const*, std::vector<ASTPointer<Expression>>const *>> baseConstructorArguments;
|
||||
|
||||
using boost::adaptors::reverse;
|
||||
for (ASTPointer<InheritanceSpecifier> const& base: _contract.baseContracts())
|
||||
if (FunctionDefinition const* baseConstructor = dynamic_cast<ContractDefinition const*>(
|
||||
base->name().annotation().referencedDeclaration
|
||||
)->constructor(); baseConstructor && base->arguments())
|
||||
baseConstructorArguments.emplace_back(
|
||||
dynamic_cast<ContractDefinition const*>(baseConstructor->scope()),
|
||||
base->arguments()
|
||||
);
|
||||
|
||||
ostringstream out;
|
||||
if (FunctionDefinition const* constructor = _contract.constructor())
|
||||
for (auto const& modifier: constructor->modifiers())
|
||||
if (FunctionDefinition const* baseConstructor = dynamic_cast<ContractDefinition const*>(
|
||||
modifier->name()->annotation().referencedDeclaration
|
||||
)->constructor(); baseConstructor && modifier->arguments())
|
||||
baseConstructorArguments.emplace_back(
|
||||
dynamic_cast<ContractDefinition const*>(baseConstructor->scope()),
|
||||
modifier->arguments()
|
||||
);
|
||||
|
||||
FunctionDefinition const* constructor = _contract.constructor();
|
||||
if (constructor && !constructor->isPayable())
|
||||
out << callValueCheck();
|
||||
|
||||
for (ContractDefinition const* contract: reverse(_contract.annotation().linearizedBaseContracts))
|
||||
IRGeneratorForStatements generator{m_context, m_utils};
|
||||
for (auto&& [baseContract, arguments]: baseConstructorArguments)
|
||||
{
|
||||
out <<
|
||||
"\n// Begin state variable initialization for contract \"" <<
|
||||
contract->name() <<
|
||||
"\" (" <<
|
||||
contract->stateVariables().size() <<
|
||||
" variables)\n";
|
||||
|
||||
IRGeneratorForStatements generator{m_context, m_utils};
|
||||
for (VariableDeclaration const* variable: contract->stateVariables())
|
||||
if (!variable->isConstant() && !variable->immutable())
|
||||
generator.initializeStateVar(*variable);
|
||||
out << generator.code();
|
||||
|
||||
out << "// End state variable initialization for contract \"" << contract->name() << "\".\n";
|
||||
solAssert(baseContract && arguments, "");
|
||||
if (baseContract->constructor() && !arguments->empty())
|
||||
{
|
||||
vector<string> params;
|
||||
for (size_t i = 0; i < arguments->size(); ++i)
|
||||
params.emplace_back(generator.evaluateExpression(
|
||||
*(arguments->at(i)),
|
||||
*(baseContract->constructor()->parameters()[i]->type())
|
||||
).commaSeparatedList());
|
||||
constructorParams[baseContract] = joinHumanReadable(params);
|
||||
}
|
||||
}
|
||||
|
||||
if (constructor)
|
||||
return {generator.code(), constructorParams};
|
||||
}
|
||||
|
||||
string IRGenerator::initStateVariables(ContractDefinition const& _contract)
|
||||
{
|
||||
IRGeneratorForStatements generator{m_context, m_utils};
|
||||
for (VariableDeclaration const* variable: _contract.stateVariables())
|
||||
if (!variable->isConstant() && !variable->immutable())
|
||||
generator.initializeStateVar(*variable);
|
||||
|
||||
return generator.code();
|
||||
}
|
||||
|
||||
void IRGenerator::generateImplicitConstructors(ContractDefinition const& _contract)
|
||||
{
|
||||
auto listAllParams = [&](
|
||||
map<ContractDefinition const*, string> const& baseParams) -> string
|
||||
{
|
||||
ABIFunctions abiFunctions(m_evmVersion, m_context.revertStrings(), m_context.functionCollector());
|
||||
unsigned paramVars = make_shared<TupleType>(constructor->functionType(false)->parameterTypes())->sizeOnStack();
|
||||
vector<string> params;
|
||||
for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
|
||||
if (baseParams.count(contract))
|
||||
params.emplace_back(baseParams.at(contract));
|
||||
return joinHumanReadable(params);
|
||||
};
|
||||
|
||||
Whiskers t(R"X(
|
||||
let programSize := datasize("<object>")
|
||||
let argSize := sub(codesize(), programSize)
|
||||
map<ContractDefinition const*, string> baseConstructorParams;
|
||||
for (size_t i = 0; i < _contract.annotation().linearizedBaseContracts.size(); ++i)
|
||||
{
|
||||
ContractDefinition const* contract = _contract.annotation().linearizedBaseContracts[i];
|
||||
baseConstructorParams.erase(contract);
|
||||
|
||||
let memoryDataOffset := <allocate>(argSize)
|
||||
codecopy(memoryDataOffset, programSize, argSize)
|
||||
m_context.functionCollector().createFunction(implicitConstructorName(*contract), [&]() {
|
||||
Whiskers t(R"(
|
||||
function <functionName>(<params><comma><baseParams>) {
|
||||
<evalBaseArguments>
|
||||
<?hasNextConstructor> <nextConstructor>(<nextParams>) </hasNextConstructor>
|
||||
<initStateVariables>
|
||||
<userDefinedConstructorBody>
|
||||
}
|
||||
)");
|
||||
string params;
|
||||
if (contract->constructor())
|
||||
for (ASTPointer<VariableDeclaration> const& varDecl: contract->constructor()->parameters())
|
||||
params += (params.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList();
|
||||
t("params", params);
|
||||
string baseParamsString = listAllParams(baseConstructorParams);
|
||||
t("baseParams", baseParamsString);
|
||||
t("comma", !params.empty() && !baseParamsString.empty() ? ", " : "");
|
||||
t("functionName", implicitConstructorName(*contract));
|
||||
pair<string, map<ContractDefinition const*, string>> evaluatedArgs = evaluateConstructorArguments(*contract);
|
||||
baseConstructorParams.insert(evaluatedArgs.second.begin(), evaluatedArgs.second.end());
|
||||
t("evalBaseArguments", evaluatedArgs.first);
|
||||
if (i < _contract.annotation().linearizedBaseContracts.size() - 1)
|
||||
{
|
||||
t("hasNextConstructor", true);
|
||||
ContractDefinition const* nextContract = _contract.annotation().linearizedBaseContracts[i + 1];
|
||||
t("nextConstructor", implicitConstructorName(*nextContract));
|
||||
t("nextParams", listAllParams(baseConstructorParams));
|
||||
}
|
||||
else
|
||||
t("hasNextConstructor", false);
|
||||
t("initStateVariables", initStateVariables(*contract));
|
||||
t("userDefinedConstructorBody", contract->constructor() ? generate(contract->constructor()->body()) : "");
|
||||
|
||||
<assignToParams> <abiDecode>(memoryDataOffset, add(memoryDataOffset, argSize))
|
||||
|
||||
<constructorName>(<params>)
|
||||
)X");
|
||||
t("object", creationObjectName(_contract));
|
||||
t("allocate", m_utils.allocationFunction());
|
||||
t("assignToParams", paramVars == 0 ? "" : "let " + suffixedVariableNameList("param_", 0, paramVars) + " := ");
|
||||
t("params", suffixedVariableNameList("param_", 0, paramVars));
|
||||
t("abiDecode", abiFunctions.tupleDecoder(constructor->functionType(false)->parameterTypes(), true));
|
||||
t("constructorName", m_context.enqueueFunctionForCodeGeneration(*constructor));
|
||||
|
||||
out << t.render();
|
||||
return t.render();
|
||||
});
|
||||
}
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
string IRGenerator::deployCode(ContractDefinition const& _contract)
|
||||
@ -323,6 +393,11 @@ string IRGenerator::runtimeObjectName(ContractDefinition const& _contract)
|
||||
return _contract.name() + "_" + to_string(_contract.id()) + "_deployed";
|
||||
}
|
||||
|
||||
string IRGenerator::implicitConstructorName(ContractDefinition const& _contract)
|
||||
{
|
||||
return "constructor_" + _contract.name() + "_" + to_string(_contract.id());
|
||||
}
|
||||
|
||||
string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
||||
{
|
||||
Whiskers t(R"X(
|
||||
|
@ -67,12 +67,29 @@ private:
|
||||
/// Generates code that assigns the initial value of the respective type.
|
||||
std::string generateInitialAssignment(VariableDeclaration const& _varDecl);
|
||||
|
||||
std::string constructorCode(ContractDefinition const& _contract);
|
||||
/// Generates implicit constructors for all contracts in the inheritance hierarchy of
|
||||
/// @a _contract
|
||||
/// If there are user defined constructors, their body will be included in implicit constructors body.
|
||||
void generateImplicitConstructors(ContractDefinition const& _contract);
|
||||
|
||||
/// Evaluates constructor's arguments for all base contracts (listed in inheritance specifiers) of
|
||||
/// @a _contract
|
||||
/// @returns Pair of expressions needed to evaluate params and list of parameters in a map contract -> params
|
||||
std::pair<std::string, std::map<ContractDefinition const*, std::string>> evaluateConstructorArguments(
|
||||
ContractDefinition const& _contract
|
||||
);
|
||||
|
||||
/// Initializes state variables of
|
||||
/// @a _contract
|
||||
/// @returns Source code to initialize state variables
|
||||
std::string initStateVariables(ContractDefinition const& _contract);
|
||||
|
||||
std::string deployCode(ContractDefinition const& _contract);
|
||||
std::string callValueCheck();
|
||||
|
||||
std::string creationObjectName(ContractDefinition const& _contract);
|
||||
std::string runtimeObjectName(ContractDefinition const& _contract);
|
||||
std::string implicitConstructorName(ContractDefinition const& _contract);
|
||||
|
||||
std::string dispatchRoutine(ContractDefinition const& _contract);
|
||||
|
||||
|
@ -169,6 +169,14 @@ void IRGeneratorForStatements::initializeLocalVar(VariableDeclaration const& _va
|
||||
assign(m_context.localVariable(_varDecl), zero);
|
||||
}
|
||||
|
||||
IRVariable IRGeneratorForStatements::evaluateExpression(Expression const& _expression, Type const& _targetType)
|
||||
{
|
||||
_expression.accept(*this);
|
||||
IRVariable variable{m_context.newYulVariable(), _targetType};
|
||||
define(variable, _expression);
|
||||
return variable;
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _varDeclStatement)
|
||||
{
|
||||
if (Expression const* expression = _varDeclStatement.initialValue())
|
||||
|
@ -51,6 +51,9 @@ public:
|
||||
/// Generates code to initialize the given local variable.
|
||||
void initializeLocalVar(VariableDeclaration const& _varDecl);
|
||||
|
||||
/// Calculates expression's value and returns variable where it was stored
|
||||
IRVariable evaluateExpression(Expression const& _expression, Type const& _to);
|
||||
|
||||
void endVisit(VariableDeclarationStatement const& _variableDeclaration) override;
|
||||
bool visit(Conditional const& _conditional) override;
|
||||
bool visit(Assignment const& _assignment) override;
|
||||
|
@ -1,6 +1,8 @@
|
||||
{"contracts":{"A":{"C":{"ewasm":{"wast":"(module
|
||||
;; sub-module \"C_2_deployed\" will be encoded as custom section in binary here, but is skipped in text mode.
|
||||
(import \"ethereum\" \"codeCopy\" (func $eth.codeCopy (param i32 i32 i32)))
|
||||
(import \"ethereum\" \"revert\" (func $eth.revert (param i32 i32)))
|
||||
(import \"ethereum\" \"getCallValue\" (func $eth.getCallValue (param i32)))
|
||||
(import \"ethereum\" \"finish\" (func $eth.finish (param i32 i32)))
|
||||
(memory $memory (export \"memory\") 1)
|
||||
(export \"main\" (func $main))
|
||||
@ -9,27 +11,30 @@
|
||||
(local $_1 i64)
|
||||
(local $p i64)
|
||||
(local $r i64)
|
||||
(local $hi i64)
|
||||
(local $hi_1 i64)
|
||||
(local $y i64)
|
||||
(local $hi_2 i64)
|
||||
(local $_2 i64)
|
||||
(local $z1 i64)
|
||||
(local $z2 i64)
|
||||
(local $z3 i64)
|
||||
(local $_3 i64)
|
||||
(local.set $_1 (i64.const 0))
|
||||
(local.set $p (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 64)))
|
||||
(local.set $r (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $p)) (i32.wrap_i64 (i64.const 64)))))
|
||||
(if (i64.ne (i64.extend_i32_u (i32.lt_u (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (local.get $p)))) (i64.const 0)) (then
|
||||
(unreachable)))
|
||||
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $_1)) (i64.const 16)))
|
||||
(local.set $hi_1 (i64.shl (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $_1) (i64.const 16)))) (i64.const 32)))
|
||||
(local.set $y (i64.or (local.get $hi_1) (call $endian_swap_32 (i64.shr_u (local.get $_1) (i64.const 32)))))
|
||||
(i64.store (i32.wrap_i64 (local.get $r)) (local.get $y))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 8))))) (local.get $y))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 16))))) (local.get $y))
|
||||
(local.set $hi_2 (i64.shl (call $endian_swap_32 (i64.const 128)) (i64.const 32)))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 24))))) (i64.or (local.get $hi_2) (call $endian_swap_32 (i64.shr_u (i64.const 128) (i64.const 32)))))
|
||||
(local.set $_2 (datasize \"C_2_deployed\"))
|
||||
(call $eth.codeCopy (i32.wrap_i64 (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (dataoffset \"C_2_deployed\"))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_2))))
|
||||
(call $eth.finish (i32.wrap_i64 (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_2))))
|
||||
(local.set $_2 (call $endian_swap (local.get $_1)))
|
||||
(i64.store (i32.wrap_i64 (local.get $r)) (local.get $_2))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 8))))) (local.get $_2))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 16))))) (local.get $_2))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 24))))) (call $endian_swap (i64.const 128)))
|
||||
(call $eth.getCallValue (i32.wrap_i64 (i64.const 0)))
|
||||
(local.set $z1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.const 0)))))
|
||||
(local.set $z2 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 8))))))))
|
||||
(local.set $z3 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 16))))))))
|
||||
(if (i64.ne (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $z1) (local.get $z2)) (i64.or (local.get $z3) (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 24)))))))))))))) (i64.const 0)) (then
|
||||
(call $revert (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))))
|
||||
(local.set $_3 (datasize \"C_2_deployed\"))
|
||||
(call $codecopy (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (dataoffset \"C_2_deployed\") (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3))
|
||||
(call $return (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3))
|
||||
)
|
||||
|
||||
(func $u256_to_i32
|
||||
@ -62,6 +67,22 @@
|
||||
(local.get $r)
|
||||
)
|
||||
|
||||
(func $codecopy
|
||||
(param $x1 i64)
|
||||
(param $x2 i64)
|
||||
(param $x3 i64)
|
||||
(param $x4 i64)
|
||||
(param $y1 i64)
|
||||
(param $y2 i64)
|
||||
(param $y3 i64)
|
||||
(param $y4 i64)
|
||||
(param $z1 i64)
|
||||
(param $z2 i64)
|
||||
(param $z3 i64)
|
||||
(param $z4 i64)
|
||||
(call $eth.codeCopy (i32.wrap_i64 (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $z1) (local.get $z2) (local.get $z3) (local.get $z4))))
|
||||
)
|
||||
|
||||
(func $endian_swap_16
|
||||
(param $x i64)
|
||||
(result i64)
|
||||
@ -80,5 +101,39 @@
|
||||
(local.get $y)
|
||||
)
|
||||
|
||||
(func $endian_swap
|
||||
(param $x i64)
|
||||
(result i64)
|
||||
(local $y i64)
|
||||
(local $hi i64)
|
||||
(local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32)))
|
||||
(local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32)))))
|
||||
(local.get $y)
|
||||
)
|
||||
|
||||
(func $return
|
||||
(param $x1 i64)
|
||||
(param $x2 i64)
|
||||
(param $x3 i64)
|
||||
(param $x4 i64)
|
||||
(param $y1 i64)
|
||||
(param $y2 i64)
|
||||
(param $y3 i64)
|
||||
(param $y4 i64)
|
||||
(call $eth.finish (i32.wrap_i64 (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4))))
|
||||
)
|
||||
|
||||
(func $revert
|
||||
(param $x1 i64)
|
||||
(param $x2 i64)
|
||||
(param $x3 i64)
|
||||
(param $x4 i64)
|
||||
(param $y1 i64)
|
||||
(param $y2 i64)
|
||||
(param $y3 i64)
|
||||
(param $y4 i64)
|
||||
(call $eth.revert (i32.wrap_i64 (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4))))
|
||||
)
|
||||
|
||||
)
|
||||
"}}}},"sources":{"A":{"id":0}}}
|
||||
|
@ -8,8 +8,12 @@
|
||||
object \"C_6\" {
|
||||
code {
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
constructor_C_6()
|
||||
codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))
|
||||
return(0, datasize(\"C_6_deployed\"))
|
||||
function constructor_C_6()
|
||||
{ }
|
||||
}
|
||||
object \"C_6_deployed\" {
|
||||
code {
|
||||
|
@ -9,15 +9,21 @@
|
||||
object \"C_6\" {
|
||||
code {
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
|
||||
// Begin state variable initialization for contract \"C\" (0 variables)
|
||||
// End state variable initialization for contract \"C\".
|
||||
|
||||
constructor_C_6()
|
||||
|
||||
codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))
|
||||
return(0, datasize(\"C_6_deployed\"))
|
||||
|
||||
|
||||
function constructor_C_6() {
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
object \"C_6_deployed\" {
|
||||
code {
|
||||
|
@ -9,15 +9,21 @@
|
||||
object \"C_10\" {
|
||||
code {
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
|
||||
// Begin state variable initialization for contract \"C\" (0 variables)
|
||||
// End state variable initialization for contract \"C\".
|
||||
|
||||
constructor_C_10()
|
||||
|
||||
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
|
||||
return(0, datasize(\"C_10_deployed\"))
|
||||
|
||||
|
||||
function constructor_C_10() {
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
object \"C_10_deployed\" {
|
||||
code {
|
||||
|
@ -9,15 +9,21 @@
|
||||
object \"C_10\" {
|
||||
code {
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
|
||||
// Begin state variable initialization for contract \"C\" (0 variables)
|
||||
// End state variable initialization for contract \"C\".
|
||||
|
||||
constructor_C_10()
|
||||
|
||||
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
|
||||
return(0, datasize(\"C_10_deployed\"))
|
||||
|
||||
|
||||
function constructor_C_10() {
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
object \"C_10_deployed\" {
|
||||
code {
|
||||
|
@ -9,15 +9,21 @@
|
||||
object \"C_10\" {
|
||||
code {
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
|
||||
// Begin state variable initialization for contract \"C\" (0 variables)
|
||||
// End state variable initialization for contract \"C\".
|
||||
|
||||
constructor_C_10()
|
||||
|
||||
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
|
||||
return(0, datasize(\"C_10_deployed\"))
|
||||
|
||||
|
||||
function constructor_C_10() {
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
object \"C_10_deployed\" {
|
||||
code {
|
||||
|
@ -9,15 +9,21 @@
|
||||
object \"C_10\" {
|
||||
code {
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
|
||||
// Begin state variable initialization for contract \"C\" (0 variables)
|
||||
// End state variable initialization for contract \"C\".
|
||||
|
||||
constructor_C_10()
|
||||
|
||||
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
|
||||
return(0, datasize(\"C_10_deployed\"))
|
||||
|
||||
|
||||
function constructor_C_10() {
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
object \"C_10_deployed\" {
|
||||
code {
|
||||
|
@ -9,15 +9,21 @@
|
||||
object \"C_10\" {
|
||||
code {
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
|
||||
// Begin state variable initialization for contract \"C\" (0 variables)
|
||||
// End state variable initialization for contract \"C\".
|
||||
|
||||
constructor_C_10()
|
||||
|
||||
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
|
||||
return(0, datasize(\"C_10_deployed\"))
|
||||
|
||||
|
||||
function constructor_C_10() {
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
object \"C_10_deployed\" {
|
||||
code {
|
||||
|
@ -0,0 +1,14 @@
|
||||
contract A {
|
||||
uint x = 42;
|
||||
function f() public returns(uint256) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
contract B is A {
|
||||
uint public y = f();
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// constructor() ->
|
||||
// y() -> 42
|
@ -0,0 +1,17 @@
|
||||
contract A {
|
||||
uint x;
|
||||
constructor() public {
|
||||
x = 42;
|
||||
}
|
||||
function f() public returns(uint256) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
contract B is A {
|
||||
uint public y = f();
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// constructor() ->
|
||||
// y() -> 42
|
@ -0,0 +1,28 @@
|
||||
contract A {
|
||||
uint public i;
|
||||
uint public k;
|
||||
|
||||
constructor(uint newI, uint newK) public {
|
||||
i = newI;
|
||||
k = newK;
|
||||
}
|
||||
}
|
||||
abstract contract B is A {
|
||||
uint public j;
|
||||
constructor(uint newJ) public {
|
||||
j = newJ;
|
||||
}
|
||||
}
|
||||
contract C is A {
|
||||
constructor(uint newI, uint newK) A(newI, newK) public {}
|
||||
}
|
||||
contract D is B, C {
|
||||
constructor(uint newI, uint newK) B(newI) C(newI, newK + 1) public {}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor(): 2, 0 ->
|
||||
// i() -> 2
|
||||
// j() -> 2
|
||||
// k() -> 1
|
@ -0,0 +1,18 @@
|
||||
contract C {
|
||||
uint public i;
|
||||
uint public k;
|
||||
|
||||
constructor(uint newI, uint newK) public {
|
||||
i = newI;
|
||||
k = newK;
|
||||
}
|
||||
}
|
||||
contract D is C {
|
||||
constructor(uint newI, uint newK) C(newI, newK + 1) public {}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor(): 2, 0 ->
|
||||
// i() -> 2
|
||||
// k() -> 1
|
@ -0,0 +1,15 @@
|
||||
contract C {
|
||||
uint public i;
|
||||
uint public k;
|
||||
|
||||
constructor(uint newI, uint newK) public {
|
||||
i = newI;
|
||||
k = newK;
|
||||
}
|
||||
}
|
||||
contract D is C(2, 1) {}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// i() -> 2
|
||||
// k() -> 1
|
@ -0,0 +1,14 @@
|
||||
contract A {
|
||||
uint public x = 0;
|
||||
uint y = f();
|
||||
function f() public returns (uint256) {
|
||||
++x;
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
contract B is A {
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// x() -> 1
|
@ -0,0 +1,18 @@
|
||||
contract A {
|
||||
uint public x = 0;
|
||||
uint y = f();
|
||||
function f() public returns (uint256) {
|
||||
++x;
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
contract B is A {
|
||||
uint public z;
|
||||
constructor() public {
|
||||
z = x;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// z() -> 1
|
@ -0,0 +1,29 @@
|
||||
contract A {
|
||||
uint public a = 42;
|
||||
uint public b;
|
||||
uint public c;
|
||||
constructor(uint x) public {
|
||||
b = a;
|
||||
a = x;
|
||||
}
|
||||
function f(uint x) public returns (uint256) { c = x * 3; return 23; }
|
||||
}
|
||||
contract B is A {
|
||||
uint public d = f(a);
|
||||
uint public e = b;
|
||||
uint public b_a;
|
||||
uint public b_b;
|
||||
uint public b_c;
|
||||
constructor() public A(17) { b_a = a; b_b = b; b_c = c; }
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// a() -> 17
|
||||
// b() -> 42
|
||||
// c() -> 51
|
||||
// b_a() -> 17
|
||||
// b_b() -> 42
|
||||
// b_c() -> 51
|
||||
// d() -> 23
|
||||
// e() -> 42
|
Loading…
Reference in New Issue
Block a user