mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8591 from mijovic/sol2YulConstructorParams
[Sol2Yul] Adding support for constructors with parameters (inheritance)
This commit is contained in:
commit
16ed53ddd0
@ -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.
|
/// If returndatacopy() is not supported by the underlying target, a empty array will be returned instead.
|
||||||
std::string extractReturndataFunction();
|
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:
|
private:
|
||||||
/// Special case of conversionFunction - handles everything that does not
|
/// Special case of conversionFunction - handles everything that does not
|
||||||
/// use exactly one variable to hold the value.
|
/// use exactly one variable to hold the value.
|
||||||
|
@ -81,7 +81,9 @@ string IRGenerator::generate(ContractDefinition const& _contract)
|
|||||||
object "<CreationObject>" {
|
object "<CreationObject>" {
|
||||||
code {
|
code {
|
||||||
<memoryInit>
|
<memoryInit>
|
||||||
<constructor>
|
<callValueCheck>
|
||||||
|
<?constructorHasParams> let <constructorParams> := <copyConstructorArguments>() </constructorHasParams>
|
||||||
|
<implicitConstructor>(<constructorParams>)
|
||||||
<deploy>
|
<deploy>
|
||||||
<functions>
|
<functions>
|
||||||
}
|
}
|
||||||
@ -99,8 +101,25 @@ string IRGenerator::generate(ContractDefinition const& _contract)
|
|||||||
|
|
||||||
t("CreationObject", creationObjectName(_contract));
|
t("CreationObject", creationObjectName(_contract));
|
||||||
t("memoryInit", memoryInit());
|
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));
|
t("deploy", deployCode(_contract));
|
||||||
|
generateImplicitConstructors(_contract);
|
||||||
generateQueuedFunctions();
|
generateQueuedFunctions();
|
||||||
t("functions", m_context.functionCollector().requestedFunctions());
|
t("functions", m_context.functionCollector().requestedFunctions());
|
||||||
|
|
||||||
@ -238,64 +257,115 @@ string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDec
|
|||||||
return generator.code();
|
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.
|
map<ContractDefinition const*, string> constructorParams;
|
||||||
solAssert(!_contract.isLibrary(), "Tried to initialize state variables of library.");
|
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();
|
IRGeneratorForStatements generator{m_context, m_utils};
|
||||||
if (constructor && !constructor->isPayable())
|
for (auto&& [baseContract, arguments]: baseConstructorArguments)
|
||||||
out << callValueCheck();
|
|
||||||
|
|
||||||
for (ContractDefinition const* contract: reverse(_contract.annotation().linearizedBaseContracts))
|
|
||||||
{
|
{
|
||||||
out <<
|
solAssert(baseContract && arguments, "");
|
||||||
"\n// Begin state variable initialization for contract \"" <<
|
if (baseContract->constructor() && !arguments->empty())
|
||||||
contract->name() <<
|
{
|
||||||
"\" (" <<
|
vector<string> params;
|
||||||
contract->stateVariables().size() <<
|
for (size_t i = 0; i < arguments->size(); ++i)
|
||||||
" variables)\n";
|
params.emplace_back(generator.evaluateExpression(
|
||||||
|
*(arguments->at(i)),
|
||||||
IRGeneratorForStatements generator{m_context, m_utils};
|
*(baseContract->constructor()->parameters()[i]->type())
|
||||||
for (VariableDeclaration const* variable: contract->stateVariables())
|
).commaSeparatedList());
|
||||||
if (!variable->isConstant() && !variable->immutable())
|
constructorParams[baseContract] = joinHumanReadable(params);
|
||||||
generator.initializeStateVar(*variable);
|
}
|
||||||
out << generator.code();
|
|
||||||
|
|
||||||
out << "// End state variable initialization for contract \"" << contract->name() << "\".\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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());
|
vector<string> params;
|
||||||
unsigned paramVars = make_shared<TupleType>(constructor->functionType(false)->parameterTypes())->sizeOnStack();
|
for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
|
||||||
|
if (baseParams.count(contract))
|
||||||
|
params.emplace_back(baseParams.at(contract));
|
||||||
|
return joinHumanReadable(params);
|
||||||
|
};
|
||||||
|
|
||||||
Whiskers t(R"X(
|
map<ContractDefinition const*, string> baseConstructorParams;
|
||||||
let programSize := datasize("<object>")
|
for (size_t i = 0; i < _contract.annotation().linearizedBaseContracts.size(); ++i)
|
||||||
let argSize := sub(codesize(), programSize)
|
{
|
||||||
|
ContractDefinition const* contract = _contract.annotation().linearizedBaseContracts[i];
|
||||||
|
baseConstructorParams.erase(contract);
|
||||||
|
|
||||||
let memoryDataOffset := <allocate>(argSize)
|
m_context.functionCollector().createFunction(implicitConstructorName(*contract), [&]() {
|
||||||
codecopy(memoryDataOffset, programSize, argSize)
|
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))
|
return t.render();
|
||||||
|
});
|
||||||
<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 out.str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string IRGenerator::deployCode(ContractDefinition const& _contract)
|
string IRGenerator::deployCode(ContractDefinition const& _contract)
|
||||||
@ -323,6 +393,11 @@ string IRGenerator::runtimeObjectName(ContractDefinition const& _contract)
|
|||||||
return _contract.name() + "_" + to_string(_contract.id()) + "_deployed";
|
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)
|
string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
||||||
{
|
{
|
||||||
Whiskers t(R"X(
|
Whiskers t(R"X(
|
||||||
|
@ -67,12 +67,29 @@ private:
|
|||||||
/// Generates code that assigns the initial value of the respective type.
|
/// Generates code that assigns the initial value of the respective type.
|
||||||
std::string generateInitialAssignment(VariableDeclaration const& _varDecl);
|
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 deployCode(ContractDefinition const& _contract);
|
||||||
std::string callValueCheck();
|
std::string callValueCheck();
|
||||||
|
|
||||||
std::string creationObjectName(ContractDefinition const& _contract);
|
std::string creationObjectName(ContractDefinition const& _contract);
|
||||||
std::string runtimeObjectName(ContractDefinition const& _contract);
|
std::string runtimeObjectName(ContractDefinition const& _contract);
|
||||||
|
std::string implicitConstructorName(ContractDefinition const& _contract);
|
||||||
|
|
||||||
std::string dispatchRoutine(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);
|
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)
|
void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _varDeclStatement)
|
||||||
{
|
{
|
||||||
if (Expression const* expression = _varDeclStatement.initialValue())
|
if (Expression const* expression = _varDeclStatement.initialValue())
|
||||||
|
@ -51,6 +51,9 @@ public:
|
|||||||
/// Generates code to initialize the given local variable.
|
/// Generates code to initialize the given local variable.
|
||||||
void initializeLocalVar(VariableDeclaration const& _varDecl);
|
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;
|
void endVisit(VariableDeclarationStatement const& _variableDeclaration) override;
|
||||||
bool visit(Conditional const& _conditional) override;
|
bool visit(Conditional const& _conditional) override;
|
||||||
bool visit(Assignment const& _assignment) override;
|
bool visit(Assignment const& _assignment) override;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
{"contracts":{"A":{"C":{"ewasm":{"wast":"(module
|
{"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.
|
;; 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\" \"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)))
|
(import \"ethereum\" \"finish\" (func $eth.finish (param i32 i32)))
|
||||||
(memory $memory (export \"memory\") 1)
|
(memory $memory (export \"memory\") 1)
|
||||||
(export \"main\" (func $main))
|
(export \"main\" (func $main))
|
||||||
@ -9,27 +11,30 @@
|
|||||||
(local $_1 i64)
|
(local $_1 i64)
|
||||||
(local $p i64)
|
(local $p i64)
|
||||||
(local $r i64)
|
(local $r i64)
|
||||||
(local $hi i64)
|
|
||||||
(local $hi_1 i64)
|
|
||||||
(local $y i64)
|
|
||||||
(local $hi_2 i64)
|
|
||||||
(local $_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 $_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 $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)))))
|
(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
|
(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)))
|
(unreachable)))
|
||||||
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $_1)) (i64.const 16)))
|
(local.set $_2 (call $endian_swap (local.get $_1)))
|
||||||
(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)))
|
(i64.store (i32.wrap_i64 (local.get $r)) (local.get $_2))
|
||||||
(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 (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 (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 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 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 24))))) (call $endian_swap (i64.const 128)))
|
||||||
(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))
|
(call $eth.getCallValue (i32.wrap_i64 (i64.const 0)))
|
||||||
(local.set $hi_2 (i64.shl (call $endian_swap_32 (i64.const 128)) (i64.const 32)))
|
(local.set $z1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.const 0)))))
|
||||||
(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 $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 $_2 (datasize \"C_2_deployed\"))
|
(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))))))))
|
||||||
(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))))
|
(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 $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))))
|
(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
|
(func $u256_to_i32
|
||||||
@ -62,6 +67,22 @@
|
|||||||
(local.get $r)
|
(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
|
(func $endian_swap_16
|
||||||
(param $x i64)
|
(param $x i64)
|
||||||
(result i64)
|
(result i64)
|
||||||
@ -80,5 +101,39 @@
|
|||||||
(local.get $y)
|
(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}}}
|
"}}}},"sources":{"A":{"id":0}}}
|
||||||
|
@ -8,8 +8,12 @@
|
|||||||
object \"C_6\" {
|
object \"C_6\" {
|
||||||
code {
|
code {
|
||||||
mstore(64, 128)
|
mstore(64, 128)
|
||||||
|
if callvalue() { revert(0, 0) }
|
||||||
|
constructor_C_6()
|
||||||
codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))
|
codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))
|
||||||
return(0, datasize(\"C_6_deployed\"))
|
return(0, datasize(\"C_6_deployed\"))
|
||||||
|
function constructor_C_6()
|
||||||
|
{ }
|
||||||
}
|
}
|
||||||
object \"C_6_deployed\" {
|
object \"C_6_deployed\" {
|
||||||
code {
|
code {
|
||||||
|
@ -9,15 +9,21 @@
|
|||||||
object \"C_6\" {
|
object \"C_6\" {
|
||||||
code {
|
code {
|
||||||
mstore(64, 128)
|
mstore(64, 128)
|
||||||
|
if callvalue() { revert(0, 0) }
|
||||||
|
|
||||||
// Begin state variable initialization for contract \"C\" (0 variables)
|
constructor_C_6()
|
||||||
// End state variable initialization for contract \"C\".
|
|
||||||
|
|
||||||
|
|
||||||
codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))
|
codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))
|
||||||
return(0, datasize(\"C_6_deployed\"))
|
return(0, datasize(\"C_6_deployed\"))
|
||||||
|
|
||||||
|
|
||||||
|
function constructor_C_6() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
object \"C_6_deployed\" {
|
object \"C_6_deployed\" {
|
||||||
code {
|
code {
|
||||||
|
@ -9,15 +9,21 @@
|
|||||||
object \"C_10\" {
|
object \"C_10\" {
|
||||||
code {
|
code {
|
||||||
mstore(64, 128)
|
mstore(64, 128)
|
||||||
|
if callvalue() { revert(0, 0) }
|
||||||
|
|
||||||
// Begin state variable initialization for contract \"C\" (0 variables)
|
constructor_C_10()
|
||||||
// End state variable initialization for contract \"C\".
|
|
||||||
|
|
||||||
|
|
||||||
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
|
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
|
||||||
return(0, datasize(\"C_10_deployed\"))
|
return(0, datasize(\"C_10_deployed\"))
|
||||||
|
|
||||||
|
|
||||||
|
function constructor_C_10() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
object \"C_10_deployed\" {
|
object \"C_10_deployed\" {
|
||||||
code {
|
code {
|
||||||
|
@ -9,15 +9,21 @@
|
|||||||
object \"C_10\" {
|
object \"C_10\" {
|
||||||
code {
|
code {
|
||||||
mstore(64, 128)
|
mstore(64, 128)
|
||||||
|
if callvalue() { revert(0, 0) }
|
||||||
|
|
||||||
// Begin state variable initialization for contract \"C\" (0 variables)
|
constructor_C_10()
|
||||||
// End state variable initialization for contract \"C\".
|
|
||||||
|
|
||||||
|
|
||||||
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
|
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
|
||||||
return(0, datasize(\"C_10_deployed\"))
|
return(0, datasize(\"C_10_deployed\"))
|
||||||
|
|
||||||
|
|
||||||
|
function constructor_C_10() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
object \"C_10_deployed\" {
|
object \"C_10_deployed\" {
|
||||||
code {
|
code {
|
||||||
|
@ -9,15 +9,21 @@
|
|||||||
object \"C_10\" {
|
object \"C_10\" {
|
||||||
code {
|
code {
|
||||||
mstore(64, 128)
|
mstore(64, 128)
|
||||||
|
if callvalue() { revert(0, 0) }
|
||||||
|
|
||||||
// Begin state variable initialization for contract \"C\" (0 variables)
|
constructor_C_10()
|
||||||
// End state variable initialization for contract \"C\".
|
|
||||||
|
|
||||||
|
|
||||||
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
|
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
|
||||||
return(0, datasize(\"C_10_deployed\"))
|
return(0, datasize(\"C_10_deployed\"))
|
||||||
|
|
||||||
|
|
||||||
|
function constructor_C_10() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
object \"C_10_deployed\" {
|
object \"C_10_deployed\" {
|
||||||
code {
|
code {
|
||||||
|
@ -9,15 +9,21 @@
|
|||||||
object \"C_10\" {
|
object \"C_10\" {
|
||||||
code {
|
code {
|
||||||
mstore(64, 128)
|
mstore(64, 128)
|
||||||
|
if callvalue() { revert(0, 0) }
|
||||||
|
|
||||||
// Begin state variable initialization for contract \"C\" (0 variables)
|
constructor_C_10()
|
||||||
// End state variable initialization for contract \"C\".
|
|
||||||
|
|
||||||
|
|
||||||
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
|
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
|
||||||
return(0, datasize(\"C_10_deployed\"))
|
return(0, datasize(\"C_10_deployed\"))
|
||||||
|
|
||||||
|
|
||||||
|
function constructor_C_10() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
object \"C_10_deployed\" {
|
object \"C_10_deployed\" {
|
||||||
code {
|
code {
|
||||||
|
@ -9,15 +9,21 @@
|
|||||||
object \"C_10\" {
|
object \"C_10\" {
|
||||||
code {
|
code {
|
||||||
mstore(64, 128)
|
mstore(64, 128)
|
||||||
|
if callvalue() { revert(0, 0) }
|
||||||
|
|
||||||
// Begin state variable initialization for contract \"C\" (0 variables)
|
constructor_C_10()
|
||||||
// End state variable initialization for contract \"C\".
|
|
||||||
|
|
||||||
|
|
||||||
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
|
codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\"))
|
||||||
return(0, datasize(\"C_10_deployed\"))
|
return(0, datasize(\"C_10_deployed\"))
|
||||||
|
|
||||||
|
|
||||||
|
function constructor_C_10() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
object \"C_10_deployed\" {
|
object \"C_10_deployed\" {
|
||||||
code {
|
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