aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libevmasm/Assembly.cpp11
-rw-r--r--libevmasm/Assembly.h3
-rw-r--r--libjulia/backends/evm/AbstractAssembly.h2
-rw-r--r--libjulia/backends/evm/EVMAssembly.cpp8
-rw-r--r--libjulia/backends/evm/EVMAssembly.h3
-rw-r--r--libjulia/backends/evm/EVMCodeTransform.cpp30
-rw-r--r--libjulia/backends/evm/EVMCodeTransform.h9
-rw-r--r--libsolidity/codegen/CompilerContext.cpp16
-rw-r--r--libsolidity/codegen/CompilerContext.h5
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp2
-rw-r--r--libsolidity/inlineasm/AsmCodeGen.cpp16
-rw-r--r--libsolidity/inlineasm/AsmCodeGen.h3
-rw-r--r--test/libsolidity/ABIEncoderTests.cpp28
13 files changed, 108 insertions, 28 deletions
diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp
index 6b4bb52b..31857c09 100644
--- a/libevmasm/Assembly.cpp
+++ b/libevmasm/Assembly.cpp
@@ -49,6 +49,8 @@ void Assembly::append(Assembly const& _a)
}
m_deposit = newDeposit;
m_usedTags += _a.m_usedTags;
+ // This does not transfer the names of named tags on purpose. The tags themselves are
+ // transferred, but their names are only available inside the assembly.
for (auto const& i: _a.m_data)
m_data.insert(i);
for (auto const& i: _a.m_strings)
@@ -326,6 +328,14 @@ AssemblyItem const& Assembly::append(AssemblyItem const& _i)
return back();
}
+AssemblyItem Assembly::namedTag(string const& _name)
+{
+ assertThrow(!_name.empty(), AssemblyException, "");
+ if (!m_namedTags.count(_name))
+ m_namedTags[_name] = size_t(newTag().data());
+ return AssemblyItem(Tag, m_namedTags.at(_name));
+}
+
AssemblyItem Assembly::newPushLibraryAddress(string const& _identifier)
{
h256 h(dev::keccak256(_identifier));
@@ -581,6 +591,7 @@ LinkerObject const& Assembly::assemble() const
assertThrow(i.data() != 0, AssemblyException, "");
assertThrow(i.splitForeignPushTag().first == size_t(-1), AssemblyException, "Foreign tag.");
assertThrow(ret.bytecode.size() < 0xffffffffL, AssemblyException, "Tag too large.");
+ assertThrow(m_tagPositionsInBytecode[size_t(i.data())] == size_t(-1), AssemblyException, "Duplicate tag position.");
m_tagPositionsInBytecode[size_t(i.data())] = ret.bytecode.size();
ret.bytecode.push_back((byte)Instruction::JUMPDEST);
break;
diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h
index cbdd71bc..885192e4 100644
--- a/libevmasm/Assembly.h
+++ b/libevmasm/Assembly.h
@@ -47,6 +47,8 @@ public:
AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); }
AssemblyItem newPushTag() { return AssemblyItem(PushTag, m_usedTags++); }
+ /// Returns a tag identified by the given name. Creates it if it does not yet exist.
+ AssemblyItem namedTag(std::string const& _name);
AssemblyItem newData(bytes const& _data) { h256 h(dev::keccak256(asString(_data))); m_data[h] = _data; return AssemblyItem(PushData, h); }
AssemblyItem newSub(AssemblyPointer const& _sub) { m_subs.push_back(_sub); return AssemblyItem(PushSub, m_subs.size() - 1); }
Assembly const& sub(size_t _sub) const { return *m_subs.at(_sub); }
@@ -150,6 +152,7 @@ private:
protected:
/// 0 is reserved for exception
unsigned m_usedTags = 1;
+ std::map<std::string, size_t> m_namedTags;
AssemblyItems m_items;
std::map<h256, bytes> m_data;
/// Data that is appended to the very end of the contract.
diff --git a/libjulia/backends/evm/AbstractAssembly.h b/libjulia/backends/evm/AbstractAssembly.h
index cfc9b8a5..8e90a912 100644
--- a/libjulia/backends/evm/AbstractAssembly.h
+++ b/libjulia/backends/evm/AbstractAssembly.h
@@ -66,6 +66,8 @@ public:
virtual void appendLabelReference(LabelID _labelId) = 0;
/// Generate a new unique label.
virtual LabelID newLabelId() = 0;
+ /// Returns a label identified by the given name. Creates it if it does not yet exist.
+ virtual LabelID namedLabel(std::string const& _name) = 0;
/// Append a reference to a to-be-linked symobl.
/// Currently, we assume that the value is always a 20 byte number.
virtual void appendLinkerSymbol(std::string const& _name) = 0;
diff --git a/libjulia/backends/evm/EVMAssembly.cpp b/libjulia/backends/evm/EVMAssembly.cpp
index 173d5e93..1d499b20 100644
--- a/libjulia/backends/evm/EVMAssembly.cpp
+++ b/libjulia/backends/evm/EVMAssembly.cpp
@@ -77,6 +77,14 @@ EVMAssembly::LabelID EVMAssembly::newLabelId()
return m_nextLabelId++;
}
+AbstractAssembly::LabelID EVMAssembly::namedLabel(string const& _name)
+{
+ solAssert(!_name.empty(), "");
+ if (!m_namedLabels.count(_name))
+ m_namedLabels[_name] = newLabelId();
+ return m_namedLabels[_name];
+}
+
void EVMAssembly::appendLinkerSymbol(string const&)
{
solAssert(false, "Linker symbols not yet implemented.");
diff --git a/libjulia/backends/evm/EVMAssembly.h b/libjulia/backends/evm/EVMAssembly.h
index 69585822..593cee6a 100644
--- a/libjulia/backends/evm/EVMAssembly.h
+++ b/libjulia/backends/evm/EVMAssembly.h
@@ -52,6 +52,8 @@ public:
virtual void appendLabelReference(LabelID _labelId) override;
/// Generate a new unique label.
virtual LabelID newLabelId() override;
+ /// Returns a label identified by the given name. Creates it if it does not yet exist.
+ virtual LabelID namedLabel(std::string const& _name) override;
/// Append a reference to a to-be-linked symobl.
/// Currently, we assume that the value is always a 20 byte number.
virtual void appendLinkerSymbol(std::string const& _name) override;
@@ -85,6 +87,7 @@ private:
LabelID m_nextLabelId = 0;
int m_stackHeight = 0;
bytes m_bytecode;
+ std::map<std::string, LabelID> m_namedLabels;
std::map<LabelID, size_t> m_labelPositions;
std::map<size_t, LabelID> m_labelReferences;
std::vector<size_t> m_assemblySizePositions;
diff --git a/libjulia/backends/evm/EVMCodeTransform.cpp b/libjulia/backends/evm/EVMCodeTransform.cpp
index 704aa3c1..e0b11cf3 100644
--- a/libjulia/backends/evm/EVMCodeTransform.cpp
+++ b/libjulia/backends/evm/EVMCodeTransform.cpp
@@ -108,10 +108,10 @@ void CodeTransform::operator()(FunctionCall const& _call)
visitExpression(arg);
m_assembly.setSourceLocation(_call.location);
if (m_evm15)
- m_assembly.appendJumpsub(functionEntryID(*function), function->arguments.size(), function->returns.size());
+ m_assembly.appendJumpsub(functionEntryID(_call.functionName.name, *function), function->arguments.size(), function->returns.size());
else
{
- m_assembly.appendJumpTo(functionEntryID(*function), function->returns.size() - function->arguments.size() - 1);
+ m_assembly.appendJumpTo(functionEntryID(_call.functionName.name, *function), function->returns.size() - function->arguments.size() - 1);
m_assembly.appendLabel(returnLabel);
m_stackAdjustment--;
}
@@ -286,12 +286,12 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
if (m_evm15)
{
m_assembly.appendJumpTo(afterFunction, -stackHeightBefore);
- m_assembly.appendBeginsub(functionEntryID(function), _function.arguments.size());
+ m_assembly.appendBeginsub(functionEntryID(_function.name, function), _function.arguments.size());
}
else
{
m_assembly.appendJumpTo(afterFunction, -stackHeightBefore + height);
- m_assembly.appendLabel(functionEntryID(function));
+ m_assembly.appendLabel(functionEntryID(_function.name, function));
}
m_stackAdjustment += localStackAdjustment;
@@ -303,8 +303,16 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
m_assembly.appendConstant(u256(0));
}
- CodeTransform(m_assembly, m_info, m_julia, m_evm15, m_identifierAccess, localStackAdjustment, m_context)
- (_function.body);
+ CodeTransform(
+ m_assembly,
+ m_info,
+ m_julia,
+ m_evm15,
+ m_identifierAccess,
+ m_useNamedLabelsForFunctions,
+ localStackAdjustment,
+ m_context
+ )(_function.body);
{
// The stack layout here is:
@@ -421,10 +429,16 @@ AbstractAssembly::LabelID CodeTransform::labelID(Scope::Label const& _label)
return m_context->labelIDs[&_label];
}
-AbstractAssembly::LabelID CodeTransform::functionEntryID(Scope::Function const& _function)
+AbstractAssembly::LabelID CodeTransform::functionEntryID(string const& _name, Scope::Function const& _function)
{
if (!m_context->functionEntryIDs.count(&_function))
- m_context->functionEntryIDs[&_function] = m_assembly.newLabelId();
+ {
+ AbstractAssembly::LabelID id =
+ m_useNamedLabelsForFunctions ?
+ m_assembly.namedLabel(_name) :
+ m_assembly.newLabelId();
+ m_context->functionEntryIDs[&_function] = id;
+ }
return m_context->functionEntryIDs[&_function];
}
diff --git a/libjulia/backends/evm/EVMCodeTransform.h b/libjulia/backends/evm/EVMCodeTransform.h
index cd452c5b..2c0fd10c 100644
--- a/libjulia/backends/evm/EVMCodeTransform.h
+++ b/libjulia/backends/evm/EVMCodeTransform.h
@@ -50,13 +50,15 @@ public:
solidity::assembly::AsmAnalysisInfo& _analysisInfo,
bool _julia = false,
bool _evm15 = false,
- ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess()
+ ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess(),
+ bool _useNamedLabelsForFunctions = false
): CodeTransform(
_assembly,
_analysisInfo,
_julia,
_evm15,
_identifierAccess,
+ _useNamedLabelsForFunctions,
_assembly.stackHeight(),
std::make_shared<Context>()
)
@@ -78,6 +80,7 @@ protected:
bool _julia,
bool _evm15,
ExternalIdentifierAccess const& _identifierAccess,
+ bool _useNamedLabelsForFunctions,
int _stackAdjustment,
std::shared_ptr<Context> _context
):
@@ -85,6 +88,7 @@ protected:
m_info(_analysisInfo),
m_julia(_julia),
m_evm15(_evm15),
+ m_useNamedLabelsForFunctions(_useNamedLabelsForFunctions),
m_identifierAccess(_identifierAccess),
m_stackAdjustment(_stackAdjustment),
m_context(_context)
@@ -110,7 +114,7 @@ private:
/// @returns the label ID corresponding to the given label, allocating a new one if
/// necessary.
AbstractAssembly::LabelID labelID(solidity::assembly::Scope::Label const& _label);
- AbstractAssembly::LabelID functionEntryID(solidity::assembly::Scope::Function const& _function);
+ AbstractAssembly::LabelID functionEntryID(std::string const& _name, solidity::assembly::Scope::Function const& _function);
/// Generates code for an expression that is supposed to return a single value.
void visitExpression(solidity::assembly::Statement const& _expression);
@@ -136,6 +140,7 @@ private:
solidity::assembly::Scope* m_scope = nullptr;
bool m_julia = false;
bool m_evm15 = false;
+ bool m_useNamedLabelsForFunctions = false;
ExternalIdentifierAccess m_identifierAccess;
/// Adjustment between the stack height as determined during the analysis phase
/// and the stack height in the assembly. This is caused by an initial stack being present
diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp
index ed780d0b..5a77162e 100644
--- a/libsolidity/codegen/CompilerContext.cpp
+++ b/libsolidity/codegen/CompilerContext.cpp
@@ -266,19 +266,9 @@ void CompilerContext::resetVisitedNodes(ASTNode const* _node)
void CompilerContext::appendInlineAssembly(
string const& _assembly,
vector<string> const& _localVariables,
- map<string, string> const& _replacements
+ bool _system
)
{
- string replacedAssembly;
- string const* assembly = &_assembly;
- if (!_replacements.empty())
- {
- replacedAssembly = _assembly;
- for (auto const& replacement: _replacements)
- replacedAssembly = boost::algorithm::replace_all_copy(replacedAssembly, replacement.first, replacement.second);
- assembly = &replacedAssembly;
- }
-
int startStackHeight = stackHeight();
julia::ExternalIdentifierAccess identifierAccess;
@@ -320,7 +310,7 @@ void CompilerContext::appendInlineAssembly(
ErrorList errors;
ErrorReporter errorReporter(errors);
- auto scanner = make_shared<Scanner>(CharStream(*assembly), "--CODEGEN--");
+ auto scanner = make_shared<Scanner>(CharStream(_assembly), "--CODEGEN--");
auto parserResult = assembly::Parser(errorReporter).parse(scanner);
solAssert(parserResult, "Failed to parse inline assembly block.");
solAssert(errorReporter.errors().empty(), "Failed to parse inline assembly block.");
@@ -329,7 +319,7 @@ void CompilerContext::appendInlineAssembly(
assembly::AsmAnalyzer analyzer(analysisInfo, errorReporter, false, identifierAccess.resolve);
solAssert(analyzer.analyze(*parserResult), "Failed to analyze inline assembly block.");
solAssert(errorReporter.errors().empty(), "Failed to analyze inline assembly block.");
- assembly::CodeGenerator::assemble(*parserResult, analysisInfo, *m_asm, identifierAccess);
+ assembly::CodeGenerator::assemble(*parserResult, analysisInfo, *m_asm, identifierAccess, _system);
}
FunctionDefinition const& CompilerContext::resolveVirtualFunction(
diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h
index 5116585e..dd36bba0 100644
--- a/libsolidity/codegen/CompilerContext.h
+++ b/libsolidity/codegen/CompilerContext.h
@@ -156,6 +156,8 @@ public:
eth::AssemblyItem pushNewTag() { return m_asm->append(m_asm->newPushTag()).tag(); }
/// @returns a new tag without pushing any opcodes or data
eth::AssemblyItem newTag() { return m_asm->newTag(); }
+ /// @returns a new tag identified by name.
+ eth::AssemblyItem namedTag(std::string const& _name) { return m_asm->namedTag(_name); }
/// Adds a subroutine to the code (in the data section) and pushes its size (via a tag)
/// on the stack. @returns the pushsub assembly item.
eth::AssemblyItem addSubroutine(eth::AssemblyPointer const& _assembly) { return m_asm->appendSubroutine(_assembly); }
@@ -185,10 +187,11 @@ public:
/// Appends inline assembly. @a _replacements are string-matching replacements that are performed
/// prior to parsing the inline assembly.
/// @param _localVariables assigns stack positions to variables with the last one being the stack top
+ /// @param _system if true, this is a "system-level" assembly where all functions use named labels.
void appendInlineAssembly(
std::string const& _assembly,
std::vector<std::string> const& _localVariables = std::vector<std::string>(),
- std::map<std::string, std::string> const& _replacements = std::map<std::string, std::string>{}
+ bool _system = false
);
/// Appends arbitrary data to the end of the bytecode.
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index 146472f9..3662478d 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -319,7 +319,7 @@ void CompilerUtils::abiEncode(
ABIFunctions funs;
string routine = funs.tupleEncoder(_givenTypes, _targetTypes, _encodeAsLibraryTypes);
routine += funs.requestedFunctions();
- m_context.appendInlineAssembly("{" + routine + "}", variables);
+ m_context.appendInlineAssembly("{" + routine + "}", variables, true);
// Remove everyhing except for "value0" / the final memory pointer.
popStackSlots(numValues);
}
diff --git a/libsolidity/inlineasm/AsmCodeGen.cpp b/libsolidity/inlineasm/AsmCodeGen.cpp
index 6d0c0255..dded9f76 100644
--- a/libsolidity/inlineasm/AsmCodeGen.cpp
+++ b/libsolidity/inlineasm/AsmCodeGen.cpp
@@ -83,6 +83,10 @@ public:
{
return assemblyTagToIdentifier(m_assembly.newTag());
}
+ virtual size_t namedLabel(std::string const& _name) override
+ {
+ return assemblyTagToIdentifier(m_assembly.namedTag(_name));
+ }
virtual void appendLinkerSymbol(std::string const& _linkerSymbol) override
{
m_assembly.appendLibraryAddress(_linkerSymbol);
@@ -141,9 +145,17 @@ void assembly::CodeGenerator::assemble(
Block const& _parsedData,
AsmAnalysisInfo& _analysisInfo,
eth::Assembly& _assembly,
- julia::ExternalIdentifierAccess const& _identifierAccess
+ julia::ExternalIdentifierAccess const& _identifierAccess,
+ bool _useNamedLabelsForFunctions
)
{
EthAssemblyAdapter assemblyAdapter(_assembly);
- julia::CodeTransform(assemblyAdapter, _analysisInfo, false, false, _identifierAccess)(_parsedData);
+ julia::CodeTransform(
+ assemblyAdapter,
+ _analysisInfo,
+ false,
+ false,
+ _identifierAccess,
+ _useNamedLabelsForFunctions
+ )(_parsedData);
}
diff --git a/libsolidity/inlineasm/AsmCodeGen.h b/libsolidity/inlineasm/AsmCodeGen.h
index 2a36a590..a7d7ead1 100644
--- a/libsolidity/inlineasm/AsmCodeGen.h
+++ b/libsolidity/inlineasm/AsmCodeGen.h
@@ -46,7 +46,8 @@ public:
Block const& _parsedData,
AsmAnalysisInfo& _analysisInfo,
eth::Assembly& _assembly,
- julia::ExternalIdentifierAccess const& _identifierAccess = julia::ExternalIdentifierAccess()
+ julia::ExternalIdentifierAccess const& _identifierAccess = julia::ExternalIdentifierAccess(),
+ bool _useNamedLabelsForFunctions = false
);
};
diff --git a/test/libsolidity/ABIEncoderTests.cpp b/test/libsolidity/ABIEncoderTests.cpp
index 297c4ef0..4ddf17ce 100644
--- a/test/libsolidity/ABIEncoderTests.cpp
+++ b/test/libsolidity/ABIEncoderTests.cpp
@@ -398,6 +398,34 @@ BOOST_AUTO_TEST_CASE(calldata)
)
}
+BOOST_AUTO_TEST_CASE(function_name_collision)
+{
+ // This tests a collision between a function name used by inline assembly
+ // and by the ABI encoder
+ string sourceCode = R"(
+ contract C {
+ function f(uint x) returns (uint) {
+ assembly {
+ function abi_encode_t_uint256_to_t_uint256() {
+ mstore(0, 7)
+ return(0, 0x20)
+ }
+ switch x
+ case 0 { abi_encode_t_uint256_to_t_uint256() }
+ }
+ return 1;
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("f(uint256)", encodeArgs(0)) == encodeArgs(7));
+ BOOST_CHECK(callContractFunction("f(uint256)", encodeArgs(1)) == encodeArgs(1));
+ )
+}
+
+
+
BOOST_AUTO_TEST_SUITE_END()
}