aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/codegen
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2019-01-22 20:49:41 +0800
committerGitHub <noreply@github.com>2019-01-22 20:49:41 +0800
commit10d17f245839f208ec5085309022a32cd2502f55 (patch)
treeb2c9f68980d0d418cd6f511e9f3f3f71369abe25 /libsolidity/codegen
parent1df8f40cd2fd7b47698d847907b8ca7b47eb488d (diff)
parent0ecafe032a84cb6960545dd7f18733430c1f782d (diff)
downloaddexon-solidity-10d17f245839f208ec5085309022a32cd2502f55.tar.gz
dexon-solidity-10d17f245839f208ec5085309022a32cd2502f55.tar.zst
dexon-solidity-10d17f245839f208ec5085309022a32cd2502f55.zip
Merge pull request #5836 from ethereum/develop
Merge develop into release for 0.5.3.
Diffstat (limited to 'libsolidity/codegen')
-rw-r--r--libsolidity/codegen/ABIFunctions.cpp101
-rw-r--r--libsolidity/codegen/ABIFunctions.h35
-rw-r--r--libsolidity/codegen/Compiler.cpp12
-rw-r--r--libsolidity/codegen/Compiler.h6
-rw-r--r--libsolidity/codegen/CompilerContext.cpp15
-rw-r--r--libsolidity/codegen/CompilerContext.h16
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp23
-rw-r--r--libsolidity/codegen/CompilerUtils.h7
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp14
-rw-r--r--libsolidity/codegen/ContractCompiler.h6
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp38
11 files changed, 183 insertions, 90 deletions
diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp
index c1ab03e3..c0fa81ce 100644
--- a/libsolidity/codegen/ABIFunctions.cpp
+++ b/libsolidity/codegen/ABIFunctions.cpp
@@ -39,14 +39,19 @@ string ABIFunctions::tupleEncoder(
bool _encodeAsLibraryTypes
)
{
+ EncodingOptions options;
+ options.encodeAsLibraryTypes = _encodeAsLibraryTypes;
+ options.encodeFunctionFromStack = true;
+ options.padded = true;
+ options.dynamicInplace = false;
+
string functionName = string("abi_encode_tuple_");
for (auto const& t: _givenTypes)
functionName += t->identifier() + "_";
functionName += "_to_";
for (auto const& t: _targetTypes)
functionName += t->identifier() + "_";
- if (_encodeAsLibraryTypes)
- functionName += "_library";
+ functionName += options.toFunctionNameSuffix();
return createExternallyUsedFunction(functionName, [&]() {
solAssert(!_givenTypes.empty(), "");
@@ -90,7 +95,7 @@ string ABIFunctions::tupleEncoder(
);
elementTempl("values", valueNames);
elementTempl("pos", to_string(headPos));
- elementTempl("abiEncode", abiEncodingFunction(*_givenTypes[i], *_targetTypes[i], _encodeAsLibraryTypes, true));
+ elementTempl("abiEncode", abiEncodingFunction(*_givenTypes[i], *_targetTypes[i], options));
encodeElements += elementTempl.render();
headPos += dynamic ? 0x20 : _targetTypes[i]->calldataEncodedSize();
}
@@ -184,6 +189,20 @@ pair<string, set<string>> ABIFunctions::requestedFunctions()
return make_pair(result, std::move(m_externallyUsedFunctions));
}
+string ABIFunctions::EncodingOptions::toFunctionNameSuffix() const
+{
+ string suffix;
+ if (!padded)
+ suffix += "_nonPadded";
+ if (dynamicInplace)
+ suffix += "_inplace";
+ if (encodeFunctionFromStack)
+ suffix += "_fromStack";
+ if (encodeAsLibraryTypes)
+ suffix += "_library";
+ return suffix;
+}
+
string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
{
string functionName = string("cleanup_") + (_revertOnFailure ? "revert_" : "assert_") + _type.identifier();
@@ -490,32 +509,31 @@ string ABIFunctions::splitExternalFunctionIdFunction()
string ABIFunctions::abiEncodingFunction(
Type const& _from,
Type const& _to,
- bool _encodeAsLibraryTypes,
- bool _fromStack
+ EncodingOptions const& _options
)
{
- TypePointer toInterface = _to.fullEncodingType(_encodeAsLibraryTypes, true, false);
+ TypePointer toInterface = _to.fullEncodingType(_options.encodeAsLibraryTypes, true, false);
solUnimplementedAssert(toInterface, "Encoding type \"" + _to.toString() + "\" not yet implemented.");
Type const& to = *toInterface;
if (_from.category() == Type::Category::StringLiteral)
- return abiEncodingFunctionStringLiteral(_from, to, _encodeAsLibraryTypes);
+ return abiEncodingFunctionStringLiteral(_from, to, _options);
else if (auto toArray = dynamic_cast<ArrayType const*>(&to))
{
solAssert(_from.category() == Type::Category::Array, "");
solAssert(to.dataStoredIn(DataLocation::Memory), "");
ArrayType const& fromArray = dynamic_cast<ArrayType const&>(_from);
if (fromArray.location() == DataLocation::CallData)
- return abiEncodingFunctionCalldataArray(fromArray, *toArray, _encodeAsLibraryTypes);
+ return abiEncodingFunctionCalldataArray(fromArray, *toArray, _options);
else if (!fromArray.isByteArray() && (
fromArray.location() == DataLocation::Memory ||
fromArray.baseType()->storageBytes() > 16
))
- return abiEncodingFunctionSimpleArray(fromArray, *toArray, _encodeAsLibraryTypes);
+ return abiEncodingFunctionSimpleArray(fromArray, *toArray, _options);
else if (fromArray.location() == DataLocation::Memory)
- return abiEncodingFunctionMemoryByteArray(fromArray, *toArray, _encodeAsLibraryTypes);
+ return abiEncodingFunctionMemoryByteArray(fromArray, *toArray, _options);
else if (fromArray.location() == DataLocation::Storage)
- return abiEncodingFunctionCompactStorageArray(fromArray, *toArray, _encodeAsLibraryTypes);
+ return abiEncodingFunctionCompactStorageArray(fromArray, *toArray, _options);
else
solAssert(false, "");
}
@@ -523,14 +541,13 @@ string ABIFunctions::abiEncodingFunction(
{
StructType const* fromStruct = dynamic_cast<StructType const*>(&_from);
solAssert(fromStruct, "");
- return abiEncodingFunctionStruct(*fromStruct, *toStruct, _encodeAsLibraryTypes);
+ return abiEncodingFunctionStruct(*fromStruct, *toStruct, _options);
}
else if (_from.category() == Type::Category::Function)
return abiEncodingFunctionFunctionType(
dynamic_cast<FunctionType const&>(_from),
to,
- _encodeAsLibraryTypes,
- _fromStack
+ _options
);
solAssert(_from.sizeOnStack() == 1, "");
@@ -541,7 +558,7 @@ string ABIFunctions::abiEncodingFunction(
_from.identifier() +
"_to_" +
to.identifier() +
- (_encodeAsLibraryTypes ? "_library" : "");
+ _options.toFunctionNameSuffix();
return createFunction(functionName, [&]() {
solAssert(!to.isDynamicallyEncoded(), "");
@@ -556,7 +573,7 @@ string ABIFunctions::abiEncodingFunction(
{
// special case: convert storage reference type to value type - this is only
// possible for library calls where we just forward the storage reference
- solAssert(_encodeAsLibraryTypes, "");
+ solAssert(_options.encodeAsLibraryTypes, "");
solAssert(to == IntegerType::uint256(), "");
templ("cleanupConvert", "value");
}
@@ -574,7 +591,7 @@ string ABIFunctions::abiEncodingFunction(
string ABIFunctions::abiEncodingFunctionCalldataArray(
Type const& _from,
Type const& _to,
- bool _encodeAsLibraryTypes
+ EncodingOptions const& _options
)
{
solAssert(_to.isDynamicallySized(), "");
@@ -596,7 +613,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArray(
_from.identifier() +
"_to_" +
_to.identifier() +
- (_encodeAsLibraryTypes ? "_library" : "");
+ _options.toFunctionNameSuffix();
return createFunction(functionName, [&]() {
solUnimplementedAssert(fromArrayType.isByteArray(), "Only byte arrays can be encoded from calldata currently.");
// TODO if this is not a byte array, we might just copy byte-by-byte anyway,
@@ -622,7 +639,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArray(
string ABIFunctions::abiEncodingFunctionSimpleArray(
ArrayType const& _from,
ArrayType const& _to,
- bool _encodeAsLibraryTypes
+ EncodingOptions const& _options
)
{
string functionName =
@@ -630,7 +647,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
_from.identifier() +
"_to_" +
_to.identifier() +
- (_encodeAsLibraryTypes ? "_library" : "");
+ _options.toFunctionNameSuffix();
solAssert(_from.isDynamicallySized() == _to.isDynamicallySized(), "");
solAssert(_from.length() == _to.length(), "");
@@ -691,11 +708,13 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
templ("storeLength", "");
templ("dataAreaFun", arrayDataAreaFunction(_from));
templ("elementEncodedSize", toCompactHexWithPrefix(_to.baseType()->calldataEncodedSize()));
+
+ EncodingOptions subOptions(_options);
+ subOptions.encodeFunctionFromStack = false;
templ("encodeToMemoryFun", abiEncodingFunction(
*_from.baseType(),
*_to.baseType(),
- _encodeAsLibraryTypes,
- false
+ subOptions
));
templ("arrayElementAccess", inMemory ? "mload(srcPtr)" : _from.baseType()->isValueType() ? "sload(srcPtr)" : "srcPtr" );
templ("nextArrayElement", nextArrayElementFunction(_from));
@@ -706,7 +725,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
string ABIFunctions::abiEncodingFunctionMemoryByteArray(
ArrayType const& _from,
ArrayType const& _to,
- bool _encodeAsLibraryTypes
+ EncodingOptions const& _options
)
{
string functionName =
@@ -714,7 +733,7 @@ string ABIFunctions::abiEncodingFunctionMemoryByteArray(
_from.identifier() +
"_to_" +
_to.identifier() +
- (_encodeAsLibraryTypes ? "_library" : "");
+ _options.toFunctionNameSuffix();
solAssert(_from.isDynamicallySized() == _to.isDynamicallySized(), "");
solAssert(_from.length() == _to.length(), "");
@@ -742,7 +761,7 @@ string ABIFunctions::abiEncodingFunctionMemoryByteArray(
string ABIFunctions::abiEncodingFunctionCompactStorageArray(
ArrayType const& _from,
ArrayType const& _to,
- bool _encodeAsLibraryTypes
+ EncodingOptions const& _options
)
{
string functionName =
@@ -750,7 +769,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
_from.identifier() +
"_to_" +
_to.identifier() +
- (_encodeAsLibraryTypes ? "_library" : "");
+ _options.toFunctionNameSuffix();
solAssert(_from.isDynamicallySized() == _to.isDynamicallySized(), "");
solAssert(_from.length() == _to.length(), "");
@@ -840,11 +859,13 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
templ("itemsPerSlot", to_string(itemsPerSlot));
string elementEncodedSize = toCompactHexWithPrefix(_to.baseType()->calldataEncodedSize());
templ("elementEncodedSize", elementEncodedSize);
+
+ EncodingOptions subOptions(_options);
+ subOptions.encodeFunctionFromStack = false;
string encodeToMemoryFun = abiEncodingFunction(
*_from.baseType(),
*_to.baseType(),
- _encodeAsLibraryTypes,
- false
+ subOptions
);
templ("encodeToMemoryFun", encodeToMemoryFun);
std::vector<std::map<std::string, std::string>> items(itemsPerSlot);
@@ -859,7 +880,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
string ABIFunctions::abiEncodingFunctionStruct(
StructType const& _from,
StructType const& _to,
- bool _encodeAsLibraryTypes
+ EncodingOptions const& _options
)
{
string functionName =
@@ -867,7 +888,7 @@ string ABIFunctions::abiEncodingFunctionStruct(
_from.identifier() +
"_to_" +
_to.identifier() +
- (_encodeAsLibraryTypes ? "_library" : "");
+ _options.toFunctionNameSuffix();
solUnimplementedAssert(!_from.dataStoredIn(DataLocation::CallData), "Encoding struct from calldata is not yet supported.");
solAssert(&_from.structDefinition() == &_to.structDefinition(), "");
@@ -904,7 +925,7 @@ string ABIFunctions::abiEncodingFunctionStruct(
solAssert(member.type, "");
if (!member.type->canLiveOutsideStorage())
continue;
- TypePointer memberTypeTo = member.type->fullEncodingType(_encodeAsLibraryTypes, true, false);
+ TypePointer memberTypeTo = member.type->fullEncodingType(_options.encodeAsLibraryTypes, true, false);
solUnimplementedAssert(memberTypeTo, "Encoding type \"" + member.type->toString() + "\" not yet implemented.");
auto memberTypeFrom = _from.memberType(member.name);
solAssert(memberTypeFrom, "");
@@ -958,7 +979,10 @@ string ABIFunctions::abiEncodingFunctionStruct(
}
memberTempl("encodingOffset", toCompactHexWithPrefix(encodingOffset));
encodingOffset += dynamicMember ? 0x20 : memberTypeTo->calldataEncodedSize();
- memberTempl("abiEncode", abiEncodingFunction(*memberTypeFrom, *memberTypeTo, _encodeAsLibraryTypes, false));
+
+ EncodingOptions subOptions(_options);
+ subOptions.encodeFunctionFromStack = false;
+ memberTempl("abiEncode", abiEncodingFunction(*memberTypeFrom, *memberTypeTo, subOptions));
members.push_back({});
members.back()["encode"] = memberTempl.render();
@@ -973,7 +997,7 @@ string ABIFunctions::abiEncodingFunctionStruct(
string ABIFunctions::abiEncodingFunctionStringLiteral(
Type const& _from,
Type const& _to,
- bool _encodeAsLibraryTypes
+ EncodingOptions const& _options
)
{
solAssert(_from.category() == Type::Category::StringLiteral, "");
@@ -983,7 +1007,7 @@ string ABIFunctions::abiEncodingFunctionStringLiteral(
_from.identifier() +
"_to_" +
_to.identifier() +
- (_encodeAsLibraryTypes ? "_library" : "");
+ _options.toFunctionNameSuffix();
return createFunction(functionName, [&]() {
auto const& strType = dynamic_cast<StringLiteralType const&>(_from);
string const& value = strType.value();
@@ -1034,8 +1058,7 @@ string ABIFunctions::abiEncodingFunctionStringLiteral(
string ABIFunctions::abiEncodingFunctionFunctionType(
FunctionType const& _from,
Type const& _to,
- bool _encodeAsLibraryTypes,
- bool _fromStack
+ EncodingOptions const& _options
)
{
solAssert(_from.kind() == FunctionType::Kind::External, "");
@@ -1046,10 +1069,9 @@ string ABIFunctions::abiEncodingFunctionFunctionType(
_from.identifier() +
"_to_" +
_to.identifier() +
- (_fromStack ? "_fromStack" : "") +
- (_encodeAsLibraryTypes ? "_library" : "");
+ _options.toFunctionNameSuffix();
- if (_fromStack)
+ if (_options.encodeFunctionFromStack)
return createFunction(functionName, [&]() {
return Whiskers(R"(
function <functionName>(addr, function_id, pos) {
@@ -1716,3 +1738,4 @@ size_t ABIFunctions::headSize(TypePointers const& _targetTypes)
return headSize;
}
+
diff --git a/libsolidity/codegen/ABIFunctions.h b/libsolidity/codegen/ABIFunctions.h
index 1e0cf7fa..c5443236 100644
--- a/libsolidity/codegen/ABIFunctions.h
+++ b/libsolidity/codegen/ABIFunctions.h
@@ -87,6 +87,23 @@ public:
std::pair<std::string, std::set<std::string>> requestedFunctions();
private:
+ struct EncodingOptions
+ {
+ /// Pad/signextend value types and bytes/string to multiples of 32 bytes.
+ bool padded = true;
+ /// Store arrays and structs in place without "data pointer" and do not store the length.
+ bool dynamicInplace = false;
+ /// Only for external function types: The value is a pair of address / function id instead
+ /// of a memory pointer to the compression representation.
+ bool encodeFunctionFromStack = false;
+ /// Encode storage pointers as storage pointers (we are targeting a library call).
+ bool encodeAsLibraryTypes = false;
+
+ /// @returns a string to uniquely identify the encoding options for the encoding
+ /// function name. Skips everything that has its default value.
+ std::string toFunctionNameSuffix() const;
+ };
+
/// @returns the name of the cleanup function for the given type and
/// adds its implementation to the requested functions.
/// @param _revertOnFailure if true, causes revert on invalid data,
@@ -115,40 +132,39 @@ private:
std::string abiEncodingFunction(
Type const& _givenType,
Type const& _targetType,
- bool _encodeAsLibraryTypes,
- bool _fromStack
+ EncodingOptions const& _options
);
/// Part of @a abiEncodingFunction for array target type and given calldata array.
std::string abiEncodingFunctionCalldataArray(
Type const& _givenType,
Type const& _targetType,
- bool _encodeAsLibraryTypes
+ EncodingOptions const& _options
);
/// Part of @a abiEncodingFunction for array target type and given memory array or
/// a given storage array with one item per slot.
std::string abiEncodingFunctionSimpleArray(
ArrayType const& _givenType,
ArrayType const& _targetType,
- bool _encodeAsLibraryTypes
+ EncodingOptions const& _options
);
std::string abiEncodingFunctionMemoryByteArray(
ArrayType const& _givenType,
ArrayType const& _targetType,
- bool _encodeAsLibraryTypes
+ EncodingOptions const& _options
);
/// Part of @a abiEncodingFunction for array target type and given storage array
/// where multiple items are packed into the same storage slot.
std::string abiEncodingFunctionCompactStorageArray(
ArrayType const& _givenType,
ArrayType const& _targetType,
- bool _encodeAsLibraryTypes
+ EncodingOptions const& _options
);
/// Part of @a abiEncodingFunction for struct types.
std::string abiEncodingFunctionStruct(
StructType const& _givenType,
StructType const& _targetType,
- bool _encodeAsLibraryTypes
+ EncodingOptions const& _options
);
// @returns the name of the ABI encoding function with the given type
@@ -157,14 +173,13 @@ private:
std::string abiEncodingFunctionStringLiteral(
Type const& _givenType,
Type const& _targetType,
- bool _encodeAsLibraryTypes
+ EncodingOptions const& _options
);
std::string abiEncodingFunctionFunctionType(
FunctionType const& _from,
Type const& _to,
- bool _encodeAsLibraryTypes,
- bool _fromStack
+ EncodingOptions const& _options
);
/// @returns the name of the ABI decoding function for the given type
diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp
index a22e6e9d..72efed33 100644
--- a/libsolidity/codegen/Compiler.cpp
+++ b/libsolidity/codegen/Compiler.cpp
@@ -31,22 +31,28 @@ using namespace dev::solidity;
void Compiler::compileContract(
ContractDefinition const& _contract,
- std::map<const ContractDefinition*, eth::Assembly const*> const& _contracts,
+ std::map<ContractDefinition const*, shared_ptr<Compiler const>> const& _otherCompilers,
bytes const& _metadata
)
{
ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimize, m_optimizeRuns);
- runtimeCompiler.compileContract(_contract, _contracts);
+ runtimeCompiler.compileContract(_contract, _otherCompilers);
m_runtimeContext.appendAuxiliaryData(_metadata);
// This might modify m_runtimeContext because it can access runtime functions at
// creation time.
ContractCompiler creationCompiler(&runtimeCompiler, m_context, m_optimize, 1);
- m_runtimeSub = creationCompiler.compileConstructor(_contract, _contracts);
+ m_runtimeSub = creationCompiler.compileConstructor(_contract, _otherCompilers);
m_context.optimise(m_optimize, m_optimizeRuns);
}
+std::shared_ptr<eth::Assembly> Compiler::runtimeAssemblyPtr() const
+{
+ solAssert(m_context.runtimeContext(), "");
+ return m_context.runtimeContext()->assemblyPtr();
+}
+
eth::AssemblyItem Compiler::functionEntryLabel(FunctionDefinition const& _function) const
{
return m_runtimeContext.functionEntryLabelIfExists(_function);
diff --git a/libsolidity/codegen/Compiler.h b/libsolidity/codegen/Compiler.h
index 784d7f8c..c21de96d 100644
--- a/libsolidity/codegen/Compiler.h
+++ b/libsolidity/codegen/Compiler.h
@@ -45,11 +45,15 @@ public:
/// @arg _metadata contains the to be injected metadata CBOR
void compileContract(
ContractDefinition const& _contract,
- std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts,
+ std::map<ContractDefinition const*, std::shared_ptr<Compiler const>> const& _otherCompilers,
bytes const& _metadata
);
/// @returns Entire assembly.
eth::Assembly const& assembly() const { return m_context.assembly(); }
+ /// @returns Entire assembly as a shared pointer to non-const.
+ std::shared_ptr<eth::Assembly> assemblyPtr() const { return m_context.assemblyPtr(); }
+ /// @returns Runtime assembly.
+ std::shared_ptr<eth::Assembly> runtimeAssemblyPtr() const;
/// @returns The entire assembled object (with constructor).
eth::LinkerObject assembledObject() const { return m_context.assembledObject(); }
/// @returns Only the runtime object (without constructor).
diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp
index be681b2e..861b1c98 100644
--- a/libsolidity/codegen/CompilerContext.cpp
+++ b/libsolidity/codegen/CompilerContext.cpp
@@ -167,11 +167,18 @@ unsigned CompilerContext::numberOfLocalVariables() const
return m_localVariables.size();
}
-eth::Assembly const& CompilerContext::compiledContract(const ContractDefinition& _contract) const
+shared_ptr<eth::Assembly> CompilerContext::compiledContract(ContractDefinition const& _contract) const
{
- auto ret = m_compiledContracts.find(&_contract);
- solAssert(ret != m_compiledContracts.end(), "Compiled contract not found.");
- return *ret->second;
+ auto ret = m_otherCompilers.find(&_contract);
+ solAssert(ret != m_otherCompilers.end(), "Compiled contract not found.");
+ return ret->second->assemblyPtr();
+}
+
+shared_ptr<eth::Assembly> CompilerContext::compiledContractRuntime(ContractDefinition const& _contract) const
+{
+ auto ret = m_otherCompilers.find(&_contract);
+ solAssert(ret != m_otherCompilers.end(), "Compiled contract not found.");
+ return ret->second->runtimeAssemblyPtr();
}
bool CompilerContext::isLocalVariable(Declaration const* _declaration) const
diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h
index dedcd95f..e5ddfbc5 100644
--- a/libsolidity/codegen/CompilerContext.h
+++ b/libsolidity/codegen/CompilerContext.h
@@ -41,6 +41,7 @@
namespace dev {
namespace solidity {
+class Compiler;
/**
* Context to be shared by all units that compile the same contract.
@@ -74,8 +75,9 @@ public:
/// Returns the number of currently allocated local variables.
unsigned numberOfLocalVariables() const;
- void setCompiledContracts(std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts) { m_compiledContracts = _contracts; }
- eth::Assembly const& compiledContract(ContractDefinition const& _contract) const;
+ void setOtherCompilers(std::map<ContractDefinition const*, std::shared_ptr<Compiler const>> const& _otherCompilers) { m_otherCompilers = _otherCompilers; }
+ std::shared_ptr<eth::Assembly> compiledContract(ContractDefinition const& _contract) const;
+ std::shared_ptr<eth::Assembly> compiledContractRuntime(ContractDefinition const& _contract) const;
void setStackOffset(int _offset) { m_asm->setDeposit(_offset); }
void adjustStackOffset(int _adjustment) { m_asm->adjustDeposit(_adjustment); }
@@ -222,15 +224,15 @@ public:
void optimise(bool _fullOptimsation, unsigned _runs = 200) { m_asm->optimise(_fullOptimsation, m_evmVersion, true, _runs); }
/// @returns the runtime context if in creation mode and runtime context is set, nullptr otherwise.
- CompilerContext* runtimeContext() { return m_runtimeContext; }
+ CompilerContext* runtimeContext() const { return m_runtimeContext; }
/// @returns the identifier of the runtime subroutine.
size_t runtimeSub() const { return m_runtimeSub; }
/// @returns a const reference to the underlying assembly.
eth::Assembly const& assembly() const { return *m_asm; }
- /// @returns non-const reference to the underlying assembly. Should be avoided in favour of
- /// wrappers in this class.
- eth::Assembly& nonConstAssembly() { return *m_asm; }
+ /// @returns a shared pointer to the assembly.
+ /// Should be avoided except when adding sub-assemblies.
+ std::shared_ptr<eth::Assembly> assemblyPtr() const { return m_asm; }
/// @arg _sourceCodes is the map of input files to source code strings
std::string assemblyString(StringMap const& _sourceCodes = StringMap()) const
@@ -307,7 +309,7 @@ private:
/// Activated experimental features.
std::set<ExperimentalFeature> m_experimentalFeatures;
/// Other already compiled contracts to be used in contract creation calls.
- std::map<ContractDefinition const*, eth::Assembly const*> m_compiledContracts;
+ std::map<ContractDefinition const*, std::shared_ptr<Compiler const>> m_otherCompilers;
/// Storage offsets of state variables
std::map<Declaration const*, std::pair<u256, unsigned>> m_stateVariables;
/// Offsets of local variables on the stack (relative to stack base).
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index bbc703c7..6cfb0777 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -1199,6 +1199,29 @@ void CompilerUtils::computeHashStatic()
m_context << u256(32) << u256(0) << Instruction::KECCAK256;
}
+void CompilerUtils::copyContractCodeToMemory(ContractDefinition const& contract, bool _creation)
+{
+ string which = _creation ? "Creation" : "Runtime";
+ m_context.callLowLevelFunction(
+ "$copyContract" + which + "CodeToMemory_" + contract.type()->identifier(),
+ 1,
+ 1,
+ [&contract, _creation](CompilerContext& _context)
+ {
+ // copy the contract's code into memory
+ shared_ptr<eth::Assembly> assembly =
+ _creation ?
+ _context.compiledContract(contract) :
+ _context.compiledContractRuntime(contract);
+ // pushes size
+ auto subroutine = _context.addSubroutine(assembly);
+ _context << Instruction::DUP1 << subroutine;
+ _context << Instruction::DUP4 << Instruction::CODECOPY;
+ _context << Instruction::ADD;
+ }
+ );
+}
+
void CompilerUtils::storeStringData(bytesConstRef _data)
{
//@todo provide both alternatives to the optimiser
diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h
index 7e4f47ba..6bde2e8b 100644
--- a/libsolidity/codegen/CompilerUtils.h
+++ b/libsolidity/codegen/CompilerUtils.h
@@ -263,6 +263,13 @@ public:
/// Appends code that computes the Keccak-256 hash of the topmost stack element of 32 byte type.
void computeHashStatic();
+ /// Apppends code that copies the code of the given contract to memory.
+ /// Stack pre: Memory position
+ /// Stack post: Updated memory position
+ /// @param creation if true, copies creation code, if false copies runtime code.
+ /// @note the contract has to be compiled already, so beware of cyclic dependencies!
+ void copyContractCodeToMemory(ContractDefinition const& contract, bool _creationCode);
+
/// Bytes we need to the start of call data.
/// - The size in bytes of the function (hash) identifier.
static const unsigned dataStartOffset;
diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp
index b051d260..f843e07a 100644
--- a/libsolidity/codegen/ContractCompiler.cpp
+++ b/libsolidity/codegen/ContractCompiler.cpp
@@ -60,7 +60,7 @@ private:
void ContractCompiler::compileContract(
ContractDefinition const& _contract,
- std::map<const ContractDefinition*, eth::Assembly const*> const& _contracts
+ map<ContractDefinition const*, shared_ptr<Compiler const>> const& _otherCompilers
)
{
CompilerContext::LocationSetter locationSetter(m_context, _contract);
@@ -70,7 +70,7 @@ void ContractCompiler::compileContract(
// This has to be the first code in the contract.
appendDelegatecallCheck();
- initializeContext(_contract, _contracts);
+ initializeContext(_contract, _otherCompilers);
// This generates the dispatch function for externally visible functions
// and adds the function to the compilation queue. Additionally internal functions,
// which are referenced directly or indirectly will be added.
@@ -81,7 +81,7 @@ void ContractCompiler::compileContract(
size_t ContractCompiler::compileConstructor(
ContractDefinition const& _contract,
- std::map<const ContractDefinition*, eth::Assembly const*> const& _contracts
+ std::map<ContractDefinition const*, shared_ptr<Compiler const>> const& _otherCompilers
)
{
CompilerContext::LocationSetter locationSetter(m_context, _contract);
@@ -89,18 +89,18 @@ size_t ContractCompiler::compileConstructor(
return deployLibrary(_contract);
else
{
- initializeContext(_contract, _contracts);
+ initializeContext(_contract, _otherCompilers);
return packIntoContractCreator(_contract);
}
}
void ContractCompiler::initializeContext(
ContractDefinition const& _contract,
- map<ContractDefinition const*, eth::Assembly const*> const& _compiledContracts
+ map<ContractDefinition const*, shared_ptr<Compiler const>> const& _otherCompilers
)
{
m_context.setExperimentalFeatures(_contract.sourceUnit().annotation().experimentalFeatures);
- m_context.setCompiledContracts(_compiledContracts);
+ m_context.setOtherCompilers(_otherCompilers);
m_context.setInheritanceHierarchy(_contract.annotation().linearizedBaseContracts);
CompilerUtils(m_context).initialiseFreeMemoryPointer();
registerStateVariables(_contract);
@@ -716,7 +716,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
CodeGenerator::assemble(
_inlineAssembly.operations(),
*_inlineAssembly.annotation().analysisInfo,
- m_context.nonConstAssembly(),
+ *m_context.assemblyPtr(),
identifierAccess
);
m_context.setStackOffset(startStackHeight);
diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h
index 40871f0d..9ab006f6 100644
--- a/libsolidity/codegen/ContractCompiler.h
+++ b/libsolidity/codegen/ContractCompiler.h
@@ -49,13 +49,13 @@ public:
void compileContract(
ContractDefinition const& _contract,
- std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts
+ std::map<ContractDefinition const*, std::shared_ptr<Compiler const>> const& _otherCompilers
);
/// Compiles the constructor part of the contract.
/// @returns the identifier of the runtime sub-assembly.
size_t compileConstructor(
ContractDefinition const& _contract,
- std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts
+ std::map<ContractDefinition const*, std::shared_ptr<Compiler const>> const& _otherCompilers
);
private:
@@ -63,7 +63,7 @@ private:
/// information about the contract like the AST annotations.
void initializeContext(
ContractDefinition const& _contract,
- std::map<ContractDefinition const*, eth::Assembly const*> const& _compiledContracts
+ std::map<ContractDefinition const*, std::shared_ptr<Compiler const>> const& _otherCompilers
);
/// Adds the code that is run at creation time. Should be run after exchanging the run-time context
/// with a new and initialized context. Adds the constructor code.
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index be2709ae..e6bb163d 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -594,22 +594,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
}
ContractDefinition const* contract =
&dynamic_cast<ContractType const&>(*function.returnParameterTypes().front()).contractDefinition();
- m_context.callLowLevelFunction(
- "$copyContractCreationCodeToMemory_" + contract->type()->identifier(),
- 0,
- 1,
- [contract](CompilerContext& _context)
- {
- // copy the contract's code into memory
- eth::Assembly const& assembly = _context.compiledContract(*contract);
- CompilerUtils(_context).fetchFreeMemoryPointer();
- // pushes size
- auto subroutine = _context.addSubroutine(make_shared<eth::Assembly>(assembly));
- _context << Instruction::DUP1 << subroutine;
- _context << Instruction::DUP4 << Instruction::CODECOPY;
- _context << Instruction::ADD;
- }
- );
+ utils().fetchFreeMemoryPointer();
+ utils().copyContractCodeToMemory(*contract, true);
utils().abiEncode(argumentTypes, function.parameterTypes());
// now on stack: memory_end_ptr
// need: size, offset, endowment
@@ -1107,6 +1093,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::GasLeft:
m_context << Instruction::GAS;
break;
+ case FunctionType::Kind::MetaType:
+ // No code to generate.
+ break;
}
}
return false;
@@ -1348,6 +1337,23 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
solAssert(false, "Gas has been removed.");
else if (member == "blockhash")
solAssert(false, "Blockhash has been removed.");
+ else if (member == "creationCode" || member == "runtimeCode")
+ {
+ TypePointer arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
+ ContractDefinition const& contract = dynamic_cast<ContractType const&>(*arg).contractDefinition();
+ utils().fetchFreeMemoryPointer();
+ m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
+ utils().copyContractCodeToMemory(contract, member == "creationCode");
+ // Stack: start end
+ m_context.appendInlineAssembly(
+ Whiskers(R"({
+ mstore(start, sub(end, add(start, 0x20)))
+ mstore(<free>, end)
+ })")("free", to_string(CompilerUtils::freeMemoryPointer)).render(),
+ {"start", "end"}
+ );
+ m_context << Instruction::POP;
+ }
else
solAssert(false, "Unknown magic member.");
break;