Merge pull request #8095 from ethereum/develop

Merge develop into release for 0.6.1
This commit is contained in:
chriseth 2020-01-03 00:35:39 +01:00 committed by GitHub
commit e6f7d5a492
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
92 changed files with 817 additions and 317 deletions

View File

@ -10,7 +10,7 @@ include(EthPolicy)
eth_policy()
# project name and version should be set after cmake_policy CMP0048
set(PROJECT_VERSION "0.6.0")
set(PROJECT_VERSION "0.6.1")
project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX)
include(TestBigEndian)

View File

@ -1,3 +1,9 @@
### 0.6.1 (2020-01-02)
Bugfixes:
* Yul Optimizer: Fix bug in redundant assignment remover in combination with break and continue statements.
### 0.6.0 (2019-12-17)
Breaking changes:
@ -33,6 +39,7 @@ Language Features:
* Allow global enums and structs.
* Allow public variables to override external functions.
* Allow underscores as delimiters in hex strings.
* Allow to react on failing external calls using ``try`` and ``catch``.
* Introduce syntax for array slices and implement them for dynamic calldata arrays.
* Introduce ``push()`` for dynamic storage arrays. It returns a reference to the newly allocated element, if applicable.
* Introduce ``virtual`` and ``override`` keywords.
@ -45,6 +52,12 @@ Compiler Features:
* ABIEncoderV2: Do not warn about enabled ABIEncoderV2 anymore (the pragma is still needed, though).
### 0.5.16 (2020-01-02)
Backported Bugfixes:
* Yul Optimizer: Fix bug in redundant assignment remover in combination with break and continue statements.
### 0.5.15 (2019-12-17)
Bugfixes:

View File

@ -1,4 +1,26 @@
[
{
"name": "YulOptimizerRedundantAssignmentBreakContinue",
"summary": "The Yul optimizer can remove essential assignments to variables declared inside for loops when Yul's continue or break statement is used. You are unlikely to be affected if you do not use inline assembly with for loops and continue and break statements.",
"description": "The Yul optimizer has a stage that removes assignments to variables that are overwritten again or are not used in all following control-flow branches. This logic incorrectly removes such assignments to variables declared inside a for loop if they can be removed in a control-flow branch that ends with ``break`` or ``continue`` even though they cannot be removed in other control-flow branches. Variables declared outside of the respective for loop are not affected.",
"introduced": "0.6.0",
"fixed": "0.6.1",
"severity": "medium",
"conditions": {
"yulOptimizer": true
}
},
{
"name": "YulOptimizerRedundantAssignmentBreakContinue0.5",
"summary": "The Yul optimizer can remove essential assignments to variables declared inside for loops when Yul's continue or break statement is used. You are unlikely to be affected if you do not use inline assembly with for loops and continue and break statements.",
"description": "The Yul optimizer has a stage that removes assignments to variables that are overwritten again or are not used in all following control-flow branches. This logic incorrectly removes such assignments to variables declared inside a for loop if they can be removed in a control-flow branch that ends with ``break`` or ``continue`` even though they cannot be removed in other control-flow branches. Variables declared outside of the respective for loop are not affected.",
"introduced": "0.5.8",
"fixed": "0.5.16",
"severity": "low",
"conditions": {
"yulOptimizer": true
}
},
{
"name": "ABIEncoderV2LoopYulOptimizer",
"summary": "If both the experimental ABIEncoderV2 and the experimental Yul optimizer are activated, one component of the Yul optimizer may reuse data in memory that has been changed in the meantime.",

View File

@ -742,32 +742,46 @@
},
"0.5.10": {
"bugs": [
"YulOptimizerRedundantAssignmentBreakContinue0.5",
"ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers"
],
"released": "2019-06-25"
},
"0.5.11": {
"bugs": [],
"bugs": [
"YulOptimizerRedundantAssignmentBreakContinue0.5"
],
"released": "2019-08-12"
},
"0.5.12": {
"bugs": [],
"bugs": [
"YulOptimizerRedundantAssignmentBreakContinue0.5"
],
"released": "2019-10-01"
},
"0.5.13": {
"bugs": [],
"bugs": [
"YulOptimizerRedundantAssignmentBreakContinue0.5"
],
"released": "2019-11-14"
},
"0.5.14": {
"bugs": [
"YulOptimizerRedundantAssignmentBreakContinue0.5",
"ABIEncoderV2LoopYulOptimizer"
],
"released": "2019-12-09"
},
"0.5.15": {
"bugs": [],
"bugs": [
"YulOptimizerRedundantAssignmentBreakContinue0.5"
],
"released": "2019-12-17"
},
"0.5.16": {
"bugs": [],
"released": "2020-01-02"
},
"0.5.2": {
"bugs": [
"SignedArrayStorageCopy",
@ -840,6 +854,7 @@
},
"0.5.8": {
"bugs": [
"YulOptimizerRedundantAssignmentBreakContinue0.5",
"ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement",
@ -849,6 +864,7 @@
},
"0.5.9": {
"bugs": [
"YulOptimizerRedundantAssignmentBreakContinue0.5",
"ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers",
"SignedArrayStorageCopy",
"ABIEncoderV2StorageArrayWithMultiSlotElement"
@ -856,7 +872,13 @@
"released": "2019-05-28"
},
"0.6.0": {
"bugs": [],
"bugs": [
"YulOptimizerRedundantAssignmentBreakContinue"
],
"released": "2019-12-17"
},
"0.6.1": {
"bugs": [],
"released": "2020-01-02"
}
}

View File

@ -33,7 +33,7 @@ Solidity Integrations
* `Solidity IDE <https://github.com/System-Glitch/Solidity-IDE>`_
Browser-based IDE with integrated compiler, Ganache and local file system support.
* `Solium <https://github.com/duaraghav8/Solium/>`_
* `Ethlint <https://github.com/duaraghav8/Ethlint>`_
Linter to identify and fix style and security issues in Solidity.
* `Superblocks Lab <https://lab.superblocks.com/>`_
@ -48,7 +48,7 @@ Solidity Integrations
Plugin for the Atom editor that provides Solidity linting.
* `Atom Solium Linter <https://atom.io/packages/linter-solium>`_
Configurable Solidty linter for Atom using Solium as a base.
Configurable Solidity linter for Atom using Solium (now Ethlint) as a base.
* Eclipse:

View File

@ -639,7 +639,7 @@ void DeclarationRegistrationHelper::endVisit(FunctionDefinition&)
bool DeclarationRegistrationHelper::visit(TryCatchClause& _tryCatchClause)
{
_tryCatchClause.setScope(m_currentScope);
_tryCatchClause.annotation().scope = m_currentScope;
enterNewSubScope(_tryCatchClause);
return true;
}
@ -675,7 +675,7 @@ void DeclarationRegistrationHelper::endVisit(FunctionTypeName&)
bool DeclarationRegistrationHelper::visit(Block& _block)
{
_block.setScope(m_currentScope);
_block.annotation().scope = m_currentScope;
enterNewSubScope(_block);
return true;
}
@ -687,7 +687,7 @@ void DeclarationRegistrationHelper::endVisit(Block&)
bool DeclarationRegistrationHelper::visit(ForStatement& _for)
{
_for.setScope(m_currentScope);
_for.annotation().scope = m_currentScope;
enterNewSubScope(_for);
return true;
}
@ -761,7 +761,7 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio
registerDeclaration(*m_scopes[m_currentScope], _declaration, nullptr, nullptr, warnAboutShadowing, inactive, m_errorReporter);
_declaration.setScope(m_currentScope);
_declaration.annotation().scope = m_currentScope;
if (_opensScope)
enterNewSubScope(_declaration);
}

View File

@ -43,10 +43,6 @@ public:
m_dialect(_dialect),
m_reportMutability(_reportMutability) {}
void operator()(yul::Instruction const& _instruction)
{
checkInstruction(_instruction.location, _instruction.instruction);
}
void operator()(yul::Literal const&) {}
void operator()(yul::Identifier const&) {}
void operator()(yul::ExpressionStatement const& _expr)

View File

@ -449,6 +449,13 @@ string Scopable::sourceUnitName() const
return sourceUnit().annotation().path;
}
DeclarationAnnotation& Declaration::annotation() const
{
if (!m_annotation)
m_annotation = make_unique<DeclarationAnnotation>();
return dynamic_cast<DeclarationAnnotation&>(*m_annotation);
}
bool VariableDeclaration::isLValue() const
{
// Constant declared variables are Read-Only
@ -653,6 +660,27 @@ InlineAssemblyAnnotation& InlineAssembly::annotation() const
return dynamic_cast<InlineAssemblyAnnotation&>(*m_annotation);
}
BlockAnnotation& Block::annotation() const
{
if (!m_annotation)
m_annotation = make_unique<BlockAnnotation>();
return dynamic_cast<BlockAnnotation&>(*m_annotation);
}
TryCatchClauseAnnotation& TryCatchClause::annotation() const
{
if (!m_annotation)
m_annotation = make_unique<TryCatchClauseAnnotation>();
return dynamic_cast<TryCatchClauseAnnotation&>(*m_annotation);
}
ForStatementAnnotation& ForStatement::annotation() const
{
if (!m_annotation)
m_annotation = make_unique<ForStatementAnnotation>();
return dynamic_cast<ForStatementAnnotation&>(*m_annotation);
}
ReturnAnnotation& Return::annotation() const
{
if (!m_annotation)

View File

@ -159,8 +159,7 @@ public:
virtual ~Scopable() = default;
/// @returns the scope this declaration resides in. Can be nullptr if it is the global scope.
/// Available only after name and type resolution step.
ASTNode const* scope() const { return m_scope; }
void setScope(ASTNode const* _scope) { m_scope = _scope; }
ASTNode const* scope() const { return annotation().scope; }
/// @returns the source unit this scopable is present in.
SourceUnit const& sourceUnit() const;
@ -172,8 +171,7 @@ public:
/// Can be combined with annotation().canonicalName (if present) to form a globally unique name.
std::string sourceUnitName() const;
protected:
ASTNode const* m_scope = nullptr;
virtual ScopableAnnotation& annotation() const = 0;
};
/**
@ -231,6 +229,8 @@ public:
/// @returns null when it is not accessible as a function.
virtual FunctionTypePointer functionType(bool /*_internal*/) const { return {}; }
DeclarationAnnotation& annotation() const override;
protected:
virtual Visibility defaultVisibility() const { return Visibility::Public; }
@ -1169,6 +1169,8 @@ public:
std::vector<ASTPointer<Statement>> const& statements() const { return m_statements; }
BlockAnnotation& annotation() const override;
private:
std::vector<ASTPointer<Statement>> m_statements;
};
@ -1248,6 +1250,8 @@ public:
ParameterList const* parameters() const { return m_parameters.get(); }
Block const& block() const { return *m_block; }
TryCatchClauseAnnotation& annotation() const override;
private:
ASTPointer<ASTString> m_errorName;
ASTPointer<ParameterList> m_parameters;
@ -1357,6 +1361,8 @@ public:
ExpressionStatement const* loopExpression() const { return m_loopExpression.get(); }
Statement const& body() const { return *m_body; }
ForStatementAnnotation& annotation() const override;
private:
/// For statement's initialization expression. for (XXX; ; ). Can be empty
ASTPointer<Statement> m_initExpression;

View File

@ -75,7 +75,18 @@ struct SourceUnitAnnotation: ASTAnnotation
std::set<ExperimentalFeature> experimentalFeatures;
};
struct ImportAnnotation: ASTAnnotation
struct ScopableAnnotation
{
/// The scope this declaration resides in. Can be nullptr if it is the global scope.
/// Available only after name and type resolution step.
ASTNode const* scope = nullptr;
};
struct DeclarationAnnotation: ASTAnnotation, ScopableAnnotation
{
};
struct ImportAnnotation: DeclarationAnnotation
{
/// The absolute path of the source unit to import.
std::string absolutePath;
@ -83,7 +94,7 @@ struct ImportAnnotation: ASTAnnotation
SourceUnit const* sourceUnit = nullptr;
};
struct TypeDeclarationAnnotation: ASTAnnotation
struct TypeDeclarationAnnotation: DeclarationAnnotation
{
/// The name of this type, prefixed by proper namespaces if globally accessible.
std::string canonicalName;
@ -104,7 +115,7 @@ struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, DocumentedAnnota
std::map<FunctionDefinition const*, ASTNode const*> baseConstructorArguments;
};
struct CallableDeclarationAnnotation: ASTAnnotation
struct CallableDeclarationAnnotation: DeclarationAnnotation
{
/// The set of functions/modifiers/events this callable overrides.
std::set<CallableDeclaration const*> baseFunctions;
@ -124,7 +135,7 @@ struct ModifierDefinitionAnnotation: CallableDeclarationAnnotation, DocumentedAn
{
};
struct VariableDeclarationAnnotation: ASTAnnotation
struct VariableDeclarationAnnotation: DeclarationAnnotation
{
/// Type of variable (type of identifier referencing this variable).
TypePointer type = nullptr;
@ -152,6 +163,18 @@ struct InlineAssemblyAnnotation: StatementAnnotation
std::shared_ptr<yul::AsmAnalysisInfo> analysisInfo;
};
struct BlockAnnotation: StatementAnnotation, ScopableAnnotation
{
};
struct TryCatchClauseAnnotation: ASTAnnotation, ScopableAnnotation
{
};
struct ForStatementAnnotation: StatementAnnotation, ScopableAnnotation
{
};
struct ReturnAnnotation: StatementAnnotation
{
/// Reference to the return parameters of the function.

View File

@ -51,10 +51,6 @@
#include <libyul/YulString.h>
#include <libyul/AsmPrinter.h>
#include <libyul/backends/wasm/EVMToEWasmTranslator.h>
#include <libyul/backends/wasm/EWasmObjectCompiler.h>
#include <libyul/backends/wasm/WasmDialect.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <libyul/AssemblyStack.h>
#include <liblangutil/Scanner.h>
@ -81,7 +77,7 @@ CompilerStack::CompilerStack(ReadCallback::Callback const& _readFile):
m_readFile{_readFile},
m_enabledSMTSolvers{smt::SMTSolverChoice::All()},
m_generateIR{false},
m_generateEWasm{false},
m_generateEwasm{false},
m_errorList{},
m_errorReporter{m_errorList}
{
@ -204,7 +200,7 @@ void CompilerStack::reset(bool _keepSettings)
m_evmVersion = langutil::EVMVersion();
m_enabledSMTSolvers = smt::SMTSolverChoice::All();
m_generateIR = false;
m_generateEWasm = false;
m_generateEwasm = false;
m_revertStrings = RevertStrings::Default;
m_optimiserSettings = OptimiserSettings::minimal();
m_metadataLiteralSources = false;
@ -467,10 +463,10 @@ bool CompilerStack::compile()
if (isRequestedContract(*contract))
{
compileContract(*contract, otherCompilers);
if (m_generateIR || m_generateEWasm)
if (m_generateIR || m_generateEwasm)
generateIR(*contract);
if (m_generateEWasm)
generateEWasm(*contract);
if (m_generateEwasm)
generateEwasm(*contract);
}
m_stackState = CompilationSuccessful;
this->link();
@ -596,20 +592,20 @@ string const& CompilerStack::yulIROptimized(string const& _contractName) const
return contract(_contractName).yulIROptimized;
}
string const& CompilerStack::eWasm(string const& _contractName) const
string const& CompilerStack::ewasm(string const& _contractName) const
{
if (m_stackState != CompilationSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
return contract(_contractName).eWasm;
return contract(_contractName).ewasm;
}
eth::LinkerObject const& CompilerStack::eWasmObject(string const& _contractName) const
eth::LinkerObject const& CompilerStack::ewasmObject(string const& _contractName) const
{
if (m_stackState != CompilationSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
return contract(_contractName).eWasmObject;
return contract(_contractName).ewasmObject;
}
eth::LinkerObject const& CompilerStack::object(string const& _contractName) const
@ -1073,15 +1069,15 @@ void CompilerStack::generateIR(ContractDefinition const& _contract)
tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run(_contract);
}
void CompilerStack::generateEWasm(ContractDefinition const& _contract)
void CompilerStack::generateEwasm(ContractDefinition const& _contract)
{
solAssert(m_stackState >= AnalysisPerformed, "");
if (m_hasError)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called generateEWasm with errors."));
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called generateEwasm with errors."));
Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
solAssert(!compiledContract.yulIROptimized.empty(), "");
if (!compiledContract.eWasm.empty())
if (!compiledContract.ewasm.empty())
return;
// Re-parse the Yul IR in EVM dialect
@ -1089,15 +1085,15 @@ void CompilerStack::generateEWasm(ContractDefinition const& _contract)
stack.parseAndAnalyze("", compiledContract.yulIROptimized);
stack.optimize();
stack.translate(yul::AssemblyStack::Language::EWasm);
stack.translate(yul::AssemblyStack::Language::Ewasm);
stack.optimize();
//cout << yul::AsmPrinter{}(*stack.parserResult()->code) << endl;
// Turn into eWasm text representation.
auto result = stack.assemble(yul::AssemblyStack::Machine::eWasm);
compiledContract.eWasm = std::move(result.assembly);
compiledContract.eWasmObject = std::move(*result.bytecode);
// Turn into Ewasm text representation.
auto result = stack.assemble(yul::AssemblyStack::Machine::Ewasm);
compiledContract.ewasm = std::move(result.assembly);
compiledContract.ewasmObject = std::move(*result.bytecode);
}
CompilerStack::Contract const& CompilerStack::contract(string const& _contractName) const

View File

@ -178,8 +178,8 @@ public:
/// Enable experimental generation of Yul IR code.
void enableIRGeneration(bool _enable = true) { m_generateIR = _enable; }
/// Enable experimental generation of eWasm code. If enabled, IR is also generated.
void enableEWasmGeneration(bool _enable = true) { m_generateEWasm = _enable; }
/// Enable experimental generation of Ewasm code. If enabled, IR is also generated.
void enableEwasmGeneration(bool _enable = true) { m_generateEwasm = _enable; }
/// @arg _metadataLiteralSources When true, store sources as literals in the contract metadata.
/// Must be set before parsing.
@ -251,11 +251,11 @@ public:
/// @returns the optimized IR representation of a contract.
std::string const& yulIROptimized(std::string const& _contractName) const;
/// @returns the eWasm text representation of a contract.
std::string const& eWasm(std::string const& _contractName) const;
/// @returns the Ewasm text representation of a contract.
std::string const& ewasm(std::string const& _contractName) const;
/// @returns the eWasm representation of a contract.
eth::LinkerObject const& eWasmObject(std::string const& _contractName) const;
/// @returns the Ewasm representation of a contract.
eth::LinkerObject const& ewasmObject(std::string const& _contractName) const;
/// @returns the assembled object for a contract.
eth::LinkerObject const& object(std::string const& _contractName) const;
@ -338,8 +338,8 @@ private:
eth::LinkerObject runtimeObject; ///< Runtime object.
std::string yulIR; ///< Experimental Yul IR code.
std::string yulIROptimized; ///< Optimized experimental Yul IR code.
std::string eWasm; ///< Experimental eWasm text representation
eth::LinkerObject eWasmObject; ///< Experimental eWasm code
std::string ewasm; ///< Experimental Ewasm text representation
eth::LinkerObject ewasmObject; ///< Experimental Ewasm code
mutable std::unique_ptr<std::string const> metadata; ///< The metadata json that will be hashed into the chain.
mutable std::unique_ptr<Json::Value const> abi;
mutable std::unique_ptr<Json::Value const> storageLayout;
@ -374,8 +374,8 @@ private:
/// The IR is stored but otherwise unused.
void generateIR(ContractDefinition const& _contract);
/// Generate eWasm representation for a single contract.
void generateEWasm(ContractDefinition const& _contract);
/// Generate Ewasm representation for a single contract.
void generateEwasm(ContractDefinition const& _contract);
/// Links all the known library addresses in the available objects. Any unknown
/// library will still be kept as an unlinked placeholder in the objects.
@ -436,7 +436,7 @@ private:
smt::SMTSolverChoice m_enabledSMTSolvers;
std::map<std::string, std::set<std::string>> m_requestedContractNames;
bool m_generateIR;
bool m_generateEWasm;
bool m_generateEwasm;
std::map<std::string, h160> m_libraries;
/// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum
/// "context:prefix=target"

View File

@ -247,9 +247,9 @@ bool isBinaryRequested(Json::Value const& _outputSelection)
return false;
}
/// @returns true if any eWasm code was requested. Note that as an exception, '*' does not
/// @returns true if any Ewasm code was requested. Note that as an exception, '*' does not
/// yet match "ewasm.wast" or "ewasm"
bool isEWasmRequested(Json::Value const& _outputSelection)
bool isEwasmRequested(Json::Value const& _outputSelection)
{
if (!_outputSelection.isObject())
return false;
@ -267,7 +267,7 @@ bool isEWasmRequested(Json::Value const& _outputSelection)
/// yet match "ir" or "irOptimized"
bool isIRRequested(Json::Value const& _outputSelection)
{
if (isEWasmRequested(_outputSelection))
if (isEwasmRequested(_outputSelection))
return true;
if (!_outputSelection.isObject())
@ -780,7 +780,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
compilerStack.enableIRGeneration(isIRRequested(_inputsAndSettings.outputSelection));
compilerStack.enableEWasmGeneration(isEWasmRequested(_inputsAndSettings.outputSelection));
compilerStack.enableEwasmGeneration(isEwasmRequested(_inputsAndSettings.outputSelection));
Json::Value errors = std::move(_inputsAndSettings.errors);
@ -956,11 +956,11 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "irOptimized", wildcardMatchesExperimental))
contractData["irOptimized"] = compilerStack.yulIROptimized(contractName);
// eWasm
// Ewasm
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "ewasm.wast", wildcardMatchesExperimental))
contractData["ewasm"]["wast"] = compilerStack.eWasm(contractName);
contractData["ewasm"]["wast"] = compilerStack.ewasm(contractName);
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "ewasm.wasm", wildcardMatchesExperimental))
contractData["ewasm"]["wasm"] = compilerStack.eWasmObject(contractName).toHex();
contractData["ewasm"]["wasm"] = compilerStack.ewasmObject(contractName).toHex();
// EVM
Json::Value evmData(Json::objectValue);

View File

@ -86,16 +86,6 @@ AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect,
return analysisInfo;
}
bool AsmAnalyzer::operator()(yul::Instruction const& _instruction)
{
yulAssert(false, "The use of non-functional instructions is disallowed. Please use functional notation instead.");
auto const& info = instructionInfo(_instruction.instruction);
m_stackHeight += info.ret - info.args;
m_info.stackHeightInfo[&_instruction] = m_stackHeight;
warnOnInstructions(_instruction.instruction, _instruction.location);
return true;
}
bool AsmAnalyzer::operator()(Literal const& _literal)
{
expectValidType(_literal.type.str(), _literal.location);

View File

@ -77,7 +77,6 @@ public:
/// Asserts on failure.
static AsmAnalysisInfo analyzeStrictAssertCorrect(Dialect const& _dialect, Object const& _object);
bool operator()(Instruction const&);
bool operator()(Literal const& _literal);
bool operator()(Identifier const&);
bool operator()(ExpressionStatement const&);

View File

@ -25,12 +25,8 @@
#include <libyul/AsmDataForward.h>
#include <libyul/YulString.h>
#include <libevmasm/Instruction.h>
#include <liblangutil/SourceLocation.h>
#include <boost/noncopyable.hpp>
#include <map>
#include <memory>
namespace yul
@ -41,8 +37,6 @@ using Type = YulString;
struct TypedName { langutil::SourceLocation location; YulString name; Type type; };
using TypedNameList = std::vector<TypedName>;
/// Direct EVM instruction (except PUSHi and JUMPDEST)
struct Instruction { langutil::SourceLocation location; dev::eth::Instruction instruction; };
/// Literal number or string (up to 32 bytes)
enum class LiteralKind { Number, Boolean, String };
struct Literal { langutil::SourceLocation location; LiteralKind kind; YulString value; Type type; };

View File

@ -29,6 +29,8 @@
#include <liblangutil/Scanner.h>
#include <liblangutil/ParserBase.h>
#include <libevmasm/Instruction.h>
#include <memory>
#include <variant>
#include <vector>
@ -56,7 +58,7 @@ public:
static std::map<std::string, dev::eth::Instruction> const& instructions();
protected:
using ElementaryOperation = std::variant<Instruction, Literal, Identifier, FunctionCall>;
using ElementaryOperation = std::variant<Literal, Identifier, FunctionCall>;
/// Creates an inline assembly node with the given source location.
template <class T> T createWithLocation(langutil::SourceLocation const& _loc = {}) const

View File

@ -16,7 +16,7 @@
*/
/**
* Full assembly stack that can support EVM-assembly and Yul as input and EVM, EVM1.5 and
* eWasm as output.
* Ewasm as output.
*/
@ -33,8 +33,8 @@
#include <libyul/backends/evm/EVMObjectCompiler.h>
#include <libyul/backends/evm/EVMMetrics.h>
#include <libyul/backends/wasm/WasmDialect.h>
#include <libyul/backends/wasm/EWasmObjectCompiler.h>
#include <libyul/backends/wasm/EVMToEWasmTranslator.h>
#include <libyul/backends/wasm/WasmObjectCompiler.h>
#include <libyul/backends/wasm/EVMToEwasmTranslator.h>
#include <libyul/optimiser/Metrics.h>
#include <libyul/ObjectParser.h>
#include <libyul/optimiser/Suite.h>
@ -59,7 +59,7 @@ Dialect const& languageToDialect(AssemblyStack::Language _language, EVMVersion _
return EVMDialect::strictAssemblyForEVMObjects(_version);
case AssemblyStack::Language::Yul:
return Dialect::yul();
case AssemblyStack::Language::EWasm:
case AssemblyStack::Language::Ewasm:
return WasmDialect::instance();
}
yulAssert(false, "");
@ -108,11 +108,11 @@ void AssemblyStack::translate(AssemblyStack::Language _targetLanguage)
return;
solAssert(
m_language == Language::StrictAssembly && _targetLanguage == Language::EWasm,
m_language == Language::StrictAssembly && _targetLanguage == Language::Ewasm,
"Invalid language combination"
);
*m_parserResult = EVMToEWasmTranslator(
*m_parserResult = EVMToEwasmTranslator(
languageToDialect(m_language, m_evmVersion)
).run(*parserResult());
@ -214,13 +214,13 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
/// TODO: fill out text representation
return object;
}
case Machine::eWasm:
case Machine::Ewasm:
{
yulAssert(m_language == Language::EWasm, "");
yulAssert(m_language == Language::Ewasm, "");
Dialect const& dialect = languageToDialect(m_language, EVMVersion{});
MachineAssemblyObject object;
auto result = EWasmObjectCompiler::compile(*m_parserResult, dialect);
auto result = WasmObjectCompiler::compile(*m_parserResult, dialect);
object.assembly = std::move(result.first);
object.bytecode = make_shared<dev::eth::LinkerObject>();
object.bytecode->bytecode = std::move(result.second);

View File

@ -16,7 +16,7 @@
*/
/**
* Full assembly stack that can support EVM-assembly and Yul as input and EVM, EVM1.5 and
* eWasm as output.
* Ewasm as output.
*/
#pragma once
@ -52,13 +52,13 @@ struct MachineAssemblyObject
/*
* Full assembly stack that can support EVM-assembly and Yul as input and EVM, EVM1.5 and
* eWasm as output.
* Ewasm as output.
*/
class AssemblyStack
{
public:
enum class Language { Yul, Assembly, StrictAssembly, EWasm };
enum class Machine { EVM, EVM15, eWasm };
enum class Language { Yul, Assembly, StrictAssembly, Ewasm };
enum class Machine { EVM, EVM15, Ewasm };
AssemblyStack():
AssemblyStack(langutil::EVMVersion{}, Language::Assembly, dev::solidity::OptimiserSettings::none())

View File

@ -44,18 +44,18 @@ add_library(yul
backends/evm/EVMMetrics.h
backends/evm/NoOutputAssembly.h
backends/evm/NoOutputAssembly.cpp
backends/wasm/EVMToEWasmTranslator.cpp
backends/wasm/EVMToEWasmTranslator.h
backends/wasm/EWasmCodeTransform.cpp
backends/wasm/EWasmCodeTransform.h
backends/wasm/EWasmObjectCompiler.cpp
backends/wasm/EWasmObjectCompiler.h
backends/wasm/EVMToEwasmTranslator.cpp
backends/wasm/EVMToEwasmTranslator.h
backends/wasm/BinaryTransform.cpp
backends/wasm/BinaryTransform.h
backends/wasm/TextTransform.cpp
backends/wasm/TextTransform.h
backends/wasm/WasmCodeTransform.cpp
backends/wasm/WasmCodeTransform.h
backends/wasm/WasmDialect.cpp
backends/wasm/WasmDialect.h
backends/wasm/WasmObjectCompiler.cpp
backends/wasm/WasmObjectCompiler.h
backends/wasm/WordSizeTransform.cpp
backends/wasm/WordSizeTransform.h
optimiser/ASTCopier.cpp

View File

@ -43,7 +43,6 @@ enum class Instruction: uint8_t;
namespace yul
{
struct Instruction;
struct Identifier;
///

View File

@ -350,16 +350,6 @@ void CodeTransform::operator()(Literal const& _literal)
checkStackHeight(&_literal);
}
void CodeTransform::operator()(yul::Instruction const& _instruction)
{
yulAssert(!m_allowStackOpt, "");
yulAssert(!m_evm15 || _instruction.instruction != dev::eth::Instruction::JUMP, "Bare JUMP instruction used for EVM1.5");
yulAssert(!m_evm15 || _instruction.instruction != dev::eth::Instruction::JUMPI, "Bare JUMPI instruction used for EVM1.5");
m_assembly.setSourceLocation(_instruction.location);
m_assembly.appendInstruction(_instruction.instruction);
checkStackHeight(&_instruction);
}
void CodeTransform::operator()(If const& _if)
{
visitExpression(*_if.condition);

View File

@ -170,7 +170,6 @@ protected:
void deleteVariable(Scope::Variable const& _var);
public:
void operator()(Instruction const& _instruction);
void operator()(Literal const& _literal);
void operator()(Identifier const& _identifier);
void operator()(FunctionCall const&);

View File

@ -15,7 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* EWasm to binary encoder.
* Component that transforms internal Wasm representation to binary.
*/
#include <libyul/backends/wasm/BinaryTransform.h>

View File

@ -15,7 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* EWasm to binary encoder.
* Component that transforms internal Wasm representation to binary.
*/
#pragma once

View File

@ -15,10 +15,10 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Translates Yul code from EVM dialect to eWasm dialect.
* Translates Yul code from EVM dialect to Ewasm dialect.
*/
#include <libyul/backends/wasm/EVMToEWasmTranslator.h>
#include <libyul/backends/wasm/EVMToEwasmTranslator.h>
#include <libyul/backends/wasm/WordSizeTransform.h>
#include <libyul/backends/wasm/WasmDialect.h>
@ -138,6 +138,10 @@ function div(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 {
// TODO implement properly
r4 := i64.div_u(x4, y4)
}
function sdiv(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 {
// TODO implement properly
unreachable()
}
function mod(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 {
// TODO implement properly
r4 := i64.rem_u(x4, y4)
@ -318,11 +322,11 @@ function sar(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 {
// TODO implement
unreachable()
}
function addmod(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 {
function addmod(x1, x2, x3, x4, y1, y2, y3, y4, m1, m2, m3, m4) -> z1, z2, z3, z4 {
// TODO implement
unreachable()
}
function mulmod(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 {
function mulmod(x1, x2, x3, x4, y1, y2, y3, y4, m1, m2, m3, m4) -> z1, z2, z3, z4 {
// TODO implement
unreachable()
}
@ -397,8 +401,7 @@ function calldatacopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) {
// Needed?
function codesize() -> z1, z2, z3, z4 {
eth.getCodeSize(0)
z1, z2, z3, z4 := mload_internal(0)
z4 := eth.getCodeSize()
}
function codecopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) {
eth.codeCopy(
@ -698,7 +701,7 @@ function invalid() {
}
Object EVMToEWasmTranslator::run(Object const& _object)
Object EVMToEwasmTranslator::run(Object const& _object)
{
if (!m_polyfill)
parsePolyfill();
@ -746,7 +749,7 @@ Object EVMToEWasmTranslator::run(Object const& _object)
return ret;
}
void EVMToEWasmTranslator::parsePolyfill()
void EVMToEwasmTranslator::parsePolyfill()
{
ErrorList errors;
ErrorReporter errorReporter(errors);

View File

@ -15,7 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Translates Yul code from EVM dialect to eWasm dialect.
* Translates Yul code from EVM dialect to Ewasm dialect.
*/
#pragma once
@ -28,10 +28,10 @@ namespace yul
{
struct Object;
class EVMToEWasmTranslator: public ASTModifier
class EVMToEwasmTranslator: public ASTModifier
{
public:
EVMToEWasmTranslator(Dialect const& _evmDialect): m_dialect(_evmDialect) {}
EVMToEwasmTranslator(Dialect const& _evmDialect): m_dialect(_evmDialect) {}
Object run(Object const& _object);
private:

View File

@ -15,7 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Component that transforms interval Wasm representation to text.
* Component that transforms internal Wasm representation to text.
*/
#include <libyul/backends/wasm/TextTransform.h>

View File

@ -15,7 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Component that transforms interval Wasm representation to text.
* Component that transforms internal Wasm representation to text.
*/
#pragma once

View File

@ -15,10 +15,10 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Common code generator for translating Yul / inline assembly to EWasm.
* Common code generator for translating Yul / inline assembly to Wasm.
*/
#include <libyul/backends/wasm/EWasmCodeTransform.h>
#include <libyul/backends/wasm/WasmCodeTransform.h>
#include <libyul/optimiser/NameCollector.h>
@ -36,11 +36,11 @@ using namespace std;
using namespace dev;
using namespace yul;
wasm::Module EWasmCodeTransform::run(Dialect const& _dialect, yul::Block const& _ast)
wasm::Module WasmCodeTransform::run(Dialect const& _dialect, yul::Block const& _ast)
{
wasm::Module module;
EWasmCodeTransform transform(_dialect, _ast);
WasmCodeTransform transform(_dialect, _ast);
for (auto const& statement: _ast.statements)
{
@ -59,7 +59,7 @@ wasm::Module EWasmCodeTransform::run(Dialect const& _dialect, yul::Block const&
return module;
}
wasm::Expression EWasmCodeTransform::generateMultiAssignment(
wasm::Expression WasmCodeTransform::generateMultiAssignment(
vector<string> _variableNames,
unique_ptr<wasm::Expression> _firstValue
)
@ -82,7 +82,7 @@ wasm::Expression EWasmCodeTransform::generateMultiAssignment(
return { std::move(block) };
}
wasm::Expression EWasmCodeTransform::operator()(VariableDeclaration const& _varDecl)
wasm::Expression WasmCodeTransform::operator()(VariableDeclaration const& _varDecl)
{
vector<string> variableNames;
for (auto const& var: _varDecl.variables)
@ -97,7 +97,7 @@ wasm::Expression EWasmCodeTransform::operator()(VariableDeclaration const& _varD
return wasm::BuiltinCall{"nop", {}};
}
wasm::Expression EWasmCodeTransform::operator()(Assignment const& _assignment)
wasm::Expression WasmCodeTransform::operator()(Assignment const& _assignment)
{
vector<string> variableNames;
for (auto const& var: _assignment.variableNames)
@ -105,12 +105,12 @@ wasm::Expression EWasmCodeTransform::operator()(Assignment const& _assignment)
return generateMultiAssignment(move(variableNames), visit(*_assignment.value));
}
wasm::Expression EWasmCodeTransform::operator()(ExpressionStatement const& _statement)
wasm::Expression WasmCodeTransform::operator()(ExpressionStatement const& _statement)
{
return visitReturnByValue(_statement.expression);
}
wasm::Expression EWasmCodeTransform::operator()(FunctionCall const& _call)
wasm::Expression WasmCodeTransform::operator()(FunctionCall const& _call)
{
bool typeConversionNeeded = false;
@ -171,19 +171,19 @@ wasm::Expression EWasmCodeTransform::operator()(FunctionCall const& _call)
return {std::move(funCall)};
}
wasm::Expression EWasmCodeTransform::operator()(Identifier const& _identifier)
wasm::Expression WasmCodeTransform::operator()(Identifier const& _identifier)
{
return wasm::LocalVariable{_identifier.name.str()};
}
wasm::Expression EWasmCodeTransform::operator()(Literal const& _literal)
wasm::Expression WasmCodeTransform::operator()(Literal const& _literal)
{
u256 value = valueOfLiteral(_literal);
yulAssert(value <= numeric_limits<uint64_t>::max(), "Literal too large: " + value.str());
return wasm::Literal{uint64_t(value)};
}
wasm::Expression EWasmCodeTransform::operator()(If const& _if)
wasm::Expression WasmCodeTransform::operator()(If const& _if)
{
// TODO converting i64 to i32 might not always be needed.
@ -197,7 +197,7 @@ wasm::Expression EWasmCodeTransform::operator()(If const& _if)
};
}
wasm::Expression EWasmCodeTransform::operator()(Switch const& _switch)
wasm::Expression WasmCodeTransform::operator()(Switch const& _switch)
{
wasm::Block block;
string condition = m_nameDispenser.newName("condition"_yulstring).str();
@ -237,13 +237,13 @@ wasm::Expression EWasmCodeTransform::operator()(Switch const& _switch)
return { std::move(block) };
}
wasm::Expression EWasmCodeTransform::operator()(FunctionDefinition const&)
wasm::Expression WasmCodeTransform::operator()(FunctionDefinition const&)
{
yulAssert(false, "Should not have visited here.");
return {};
}
wasm::Expression EWasmCodeTransform::operator()(ForLoop const& _for)
wasm::Expression WasmCodeTransform::operator()(ForLoop const& _for)
{
string breakLabel = newLabel();
string continueLabel = newLabel();
@ -262,37 +262,37 @@ wasm::Expression EWasmCodeTransform::operator()(ForLoop const& _for)
return { wasm::Block{breakLabel, make_vector<wasm::Expression>(move(loop))} };
}
wasm::Expression EWasmCodeTransform::operator()(Break const&)
wasm::Expression WasmCodeTransform::operator()(Break const&)
{
return wasm::Break{wasm::Label{m_breakContinueLabelNames.top().first}};
}
wasm::Expression EWasmCodeTransform::operator()(Continue const&)
wasm::Expression WasmCodeTransform::operator()(Continue const&)
{
return wasm::Break{wasm::Label{m_breakContinueLabelNames.top().second}};
}
wasm::Expression EWasmCodeTransform::operator()(Leave const&)
wasm::Expression WasmCodeTransform::operator()(Leave const&)
{
return wasm::Return{};
}
wasm::Expression EWasmCodeTransform::operator()(Block const& _block)
wasm::Expression WasmCodeTransform::operator()(Block const& _block)
{
return wasm::Block{{}, visit(_block.statements)};
}
unique_ptr<wasm::Expression> EWasmCodeTransform::visit(yul::Expression const& _expression)
unique_ptr<wasm::Expression> WasmCodeTransform::visit(yul::Expression const& _expression)
{
return make_unique<wasm::Expression>(std::visit(*this, _expression));
}
wasm::Expression EWasmCodeTransform::visitReturnByValue(yul::Expression const& _expression)
wasm::Expression WasmCodeTransform::visitReturnByValue(yul::Expression const& _expression)
{
return std::visit(*this, _expression);
}
vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Expression> const& _expressions)
vector<wasm::Expression> WasmCodeTransform::visit(vector<yul::Expression> const& _expressions)
{
vector<wasm::Expression> ret;
for (auto const& e: _expressions)
@ -300,12 +300,12 @@ vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Expression> const
return ret;
}
wasm::Expression EWasmCodeTransform::visit(yul::Statement const& _statement)
wasm::Expression WasmCodeTransform::visit(yul::Statement const& _statement)
{
return std::visit(*this, _statement);
}
vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Statement> const& _statements)
vector<wasm::Expression> WasmCodeTransform::visit(vector<yul::Statement> const& _statements)
{
vector<wasm::Expression> ret;
for (auto const& s: _statements)
@ -313,7 +313,7 @@ vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Statement> const&
return ret;
}
wasm::FunctionDefinition EWasmCodeTransform::translateFunction(yul::FunctionDefinition const& _fun)
wasm::FunctionDefinition WasmCodeTransform::translateFunction(yul::FunctionDefinition const& _fun)
{
wasm::FunctionDefinition fun;
fun.name = _fun.name.str();
@ -344,7 +344,7 @@ wasm::FunctionDefinition EWasmCodeTransform::translateFunction(yul::FunctionDefi
return fun;
}
wasm::Expression EWasmCodeTransform::injectTypeConversionIfNeeded(wasm::FunctionCall _call) const
wasm::Expression WasmCodeTransform::injectTypeConversionIfNeeded(wasm::FunctionCall _call) const
{
wasm::FunctionImport const& import = m_functionsToImport.at(YulString{_call.functionName});
for (size_t i = 0; i < _call.arguments.size(); ++i)
@ -361,7 +361,7 @@ wasm::Expression EWasmCodeTransform::injectTypeConversionIfNeeded(wasm::Function
return {std::move(_call)};
}
vector<wasm::Expression> EWasmCodeTransform::injectTypeConversionIfNeeded(
vector<wasm::Expression> WasmCodeTransform::injectTypeConversionIfNeeded(
vector<wasm::Expression> _arguments,
vector<Type> const& _parameterTypes
) const
@ -378,12 +378,12 @@ vector<wasm::Expression> EWasmCodeTransform::injectTypeConversionIfNeeded(
return _arguments;
}
string EWasmCodeTransform::newLabel()
string WasmCodeTransform::newLabel()
{
return m_nameDispenser.newName("label_"_yulstring).str();
}
void EWasmCodeTransform::allocateGlobals(size_t _amount)
void WasmCodeTransform::allocateGlobals(size_t _amount)
{
while (m_globalVariables.size() < _amount)
m_globalVariables.emplace_back(wasm::GlobalVariableDeclaration{

View File

@ -15,7 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Common code generator for translating Yul / inline assembly to EWasm.
* Common code generator for translating Yul / inline assembly to Wasm.
*/
#pragma once
@ -32,7 +32,7 @@ namespace yul
{
struct AsmAnalysisInfo;
class EWasmCodeTransform
class WasmCodeTransform
{
public:
static wasm::Module run(Dialect const& _dialect, yul::Block const& _ast);
@ -54,7 +54,7 @@ public:
wasm::Expression operator()(yul::Block const& _block);
private:
EWasmCodeTransform(
WasmCodeTransform(
Dialect const& _dialect,
Block const& _ast
):

View File

@ -56,10 +56,16 @@ WasmDialect::WasmDialect():
addFunction("i64.eqz", 1, 1);
m_functions["i64.eqz"_yulstring].returns.front() = "i32"_yulstring;
addFunction("i64.clz", 1, 1);
addFunction("i64.store", 2, 0, false);
m_functions["i64.store"_yulstring].parameters.front() = "i32"_yulstring;
m_functions["i64.store"_yulstring].sideEffects.invalidatesStorage = false;
addFunction("i64.store8", 2, 0, false);
m_functions["i64.store8"_yulstring].parameters.front() = "i32"_yulstring;
m_functions["i64.store8"_yulstring].sideEffects.invalidatesStorage = false;
addFunction("i64.load", 1, 1, false);
m_functions["i64.load"_yulstring].parameters.front() = "i32"_yulstring;
m_functions["i64.load"_yulstring].sideEffects.invalidatesStorage = false;
@ -120,7 +126,7 @@ void WasmDialect::addEthereumExternals()
{"getCaller", {i32ptr}, {}},
{"getCallValue", {i32ptr}, {}},
{"codeCopy", {i32ptr, i32, i32}, {}},
{"getCodeSize", {i32ptr}, {}},
{"getCodeSize", {}, {i32}},
{"getBlockCoinbase", {i32ptr}, {}},
{"create", {i32ptr, i32ptr, i32, i32ptr}, {i32}},
{"getBlockDifficulty", {i32ptr}, {}},

View File

@ -18,9 +18,9 @@
* Compiler that transforms Yul Objects to Wasm text and binary representation (Ewasm flavoured).
*/
#include <libyul/backends/wasm/EWasmObjectCompiler.h>
#include <libyul/backends/wasm/WasmObjectCompiler.h>
#include <libyul/backends/wasm/EWasmCodeTransform.h>
#include <libyul/backends/wasm/WasmCodeTransform.h>
#include <libyul/backends/wasm/BinaryTransform.h>
#include <libyul/backends/wasm/TextTransform.h>
@ -32,25 +32,25 @@
using namespace yul;
using namespace std;
pair<string, dev::bytes> EWasmObjectCompiler::compile(Object& _object, Dialect const& _dialect)
pair<string, dev::bytes> WasmObjectCompiler::compile(Object& _object, Dialect const& _dialect)
{
EWasmObjectCompiler compiler(_dialect);
WasmObjectCompiler compiler(_dialect);
wasm::Module module = compiler.run(_object);
return {wasm::TextTransform().run(module), wasm::BinaryTransform::run(module)};
}
wasm::Module EWasmObjectCompiler::run(Object& _object)
wasm::Module WasmObjectCompiler::run(Object& _object)
{
yulAssert(_object.analysisInfo, "No analysis info.");
yulAssert(_object.code, "No code.");
wasm::Module module = EWasmCodeTransform::run(m_dialect, *_object.code);
wasm::Module module = WasmCodeTransform::run(m_dialect, *_object.code);
for (auto& subNode: _object.subObjects)
if (Object* subObject = dynamic_cast<Object*>(subNode.get()))
module.subModules[subObject->name.str()] = run(*subObject);
else
yulAssert(false, "Data is not yet supported for EWasm.");
yulAssert(false, "Data is not yet supported for Wasm.");
return module;
}

View File

@ -28,6 +28,7 @@ namespace dev
{
using bytes = std::vector<uint8_t>;
}
namespace yul
{
struct Object;
@ -37,13 +38,13 @@ namespace wasm
struct Module;
}
class EWasmObjectCompiler
class WasmObjectCompiler
{
public:
/// Compiles the given object and returns the WAST and the binary representation.
/// Compiles the given object and returns the Wasm text and binary representation.
static std::pair<std::string, dev::bytes> compile(Object& _object, Dialect const& _dialect);
private:
EWasmObjectCompiler(Dialect const& _dialect):
WasmObjectCompiler(Dialect const& _dialect):
m_dialect(_dialect)
{}

View File

@ -280,29 +280,28 @@ void RedundantAssignEliminator::changeUndecidedTo(YulString _variable, Redundant
void RedundantAssignEliminator::finalize(YulString _variable, RedundantAssignEliminator::State _finalState)
{
finalize(m_assignments, _variable, _finalState);
for (auto& assignments: m_forLoopInfo.pendingBreakStmts)
finalize(assignments, _variable, _finalState);
for (auto& assignments: m_forLoopInfo.pendingContinueStmts)
finalize(assignments, _variable, _finalState);
}
std::map<Assignment const*, State> assignments;
joinMap(assignments, std::move(m_assignments[_variable]), State::join);
m_assignments.erase(_variable);
void RedundantAssignEliminator::finalize(
TrackedAssignments& _assignments,
YulString _variable,
RedundantAssignEliminator::State _finalState
)
{
for (auto const& assignment: _assignments[_variable])
for (auto& breakAssignments: m_forLoopInfo.pendingBreakStmts)
{
joinMap(assignments, std::move(breakAssignments[_variable]), State::join);
breakAssignments.erase(_variable);
}
for (auto& continueAssignments: m_forLoopInfo.pendingContinueStmts)
{
joinMap(assignments, std::move(continueAssignments[_variable]), State::join);
continueAssignments.erase(_variable);
}
for (auto const& assignment: assignments)
{
State const state = assignment.second == State::Undecided ? _finalState : assignment.second;
if (state == State::Unused && SideEffectsCollector{*m_dialect, *assignment.first->value}.movable())
// TODO the only point where we actually need this
// to be a set is for the for loop
m_pendingRemovals.insert(assignment.first);
}
_assignments.erase(_variable);
}
void AssignmentRemover::operator()(Block& _block)

View File

@ -161,8 +161,6 @@ private:
/// assignments to the final state. In this case, this also applies to pending
/// break and continue TrackedAssignments.
void finalize(YulString _variable, State _finalState);
/// Helper function for the above.
void finalize(TrackedAssignments& _assignments, YulString _variable, State _finalState);
Dialect const* m_dialect;
std::set<YulString> m_declaredVariables;

View File

@ -116,7 +116,7 @@ static string const g_strErrorRecovery = "error-recovery";
static string const g_strEVM = "evm";
static string const g_strEVM15 = "evm15";
static string const g_strEVMVersion = "evm-version";
static string const g_streWasm = "ewasm";
static string const g_strEwasm = "ewasm";
static string const g_strGas = "gas";
static string const g_strHelp = "help";
static string const g_strInputFile = "input-file";
@ -125,7 +125,6 @@ static string const g_strYul = "yul";
static string const g_strYulDialect = "yul-dialect";
static string const g_strIR = "ir";
static string const g_strIPFS = "ipfs";
static string const g_strEWasm = "ewasm";
static string const g_strLicense = "license";
static string const g_strLibraries = "libraries";
static string const g_strLink = "link";
@ -187,7 +186,7 @@ static string const g_argHelp = g_strHelp;
static string const g_argInputFile = g_strInputFile;
static string const g_argYul = g_strYul;
static string const g_argIR = g_strIR;
static string const g_argEWasm = g_strEWasm;
static string const g_argEwasm = g_strEwasm;
static string const g_argLibraries = g_strLibraries;
static string const g_argLink = g_strLink;
static string const g_argMachine = g_strMachine;
@ -234,14 +233,14 @@ static set<string> const g_machineArgs
{
g_strEVM,
g_strEVM15,
g_streWasm
g_strEwasm
};
/// Possible arguments to for --yul-dialect
static set<string> const g_yulDialectArgs
{
g_strEVM,
g_streWasm
g_strEwasm
};
/// Possible arguments to for --metadata-hash
@ -345,23 +344,23 @@ void CommandLineInterface::handleIR(string const& _contractName)
}
}
void CommandLineInterface::handleEWasm(string const& _contractName)
void CommandLineInterface::handleEwasm(string const& _contractName)
{
if (m_args.count(g_argEWasm))
if (m_args.count(g_argEwasm))
{
if (m_args.count(g_argOutputDir))
{
createFile(m_compiler->filesystemFriendlyName(_contractName) + ".wast", m_compiler->eWasm(_contractName));
createFile(m_compiler->filesystemFriendlyName(_contractName) + ".wast", m_compiler->ewasm(_contractName));
createFile(
m_compiler->filesystemFriendlyName(_contractName) + ".wasm",
asString(m_compiler->eWasmObject(_contractName).bytecode)
asString(m_compiler->ewasmObject(_contractName).bytecode)
);
}
else
{
sout() << "EWasm text:" << endl;
sout() << m_compiler->eWasm(_contractName) << endl;
sout() << "EWasm binary (hex): " << m_compiler->eWasmObject(_contractName).toHex() << endl;
sout() << "Ewasm text:" << endl;
sout() << m_compiler->ewasm(_contractName) << endl;
sout() << "Ewasm binary (hex): " << m_compiler->ewasmObject(_contractName).toHex() << endl;
}
}
}
@ -776,7 +775,7 @@ Allowed options)",
(g_argBinaryRuntime.c_str(), "Binary of the runtime part of the contracts in hex.")
(g_argAbi.c_str(), "ABI specification of the contracts.")
(g_argIR.c_str(), "Intermediate Representation (IR) of all contracts (EXPERIMENTAL).")
(g_argEWasm.c_str(), "EWasm text representation of all contracts (EXPERIMENTAL).")
(g_argEwasm.c_str(), "Ewasm text representation of all contracts (EXPERIMENTAL).")
(g_argSignatureHashes.c_str(), "Function signature hashes of the contracts.")
(g_argNatspecUser.c_str(), "Natspec user documentation of all contracts.")
(g_argNatspecDev.c_str(), "Natspec developer documentation of all contracts.")
@ -981,27 +980,27 @@ bool CommandLineInterface::processInput()
targetMachine = Machine::EVM;
else if (machine == g_strEVM15)
targetMachine = Machine::EVM15;
else if (machine == g_streWasm)
targetMachine = Machine::eWasm;
else if (machine == g_strEwasm)
targetMachine = Machine::Ewasm;
else
{
serr() << "Invalid option for --machine: " << machine << endl;
return false;
}
}
if (targetMachine == Machine::eWasm && inputLanguage == Input::StrictAssembly)
inputLanguage = Input::EWasm;
if (targetMachine == Machine::Ewasm && inputLanguage == Input::StrictAssembly)
inputLanguage = Input::Ewasm;
if (m_args.count(g_strYulDialect))
{
string dialect = m_args[g_strYulDialect].as<string>();
if (dialect == g_strEVM)
inputLanguage = Input::StrictAssembly;
else if (dialect == g_streWasm)
else if (dialect == g_strEwasm)
{
inputLanguage = Input::EWasm;
if (targetMachine != Machine::eWasm)
inputLanguage = Input::Ewasm;
if (targetMachine != Machine::Ewasm)
{
serr() << "If you select eWasm as --yul-dialect, --machine has to be eWasm as well." << endl;
serr() << "If you select Ewasm as --yul-dialect, --machine has to be Ewasm as well." << endl;
return false;
}
}
@ -1011,7 +1010,7 @@ bool CommandLineInterface::processInput()
return false;
}
}
if (optimize && (inputLanguage != Input::StrictAssembly && inputLanguage != Input::EWasm))
if (optimize && (inputLanguage != Input::StrictAssembly && inputLanguage != Input::Ewasm))
{
serr() <<
"Optimizer can only be used for strict assembly. Use --" <<
@ -1074,7 +1073,7 @@ bool CommandLineInterface::processInput()
// TODO: Perhaps we should not compile unless requested
m_compiler->enableIRGeneration(m_args.count(g_argIR));
m_compiler->enableEWasmGeneration(m_args.count(g_argEWasm));
m_compiler->enableEwasmGeneration(m_args.count(g_argEwasm));
OptimiserSettings settings = m_args.count(g_argOptimize) ? OptimiserSettings::standard() : OptimiserSettings::minimal();
settings.expectedExecutionsPerDeployment = m_args[g_argOptimizeRuns].as<unsigned>();
@ -1453,7 +1452,7 @@ bool CommandLineInterface::assemble(
string machine =
_targetMachine == yul::AssemblyStack::Machine::EVM ? "EVM" :
_targetMachine == yul::AssemblyStack::Machine::EVM15 ? "EVM 1.5" :
"eWasm";
"Ewasm";
sout() << endl << "======= " << src.first << " (" << machine << ") =======" << endl;
yul::AssemblyStack& stack = assemblyStacks[src.first];
@ -1461,9 +1460,9 @@ bool CommandLineInterface::assemble(
sout() << endl << "Pretty printed source:" << endl;
sout() << stack.print() << endl;
if (_language != yul::AssemblyStack::Language::EWasm && _targetMachine == yul::AssemblyStack::Machine::eWasm)
if (_language != yul::AssemblyStack::Language::Ewasm && _targetMachine == yul::AssemblyStack::Machine::Ewasm)
{
stack.translate(yul::AssemblyStack::Language::EWasm);
stack.translate(yul::AssemblyStack::Language::Ewasm);
stack.optimize();
sout() << endl << "==========================" << endl;
@ -1554,7 +1553,7 @@ void CommandLineInterface::outputCompilationResults()
handleBytecode(contract);
handleIR(contract);
handleEWasm(contract);
handleEwasm(contract);
handleSignatureHashes(contract);
handleMetadata(contract);
handleABI(contract);

View File

@ -67,7 +67,7 @@ private:
void handleBinary(std::string const& _contract);
void handleOpcode(std::string const& _contract);
void handleIR(std::string const& _contract);
void handleEWasm(std::string const& _contract);
void handleEwasm(std::string const& _contract);
void handleBytecode(std::string const& _contract);
void handleSignatureHashes(std::string const& _contract);
void handleMetadata(std::string const& _contract);

View File

@ -131,8 +131,8 @@ set(libyul_sources
libyul/Common.cpp
libyul/Common.h
libyul/CompilabilityChecker.cpp
libyul/EWasmTranslationTest.cpp
libyul/EWasmTranslationTest.h
libyul/EwasmTranslationTest.cpp
libyul/EwasmTranslationTest.h
libyul/FunctionSideEffects.cpp
libyul/FunctionSideEffects.h
libyul/Inliner.cpp

View File

@ -25,7 +25,7 @@
#include <test/libsolidity/SemanticTest.h>
#include <test/libsolidity/SMTCheckerTest.h>
#include <test/libsolidity/SMTCheckerJSONTest.h>
#include <test/libyul/EWasmTranslationTest.h>
#include <test/libyul/EwasmTranslationTest.h>
#include <test/libyul/YulOptimizerTest.h>
#include <test/libyul/YulInterpreterTest.h>
#include <test/libyul/ObjectCompilerTest.h>
@ -56,7 +56,7 @@ struct Testsuite
Testsuite const g_interactiveTestsuites[] = {
/*
Title Path Subpath SMT NeedsVM Creator function */
{"EWasm Translation", "libyul", "ewasmTranslationTests",false,false, &yul::test::EWasmTranslationTest::create},
{"Ewasm Translation", "libyul", "ewasmTranslationTests",false,false, &yul::test::EwasmTranslationTest::create},
{"Yul Optimizer", "libyul", "yulOptimizerTests", false, false, &yul::test::YulOptimizerTest::create},
{"Yul Interpreter", "libyul", "yulInterpreterTests", false, false, &yul::test::YulInterpreterTest::create},
{"Yul Object Compiler", "libyul", "objectCompiler", false, false, &yul::test::ObjectCompilerTest::create},

View File

@ -1,5 +1,5 @@
======= evm_to_wasm/input.sol (eWasm) =======
======= evm_to_wasm/input.sol (Ewasm) =======
Pretty printed source:
object "object" {

View File

@ -99,7 +99,7 @@ BOOST_AUTO_TEST_CASE(string_storage)
auto evmVersion = dev::test::Options::get().evmVersion();
if (evmVersion <= EVMVersion::byzantium())
CHECK_DEPLOY_GAS(134145, 130831, evmVersion);
CHECK_DEPLOY_GAS(134209, 130895, evmVersion);
// This is only correct on >=Constantinople.
else if (Options::get().useABIEncoderV2)
{
@ -107,22 +107,22 @@ BOOST_AUTO_TEST_CASE(string_storage)
{
// Costs with 0 are cases which cannot be triggered in tests.
if (evmVersion < EVMVersion::istanbul())
CHECK_DEPLOY_GAS(0, 123969, evmVersion);
CHECK_DEPLOY_GAS(0, 124033, evmVersion);
else
CHECK_DEPLOY_GAS(0, 110969, evmVersion);
CHECK_DEPLOY_GAS(0, 110981, evmVersion);
}
else
{
if (evmVersion < EVMVersion::istanbul())
CHECK_DEPLOY_GAS(147771, 131687, evmVersion);
CHECK_DEPLOY_GAS(147835, 131687, evmVersion);
else
CHECK_DEPLOY_GAS(131859, 117231, evmVersion);
CHECK_DEPLOY_GAS(131871, 117231, evmVersion);
}
}
else if (evmVersion < EVMVersion::istanbul())
CHECK_DEPLOY_GAS(126929, 119659, evmVersion);
CHECK_DEPLOY_GAS(126993, 119723, evmVersion);
else
CHECK_DEPLOY_GAS(114345, 107335, evmVersion);
CHECK_DEPLOY_GAS(114357, 107347, evmVersion);
if (evmVersion >= EVMVersion::byzantium())
{

View File

@ -14319,8 +14319,6 @@ BOOST_AUTO_TEST_CASE(event_wrong_abi_name)
)";
compileAndRun(sourceCode, 0, "ClientReceipt", bytes());
compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{"ClientReceipt", m_contractAddress}});
u256 value(18);
u256 id(0x1234);
callContractFunction("f()");
BOOST_REQUIRE_EQUAL(numLogs(), 1);

View File

@ -15,7 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
#include <test/libyul/EWasmTranslationTest.h>
#include <test/libyul/EwasmTranslationTest.h>
#include <test/tools/yulInterpreter/Interpreter.h>
@ -23,7 +23,7 @@
#include <libyul/backends/evm/EVMDialect.h>
#include <libyul/backends/wasm/WasmDialect.h>
#include <libyul/backends/wasm/EVMToEWasmTranslator.h>
#include <libyul/backends/wasm/EVMToEwasmTranslator.h>
#include <libyul/AsmParser.h>
#include <libyul/AssemblyStack.h>
#include <libyul/AsmAnalysisInfo.h>
@ -47,7 +47,7 @@ using namespace dev::solidity::test;
using namespace std;
EWasmTranslationTest::EWasmTranslationTest(string const& _filename)
EwasmTranslationTest::EwasmTranslationTest(string const& _filename)
{
boost::filesystem::path path(_filename);
@ -60,12 +60,12 @@ EWasmTranslationTest::EWasmTranslationTest(string const& _filename)
m_expectation = parseSimpleExpectations(file);
}
TestCase::TestResult EWasmTranslationTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
TestCase::TestResult EwasmTranslationTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
{
if (!parse(_stream, _linePrefix, _formatted))
return TestResult::FatalError;
*m_object = EVMToEWasmTranslator(
*m_object = EVMToEwasmTranslator(
EVMDialect::strictAssemblyForEVMObjects(dev::test::Options::get().evmVersion())
).run(*m_object);
@ -89,17 +89,17 @@ TestCase::TestResult EWasmTranslationTest::run(ostream& _stream, string const& _
return TestResult::Success;
}
void EWasmTranslationTest::printSource(ostream& _stream, string const& _linePrefix, bool const) const
void EwasmTranslationTest::printSource(ostream& _stream, string const& _linePrefix, bool const) const
{
printIndented(_stream, m_source, _linePrefix);
}
void EWasmTranslationTest::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const
void EwasmTranslationTest::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const
{
printIndented(_stream, m_obtainedResult, _linePrefix);
}
void EWasmTranslationTest::printIndented(ostream& _stream, string const& _output, string const& _linePrefix) const
void EwasmTranslationTest::printIndented(ostream& _stream, string const& _output, string const& _linePrefix) const
{
stringstream output(_output);
string line;
@ -107,7 +107,7 @@ void EWasmTranslationTest::printIndented(ostream& _stream, string const& _output
_stream << _linePrefix << line << endl;
}
bool EWasmTranslationTest::parse(ostream& _stream, string const& _linePrefix, bool const _formatted)
bool EwasmTranslationTest::parse(ostream& _stream, string const& _linePrefix, bool const _formatted)
{
AssemblyStack stack(
dev::test::Options::get().evmVersion(),
@ -127,11 +127,11 @@ bool EWasmTranslationTest::parse(ostream& _stream, string const& _linePrefix, bo
}
}
string EWasmTranslationTest::interpret()
string EwasmTranslationTest::interpret()
{
InterpreterState state;
state.maxTraceSize = 10000;
state.maxSteps = 10000;
state.maxSteps = 100000;
WasmDialect dialect;
Interpreter interpreter(state, dialect);
try
@ -147,7 +147,7 @@ string EWasmTranslationTest::interpret()
return result.str();
}
void EWasmTranslationTest::printErrors(ostream& _stream, ErrorList const& _errors)
void EwasmTranslationTest::printErrors(ostream& _stream, ErrorList const& _errors)
{
SourceReferenceFormatter formatter(_stream);

View File

@ -32,15 +32,15 @@ namespace yul
namespace test
{
class EWasmTranslationTest: public dev::solidity::test::EVMVersionRestrictedTestCase
class EwasmTranslationTest: public dev::solidity::test::EVMVersionRestrictedTestCase
{
public:
static std::unique_ptr<TestCase> create(Config const& _config)
{
return std::make_unique<EWasmTranslationTest>(_config.filename);
return std::make_unique<EwasmTranslationTest>(_config.filename);
}
explicit EWasmTranslationTest(std::string const& _filename);
explicit EwasmTranslationTest(std::string const& _filename);
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override;

View File

@ -60,6 +60,7 @@
#include <libyul/backends/evm/EVMDialect.h>
#include <libyul/backends/evm/EVMMetrics.h>
#include <libyul/backends/wasm/WordSizeTransform.h>
#include <libyul/backends/wasm/WasmDialect.h>
#include <libyul/AsmPrinter.h>
#include <libyul/AsmParser.h>
#include <libyul/AsmAnalysis.h>
@ -98,12 +99,24 @@ YulOptimizerTest::YulOptimizerTest(string const& _filename)
file.exceptions(ios::badbit);
m_source = parseSourceAndSettings(file);
if (m_settings.count("yul"))
if (m_settings.count("dialect"))
{
m_yul = true;
m_validatedSettings["yul"] = "true";
m_settings.erase("yul");
auto dialectName = m_settings["dialect"];
if (dialectName == "yul")
m_dialect = &Dialect::yul();
else if (dialectName == "ewasm")
m_dialect = &WasmDialect::instance();
else if (dialectName == "evm")
m_dialect = &EVMDialect::strictAssemblyForEVMObjects(dev::test::Options::get().evmVersion());
else
BOOST_THROW_EXCEPTION(runtime_error("Invalid dialect " + dialectName));
m_validatedSettings["dialect"] = dialectName;
m_settings.erase("dialect");
}
else
m_dialect = &EVMDialect::strictAssemblyForEVMObjects(dev::test::Options::get().evmVersion());
if (m_settings.count("step"))
{
m_validatedSettings["step"] = m_settings["step"];
@ -350,7 +363,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
return TestResult::FatalError;
}
m_obtainedResult = AsmPrinter{m_yul}(*m_ast) + "\n";
m_obtainedResult = AsmPrinter{m_dialect->flavour == AsmFlavour::Yul}(*m_ast) + "\n";
if (m_optimizerStep != m_validatedSettings["step"])
{
@ -406,7 +419,7 @@ bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool c
{
AssemblyStack stack(
dev::test::Options::get().evmVersion(),
m_yul ? AssemblyStack::Language::Yul : AssemblyStack::Language::StrictAssembly,
m_dialect->flavour == AsmFlavour::Yul ? AssemblyStack::Language::Yul : AssemblyStack::Language::StrictAssembly,
dev::solidity::OptimiserSettings::none()
);
if (!stack.parseAndAnalyze("", m_source) || !stack.errors().empty())
@ -415,7 +428,6 @@ bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool c
printErrors(_stream, stack.errors());
return false;
}
m_dialect = m_yul ? &Dialect::yul() : &EVMDialect::strictAssemblyForEVMObjects(dev::test::Options::get().evmVersion());
m_ast = stack.parserResult()->code;
m_analysisInfo = stack.parserResult()->analysisInfo;
return true;

View File

@ -71,7 +71,6 @@ private:
static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors);
std::string m_source;
bool m_yul = false;
std::string m_optimizerStep;
std::string m_expectation;

View File

@ -0,0 +1,35 @@
{
sstore(0, add(0, 1))
sstore(1, add(1, not(0)))
sstore(2, add(0, 0))
sstore(3, add(1, 2))
sstore(4, add(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 1))
sstore(5, add(
0x8000000000000000000000000000000000000000000000000000000000000000, 1
))
sstore(6, add(not(0), 1))
sstore(7, add(0xffffffffffffffffffffffffffffffff, 1))
sstore(8, add(0xffffffffffffffff, 1))
sstore(9, add(0xffffffffffffffffffffffffffffffff0000000000000000, 1))
sstore(10, add(0xffffffffffffffffffffffffffffffffffffffffffffffff, 3))
sstore(11, add(0xffffffffffffffffffffffffffffffff, 3))
sstore(12, add(0xffffffffffffffff, 3))
sstore(13, add(0xffffffffffffffffffffffffffffffff0000000000000000, 3))
}
// ----
// Trace:
// Memory dump:
// 0: 000000000000000000000000000000000000000000000000000000000000000d
// 20: 0000000000000000ffffffffffffffffffffffffffffffff0000000000000003
// Storage dump:
// 0000000000000000000000000000000000000000000000000000000000000000: 0000000000000000000000000000000000000000000000000000000000000001
// 0000000000000000000000000000000000000000000000000000000000000003: 0000000000000000000000000000000000000000000000000000000000000003
// 0000000000000000000000000000000000000000000000000000000000000004: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000005: 8000000000000000000000000000000000000000000000000000000000000001
// 0000000000000000000000000000000000000000000000000000000000000007: 0000000000000000000000000000000100000000000000000000000000000000
// 0000000000000000000000000000000000000000000000000000000000000008: 0000000000000000000000000000000000000000000000010000000000000000
// 0000000000000000000000000000000000000000000000000000000000000009: 0000000000000000ffffffffffffffffffffffffffffffff0000000000000001
// 000000000000000000000000000000000000000000000000000000000000000a: 0000000000000001000000000000000000000000000000000000000000000002
// 000000000000000000000000000000000000000000000000000000000000000b: 0000000000000000000000000000000100000000000000000000000000000002
// 000000000000000000000000000000000000000000000000000000000000000c: 0000000000000000000000000000000000000000000000010000000000000002
// 000000000000000000000000000000000000000000000000000000000000000d: 0000000000000000ffffffffffffffffffffffffffffffff0000000000000003

View File

@ -0,0 +1,20 @@
{
sstore(0, addmod(0, 1, 1))
sstore(1, addmod(0, 1, 2))
sstore(2, addmod(3, 1, 2))
sstore(3, addmod(1, not(0), 5))
sstore(4, addmod(0, 0, 0))
sstore(5, addmod(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 1, 1))
sstore(6, addmod(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 1, 0))
sstore(7, addmod(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd, 1, 5))
sstore(8, addmod(
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff,
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe,
5
))
}
// ----
// Trace:
// INVALID()
// Memory dump:
// Storage dump:

View File

@ -0,0 +1,23 @@
{
sstore(0, div(0, 1))
sstore(1, div(1, not(0)))
sstore(2, div(0, 0))
sstore(3, div(1, 2))
sstore(4, div(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 1))
sstore(5, div(
0x8000000000000000000000000000000000000000000000000000000000000000, 1
))
sstore(6, div(not(0), 1))
sstore(7, div(0xffffffffffffffffffffffffffffffff, 1))
sstore(8, div(0xffffffffffffffff, 1))
sstore(9, div(0xffffffffffffffffffffffffffffffff0000000000000000, 1))
sstore(10, div(0xffffffffffffffffffffffffffffffffffffffffffffffff, 3))
sstore(11, div(0xffffffffffffffffffffffffffffffff, 3))
sstore(12, div(0xffffffffffffffff, 3))
sstore(13, div(0xffffffffffffffffffffffffffffffff0000000000000000, 3))
}
// ----
// Trace:
// Memory dump:
// 0: 0000000000000000000000000000000000000000000000000000000000000001
// Storage dump:

View File

@ -0,0 +1,25 @@
{
sstore(0, exp(0, 1))
sstore(1, exp(1, not(0)))
sstore(2, exp(0, 0))
sstore(3, exp(1, 2))
sstore(4, exp(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 1))
sstore(5, exp(
0x8000000000000000000000000000000000000000000000000000000000000000, 1
))
sstore(6, exp(not(0), 1))
sstore(7, exp(0xffffffffffffffffffffffffffffffff, 2))
sstore(8, exp(0xffffffffffffffff, 2))
sstore(9, exp(0xffffffffffffffffffffffffffffffff0000000000000000, 2))
sstore(10, exp(0xffffffffffffffffffffffffffffffffffffffffffffffff, 3))
sstore(11, exp(0xffffffffffffffffffffffffffffffff, 3))
sstore(12, exp(0xffffffffffffffff, 3))
sstore(13, exp(0xffffffffffffffffffffffffffffffff0000000000000000, 3))
sstore(14, exp(2, 256))
sstore(15, exp(2, 255))
}
// ----
// Trace:
// INVALID()
// Memory dump:
// Storage dump:

View File

@ -0,0 +1,25 @@
{
sstore(0, mod(0, 1))
sstore(1, mod(1, not(0)))
sstore(2, mod(0, 0))
sstore(3, mod(1, 2))
sstore(4, mod(not(0), 1))
sstore(5, mod(
0x8000000000000000000000000000000000000000000000000000000000000000, 1
))
sstore(6, mod(not(0), 1))
sstore(7, mod(0xffffffffffffffffffffffffffffffff, 1))
sstore(8, mod(0xffffffffffffffffffffffffffffffffffffffffffffffff, 0xfffffffffffffffffffffffffffffffe))
sstore(9, mod(0xffffffffffffffffffffffffffffffffffffffffffffffff, 5))
sstore(10, mod(0xffffffffffffffffffffffffffffffffffffffffffffffff, 4))
sstore(11, mod(0xffffffffffffffffffffffffffffffff, 3))
sstore(12, mod(0xffffffffffffffff, 3))
sstore(13, mod(0xffffffffffffffffffffffffffffffff0000000000000000, 0xffffffffffffffff43342553000))
}
// ----
// Trace:
// Memory dump:
// 0: 0000000000000000000000000000000000000000000000000000000000000001
// 20: 0000000000000000000000000000000000000000000000000000000000000001
// Storage dump:
// 0000000000000000000000000000000000000000000000000000000000000001: 0000000000000000000000000000000000000000000000000000000000000001

View File

@ -0,0 +1,36 @@
{
sstore(0, mul(0, 1))
sstore(1, mul(1, not(0)))
sstore(2, mul(0, 0))
sstore(3, mul(1, 2))
sstore(4, mul(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 1))
sstore(5, mul(
0x8000000000000000000000000000000000000000000000000000000000000000, 1
))
sstore(6, mul(not(0), 1))
sstore(7, mul(0xffffffffffffffffffffffffffffffff, 1))
sstore(8, mul(0xffffffffffffffff, 1))
sstore(9, mul(0xffffffffffffffffffffffffffffffff0000000000000000, 1))
sstore(10, mul(0xffffffffffffffffffffffffffffffffffffffffffffffff, 3))
sstore(11, mul(0xffffffffffffffffffffffffffffffff, 3))
sstore(12, mul(0xffffffffffffffff, 3))
sstore(13, mul(0xffffffffffffffffffffffffffffffff0000000000000000, 3))
}
// ----
// Trace:
// Memory dump:
// 0: 000000000000000000000000000000000000000000000000000000000000000d
// 20: 0000000000000002fffffffffffffffffffffffffffffffd0000000000000000
// Storage dump:
// 0000000000000000000000000000000000000000000000000000000000000001: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000003: 0000000000000000000000000000000000000000000000000000000000000002
// 0000000000000000000000000000000000000000000000000000000000000004: fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe
// 0000000000000000000000000000000000000000000000000000000000000005: 8000000000000000000000000000000000000000000000000000000000000000
// 0000000000000000000000000000000000000000000000000000000000000006: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000007: 00000000000000000000000000000000ffffffffffffffffffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000008: 000000000000000000000000000000000000000000000000ffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000009: 0000000000000000ffffffffffffffffffffffffffffffff0000000000000000
// 000000000000000000000000000000000000000000000000000000000000000a: 0000000000000002fffffffffffffffffffffffffffffffffffffffffffffffd
// 000000000000000000000000000000000000000000000000000000000000000b: 00000000000000000000000000000002fffffffffffffffffffffffffffffffd
// 000000000000000000000000000000000000000000000000000000000000000c: 000000000000000000000000000000000000000000000002fffffffffffffffd
// 000000000000000000000000000000000000000000000000000000000000000d: 0000000000000002fffffffffffffffffffffffffffffffd0000000000000000

View File

@ -0,0 +1,22 @@
{
sstore(0, mulmod(0, 1, 2))
sstore(1, mulmod(1, not(0), 5))
sstore(2, mulmod(0, 0, 5))
sstore(3, mulmod(1, 3, 2))
sstore(4, mulmod(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe,
1,
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff))
sstore(5, mulmod(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 1, 1))
sstore(6, mulmod(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 1, 0))
sstore(7, mulmod(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd, 1, 5))
sstore(8, mulmod(
not(0),
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe,
25
))
}
// ----
// Trace:
// INVALID()
// Memory dump:
// Storage dump:

View File

@ -0,0 +1,25 @@
{
sstore(0, sdiv(0, 1))
sstore(1, sdiv(0, not(0)))
sstore(2, sdiv(0, 0))
sstore(3, sdiv(1, 2))
sstore(4, sdiv(not(0), 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe))
sstore(5, sdiv(0x8000000000000000000000000000000000000000000000000000000000000000, not(0)))
sstore(6, sdiv(not(0), 0x8000000000000000000000000000000000000000000000000000000000000000))
sstore(7, sdiv(0x7000000000000000000000000000000000000000000000000000000000000000, 1))
sstore(8, sdiv(1, 0x7000000000000000000000000000000000000000000000000000000000000000))
sstore(9, sdiv(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, not(0)))
sstore(10, sdiv(not(0), 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff))
sstore(11, sdiv(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 1))
sstore(12, sdiv(not(0), not(0)))
sstore(13, sdiv(
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe,
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe
))
sstore(14, sdiv(0x8000000000000000000000000000000000000000000000000000000000000001, not(0)))
}
// ----
// Trace:
// INVALID()
// Memory dump:
// Storage dump:

View File

@ -0,0 +1,29 @@
{
sstore(0, smod(0, 1))
sstore(1, smod(1, not(0)))
sstore(2, smod(0, 0))
sstore(3, smod(1, 2))
sstore(4, smod(not(0), 1))
sstore(5, smod(
0x8000000000000000000000000000000000000000000000000000000000000000, 1
))
sstore(6, smod(not(0), 1))
sstore(7, smod(0xffffffffffffffffffffffffffffffff, 1))
sstore(8, smod(0xffffffffffffffffffffffffffffffffffffffffffffffff, 0xfffffffffffffffffffffffffffffffe))
sstore(9, smod(0xffffffffffffffffffffffffffffffffffffffffffffffff, 5))
sstore(10, smod(0xffffffffffffffffffffffffffffffffffffffffffffffff, 4))
sstore(11, smod(0xffffffffffffffffffffffffffffffff, 3))
sstore(12, smod(0xffffffffffffffff, 3))
sstore(13, smod(0xffffffffffffffffffffffffffffffff0000000000000000, 0xffffffffffffffff43342553000))
sstore(14, smod(
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd,
0xffffffffffffffff43342553000
))
}
// ----
// Trace:
// Memory dump:
// 0: 0000000000000000000000000000000000000000000000000000000000000001
// 20: 0000000000000000000000000000000000000000000000000000000000000001
// Storage dump:
// 0000000000000000000000000000000000000000000000000000000000000001: 0000000000000000000000000000000000000000000000000000000000000001

View File

@ -0,0 +1,36 @@
{
sstore(0, sub(0, 1))
sstore(1, sub(1, not(0)))
sstore(2, sub(0, 0))
sstore(3, sub(1, 2))
sstore(4, sub(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 1))
sstore(5, sub(
0x8000000000000000000000000000000000000000000000000000000000000000, 1
))
sstore(6, sub(not(0), 1))
sstore(7, sub(not(0), not(0)))
sstore(8, sub(0x1000000000000000000000000000000000000000000000000, 1))
sstore(9, sub(0x100000000000000000000000000000000, 1))
sstore(10, sub(0x10000000000000000, 1))
sstore(11, sub(0x1000000000000000000000000000000000000000000000000, 3))
sstore(12, sub(0x100000000000000000000000000000000, 3))
sstore(13, sub(0x10000000000000000, 3))
}
// ----
// Trace:
// Memory dump:
// 0: 000000000000000000000000000000000000000000000000000000000000000d
// 20: 000000000000000000000000000000000000000000000000fffffffffffffffd
// Storage dump:
// 0000000000000000000000000000000000000000000000000000000000000000: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000001: 0000000000000000000000000000000000000000000000000000000000000002
// 0000000000000000000000000000000000000000000000000000000000000003: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000004: fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe
// 0000000000000000000000000000000000000000000000000000000000000005: 7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000006: fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe
// 0000000000000000000000000000000000000000000000000000000000000008: 0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
// 0000000000000000000000000000000000000000000000000000000000000009: 00000000000000000000000000000000ffffffffffffffffffffffffffffffff
// 000000000000000000000000000000000000000000000000000000000000000a: 000000000000000000000000000000000000000000000000ffffffffffffffff
// 000000000000000000000000000000000000000000000000000000000000000b: 0000000000000000fffffffffffffffffffffffffffffffffffffffffffffffd
// 000000000000000000000000000000000000000000000000000000000000000c: 00000000000000000000000000000000fffffffffffffffffffffffffffffffd
// 000000000000000000000000000000000000000000000000000000000000000d: 000000000000000000000000000000000000000000000000fffffffffffffffd

View File

@ -4,11 +4,16 @@
let z := shr(136, y)
sstore(0, y)
sstore(1, z)
sstore(2, sar(136, 0x801112131415161718191a1b1c1d1e1f20000000000000000000000000000000))
sstore(3, sar(256, 0x801112131415161718191a1b1c1d1e1f20000000000000000000000000000000))
sstore(4, sar(136, 0x701112131415161718191a1b1c1d1e1f20000000000000000000000000000000))
sstore(5, sar(256, 0x701112131415161718191a1b1c1d1e1f20000000000000000000000000000000))
}
// ====
// EVMVersion: >=constantinople
// ----
// Trace:
// INVALID()
// Memory dump:
// 0: 0000000000000000000000000000000000000000000000000000000000000001
// 20: 0000000000000000000000000000000000101112131415161718191a1b1c1d1e

View File

@ -0,0 +1,11 @@
{
sstore(0, signextend(0, 0x86))
sstore(1, signextend(0, 0x76))
sstore(2, signextend(32, not(0)))
sstore(3, signextend(5, 0xff8844553322))
}
// ----
// Trace:
// INVALID()
// Memory dump:
// Storage dump:

View File

@ -7,6 +7,5 @@
// Trace:
// INVALID()
// Memory dump:
// 0: 0000000000000000000000000000000000000000000000000000000000000014
// 40: 636f6465636f6465636f6465636f6465636f6465000000000000000000000000
// Storage dump:

View File

@ -9,6 +9,5 @@
// Trace:
// INVALID()
// Memory dump:
// 0: 0000000000000000000000000000000000000000000000000000000000000014
// 80: 636f6465636f6465636f6465636f6465636f6465000000000000000000000000
// Storage dump:

View File

@ -8,7 +8,7 @@
}
// ====
// step: disambiguator
// yul: true
// dialect: yul
// ----
// {
// { let a:u256, b:u256 }

View File

@ -8,7 +8,7 @@
}
// ====
// step: disambiguator
// yul: true
// dialect: yul
// ----
// {
// {

View File

@ -7,7 +7,7 @@
}
// ====
// step: disambiguator
// yul: true
// dialect: yul
// ----
// {
// { let a:u256, b:u256, c:u256 }

View File

@ -1,7 +1,7 @@
{ { let aanteuhdaoneudbrgkjiuaothduiathudaoeuh:u256 } { let aanteuhdaoneudbrgkjiuaothduiathudaoeuh:u256 } }
// ====
// step: disambiguator
// yul: true
// dialect: yul
// ----
// {
// {

View File

@ -1,6 +1,6 @@
{ }
// ====
// step: disambiguator
// yul: true
// dialect: yul
// ----
// { }

View File

@ -9,7 +9,7 @@
}
// ====
// step: disambiguator
// yul: true
// dialect: yul
// ----
// {
// { let a:u256, b:u256, c:u256 }

View File

@ -1,7 +1,7 @@
{ { let a:u256 } { let a:u256 } }
// ====
// step: disambiguator
// yul: true
// dialect: yul
// ----
// {
// { let a:u256 }

View File

@ -1,7 +1,7 @@
{ { let a:u256 let a_1:u256 } { let a:u256 } }
// ====
// step: disambiguator
// yul: true
// dialect: yul
// ----
// {
// {

View File

@ -7,7 +7,7 @@
}
// ====
// step: disambiguator
// yul: true
// dialect: yul
// ----
// {
// {

View File

@ -4,7 +4,7 @@
}
// ====
// step: expressionInliner
// yul: true
// dialect: yul
// ----
// {
// function f() -> x:u256

View File

@ -4,7 +4,7 @@
}
// ====
// step: expressionInliner
// yul: true
// dialect: yul
// ----
// {
// function f(a:u256) -> x:u256

View File

@ -1,7 +1,7 @@
{ let a:u256 { } function f() -> x:bool { let b:u256 := 4:u256 {} for {} f() {} {} } }
// ====
// step: functionGrouper
// yul: true
// dialect: yul
// ----
// {
// {

View File

@ -6,7 +6,7 @@
}
// ====
// step: functionGrouper
// yul: true
// dialect: yul
// ----
// {
// {

View File

@ -10,7 +10,7 @@
}
// ====
// step: functionGrouper
// yul: true
// dialect: yul
// ----
// {
// { let a:u256 }

View File

@ -3,7 +3,7 @@
}
// ====
// step: functionGrouper
// yul: true
// dialect: yul
// ----
// {
// { let a:u256 }

View File

@ -9,7 +9,7 @@
}
// ====
// step: functionHoister
// yul: true
// dialect: yul
// ----
// {
// let a:u256

View File

@ -7,7 +7,7 @@
}
// ====
// step: functionHoister
// yul: true
// dialect: yul
// ----
// {
// let a:u256

View File

@ -8,7 +8,7 @@
}
// ====
// step: functionHoister
// yul: true
// dialect: yul
// ----
// {
// let a:u256

View File

@ -4,7 +4,7 @@
}
// ====
// step: functionHoister
// yul: true
// dialect: yul
// ----
// {
// let a:u256

View File

@ -9,7 +9,7 @@
}
// ====
// step: mainFunction
// yul: true
// dialect: yul
// ----
// {
// function main()

View File

@ -7,7 +7,7 @@
}
// ====
// step: mainFunction
// yul: true
// dialect: yul
// ----
// {
// function main()

View File

@ -8,7 +8,7 @@
}
// ====
// step: mainFunction
// yul: true
// dialect: yul
// ----
// {
// function main()

View File

@ -4,7 +4,7 @@
}
// ====
// step: mainFunction
// yul: true
// dialect: yul
// ----
// {
// function main()

View File

@ -1,7 +1,7 @@
{}
// ====
// step: mainFunction
// yul: true
// dialect: yul
// ----
// {
// function main()

View File

@ -0,0 +1,26 @@
{
let i := 0
for {} lt(i, 2) { i := add(i, 1) }
{
let x
x := 1337
if lt(i,1) {
x := 42
break
}
mstore(0, x)
}
}
// ====
// step: redundantAssignEliminator
// ----
// {
// let i := 0
// for { } lt(i, 2) { i := add(i, 1) }
// {
// let x
// x := 1337
// if lt(i, 1) { break }
// mstore(0, x)
// }
// }

View File

@ -0,0 +1,27 @@
{
let i := 0
for {} lt(i, 2) { i := add(i, 1) }
{
let x
x := 1337
if lt(i,1) {
x := 42
continue
}
mstore(0, x)
}
}
// ====
// step: redundantAssignEliminator
// ----
// {
// let i := 0
// for { } lt(i, 2) { i := add(i, 1) }
// {
// let x
// x := 1337
// if lt(i, 1) { continue }
// mstore(0, x)
// }
// }

View File

@ -32,7 +32,7 @@ add_executable(isoltest
../libsolidity/SMTCheckerTest.cpp
../libsolidity/SMTCheckerJSONTest.cpp
../libyul/Common.cpp
../libyul/EWasmTranslationTest.cpp
../libyul/EwasmTranslationTest.cpp
../libyul/FunctionSideEffects.cpp
../libyul/ObjectCompilerTest.cpp
../libyul/YulOptimizerTest.cpp

View File

@ -1,8 +1,8 @@
set(sources
EVMInstructionInterpreter.h
EVMInstructionInterpreter.cpp
EWasmBuiltinInterpreter.h
EWasmBuiltinInterpreter.cpp
EwasmBuiltinInterpreter.h
EwasmBuiltinInterpreter.cpp
Interpreter.h
Interpreter.cpp
)

View File

@ -15,10 +15,10 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Yul interpreter module that evaluates EWasm builtins.
* Yul interpreter module that evaluates Ewasm builtins.
*/
#include <test/tools/yulInterpreter/EWasmBuiltinInterpreter.h>
#include <test/tools/yulInterpreter/EwasmBuiltinInterpreter.h>
#include <test/tools/yulInterpreter/Interpreter.h>
@ -49,11 +49,26 @@ void copyZeroExtended(
_target[_targetOffset + i] = _sourceOffset + i < _source.size() ? _source[_sourceOffset + i] : 0;
}
/// Count leading zeros for uint64
uint64_t clz(uint64_t _v)
{
if (_v == 0)
return 64;
uint64_t r = 0;
while (!(_v & 0x8000000000000000))
{
r += 1;
_v = _v << 1;
}
return r;
}
}
using u512 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<512, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _arguments)
u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _arguments)
{
vector<uint64_t> arg;
for (u256 const& a: _arguments)
@ -119,6 +134,8 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
return arg[0] != arg[1] ? 1 : 0;
else if (_fun == "i64.eqz"_yulstring)
return arg[0] == 0 ? 1 : 0;
else if (_fun == "i64.clz"_yulstring)
return clz(arg[0]);
else if (_fun == "i64.lt_u"_yulstring)
return arg[0] < arg[1] ? 1 : 0;
else if (_fun == "i64.gt_u"_yulstring)
@ -133,24 +150,39 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
writeMemoryWord(arg[0], arg[1]);
return 0;
}
else if (_fun == "i64.store8"_yulstring)
{
accessMemory(arg[0], 1);
writeMemoryByte(arg[0], static_cast<uint8_t>(arg[1] & 0xff));
return 0;
}
else if (_fun == "i64.load"_yulstring)
{
accessMemory(arg[0], 8);
return readMemoryWord(arg[0]);
}
else if (_fun == "eth.getAddress"_yulstring)
return writeAddress(arg[0], m_state.address);
{
writeAddress(arg[0], m_state.address);
return 0;
}
else if (_fun == "eth.getExternalBalance"_yulstring)
{
// TODO this does not read the address, but is consistent with
// EVM interpreter implementation.
// If we take the address into account, this needs to use readAddress.
return writeU128(arg[0], m_state.balance);
writeU128(arg[1], m_state.balance);
return 0;
}
else if (_fun == "eth.getBlockHash"_yulstring)
{
if (arg[0] >= m_state.blockNumber || arg[0] + 256 < m_state.blockNumber)
return 1;
else
return writeU256(arg[1], 0xaaaaaaaa + u256(arg[0] - m_state.blockNumber - 256));
{
writeU256(arg[1], 0xaaaaaaaa + u256(arg[0] - m_state.blockNumber - 256));
return 0;
}
}
else if (_fun == "eth.call"_yulstring)
{
@ -199,12 +231,21 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
return 0;
}
else if (_fun == "eth.storageLoad"_yulstring)
return writeU256(arg[1], m_state.storage[h256(readU256(arg[0]))]);
{
writeU256(arg[1], m_state.storage[h256(readU256(arg[0]))]);
return 0;
}
else if (_fun == "eth.getCaller"_yulstring)
{
// TODO should this only write 20 bytes?
return writeAddress(arg[0], m_state.caller);
writeAddress(arg[0], m_state.caller);
return 0;
}
else if (_fun == "eth.getCallValue"_yulstring)
return writeU128(arg[0], m_state.callvalue);
{
writeU128(arg[0], m_state.callvalue);
return 0;
}
else if (_fun == "eth.codeCopy"_yulstring)
{
if (accessMemory(arg[0], arg[2]))
@ -215,9 +256,12 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
return 0;
}
else if (_fun == "eth.getCodeSize"_yulstring)
return writeU256(arg[0], m_state.code.size());
return m_state.code.size();
else if (_fun == "eth.getBlockCoinbase"_yulstring)
return writeAddress(arg[0], m_state.coinbase);
{
writeAddress(arg[0], m_state.coinbase);
return 0;
}
else if (_fun == "eth.create"_yulstring)
{
// TODO access memory
@ -226,7 +270,10 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
return 0xcccccc + arg[1];
}
else if (_fun == "eth.getBlockDifficulty"_yulstring)
return writeU256(arg[0], m_state.difficulty);
{
writeU256(arg[0], m_state.difficulty);
return 0;
}
else if (_fun == "eth.externalCodeCopy"_yulstring)
{
// TODO use readAddress to read address.
@ -239,22 +286,32 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
return 0;
}
else if (_fun == "eth.getExternalCodeSize"_yulstring)
return u256(keccak256(h256(readAddress(arg[0])))) & 0xffffff;
// Generate "random" code length. Make sure it fits the page size.
return u256(keccak256(h256(readAddress(arg[0])))) & 0xfff;
else if (_fun == "eth.getGasLeft"_yulstring)
return 0x99;
else if (_fun == "eth.getBlockGasLimit"_yulstring)
return uint64_t(m_state.gaslimit);
else if (_fun == "eth.getTxGasPrice"_yulstring)
return writeU128(arg[0], m_state.gasprice);
{
writeU128(arg[0], m_state.gasprice);
return 0;
}
else if (_fun == "eth.log"_yulstring)
{
logTrace(eth::Instruction::LOG0, {});
uint64_t numberOfTopics = arg[2];
if (numberOfTopics > 4)
throw ExplicitlyTerminated();
logTrace(eth::logInstruction(numberOfTopics), {});
return 0;
}
else if (_fun == "eth.getBlockNumber"_yulstring)
return m_state.blockNumber;
else if (_fun == "eth.getTxOrigin"_yulstring)
return writeAddress(arg[0], m_state.origin);
{
writeAddress(arg[0], m_state.origin);
return 0;
}
else if (_fun == "eth.finish"_yulstring)
{
bytes data;
@ -298,7 +355,7 @@ u256 EWasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
return 0;
}
bool EWasmBuiltinInterpreter::accessMemory(u256 const& _offset, u256 const& _size)
bool EwasmBuiltinInterpreter::accessMemory(u256 const& _offset, u256 const& _size)
{
if (((_offset + _size) >= _offset) && ((_offset + _size + 0x1f) >= (_offset + _size)))
{
@ -312,7 +369,7 @@ bool EWasmBuiltinInterpreter::accessMemory(u256 const& _offset, u256 const& _siz
return false;
}
bytes EWasmBuiltinInterpreter::readMemory(uint64_t _offset, uint64_t _size)
bytes EwasmBuiltinInterpreter::readMemory(uint64_t _offset, uint64_t _size)
{
yulAssert(_size <= 0xffff, "Too large read.");
bytes data(size_t(_size), uint8_t(0));
@ -321,7 +378,7 @@ bytes EWasmBuiltinInterpreter::readMemory(uint64_t _offset, uint64_t _size)
return data;
}
uint64_t EWasmBuiltinInterpreter::readMemoryWord(uint64_t _offset)
uint64_t EwasmBuiltinInterpreter::readMemoryWord(uint64_t _offset)
{
uint64_t r = 0;
for (size_t i = 0; i < 8; i++)
@ -329,13 +386,18 @@ uint64_t EWasmBuiltinInterpreter::readMemoryWord(uint64_t _offset)
return r;
}
void EWasmBuiltinInterpreter::writeMemoryWord(uint64_t _offset, uint64_t _value)
void EwasmBuiltinInterpreter::writeMemoryWord(uint64_t _offset, uint64_t _value)
{
for (size_t i = 0; i < 8; i++)
m_state.memory[_offset + i] = uint8_t((_value >> (i * 8)) & 0xff);
}
u256 EWasmBuiltinInterpreter::writeU256(uint64_t _offset, u256 _value, size_t _croppedTo)
void EwasmBuiltinInterpreter::writeMemoryByte(uint64_t _offset, uint8_t _value)
{
m_state.memory[_offset] = _value;
}
void EwasmBuiltinInterpreter::writeU256(uint64_t _offset, u256 _value, size_t _croppedTo)
{
accessMemory(_offset, _croppedTo);
for (size_t i = 0; i < _croppedTo; i++)
@ -343,11 +405,9 @@ u256 EWasmBuiltinInterpreter::writeU256(uint64_t _offset, u256 _value, size_t _c
m_state.memory[_offset + _croppedTo - 1 - i] = uint8_t(_value & 0xff);
_value >>= 8;
}
return {};
}
u256 EWasmBuiltinInterpreter::readU256(uint64_t _offset, size_t _croppedTo)
u256 EwasmBuiltinInterpreter::readU256(uint64_t _offset, size_t _croppedTo)
{
accessMemory(_offset, _croppedTo);
u256 value;
@ -357,12 +417,12 @@ u256 EWasmBuiltinInterpreter::readU256(uint64_t _offset, size_t _croppedTo)
return value;
}
void EWasmBuiltinInterpreter::logTrace(dev::eth::Instruction _instruction, std::vector<u256> const& _arguments, bytes const& _data)
void EwasmBuiltinInterpreter::logTrace(dev::eth::Instruction _instruction, std::vector<u256> const& _arguments, bytes const& _data)
{
logTrace(dev::eth::instructionInfo(_instruction).name, _arguments, _data);
}
void EWasmBuiltinInterpreter::logTrace(std::string const& _pseudoInstruction, std::vector<u256> const& _arguments, bytes const& _data)
void EwasmBuiltinInterpreter::logTrace(std::string const& _pseudoInstruction, std::vector<u256> const& _arguments, bytes const& _data)
{
string message = _pseudoInstruction + "(";
for (size_t i = 0; i < _arguments.size(); ++i)

View File

@ -15,7 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Yul interpreter module that evaluates EWasm builtins.
* Yul interpreter module that evaluates Ewasm builtins.
*/
#pragma once
@ -45,7 +45,7 @@ namespace test
struct InterpreterState;
/**
* Interprets EWasm builtins based on the current state and logs instructions with
* Interprets Ewasm builtins based on the current state and logs instructions with
* side-effects.
*
* Since this is mainly meant to be used for differential fuzz testing, it is focused
@ -63,10 +63,10 @@ struct InterpreterState;
* The main focus is that the generated execution trace is the same for equivalent executions
* and likely to be different for non-equivalent executions.
*/
class EWasmBuiltinInterpreter
class EwasmBuiltinInterpreter
{
public:
explicit EWasmBuiltinInterpreter(InterpreterState& _state):
explicit EwasmBuiltinInterpreter(InterpreterState& _state):
m_state(_state)
{}
/// Evaluate builtin function
@ -86,11 +86,14 @@ private:
/// Writes a word to memory (little-endian)
/// Does not adjust msize, use @a accessMemory for that
void writeMemoryWord(uint64_t _offset, uint64_t _value);
/// Writes a byte to memory
/// Does not adjust msize, use @a accessMemory for that
void writeMemoryByte(uint64_t _offset, uint8_t _value);
/// Helper for eth.* builtins. Writes to memory (big-endian) and always returns zero.
dev::u256 writeU256(uint64_t _offset, dev::u256 _value, size_t _croppedTo = 32);
dev::u256 writeU128(uint64_t _offset, dev::u256 _value) { return writeU256(_offset, std::move(_value), 16); }
dev::u256 writeAddress(uint64_t _offset, dev::u256 _value) { return writeU256(_offset, std::move(_value), 20); }
void writeU256(uint64_t _offset, dev::u256 _value, size_t _croppedTo = 32);
void writeU128(uint64_t _offset, dev::u256 _value) { writeU256(_offset, std::move(_value), 16); }
void writeAddress(uint64_t _offset, dev::u256 _value) { writeU256(_offset, std::move(_value), 20); }
/// Helper for eth.* builtins. Reads from memory (big-endian) and returns the value;
dev::u256 readU256(uint64_t _offset, size_t _croppedTo = 32);
dev::u256 readU128(uint64_t _offset) { return readU256(_offset, 16); }

View File

@ -21,7 +21,7 @@
#include <test/tools/yulInterpreter/Interpreter.h>
#include <test/tools/yulInterpreter/EVMInstructionInterpreter.h>
#include <test/tools/yulInterpreter/EWasmBuiltinInterpreter.h>
#include <test/tools/yulInterpreter/EwasmBuiltinInterpreter.h>
#include <libyul/AsmData.h>
#include <libyul/Dialect.h>
@ -246,7 +246,7 @@ void ExpressionEvaluator::operator()(FunctionCall const& _funCall)
else if (WasmDialect const* dialect = dynamic_cast<WasmDialect const*>(&m_dialect))
if (dialect->builtin(_funCall.functionName.name))
{
EWasmBuiltinInterpreter interpreter(m_state);
EwasmBuiltinInterpreter interpreter(m_state);
setValue(interpreter.evalBuiltin(_funCall.functionName.name, values()));
return;
}