mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/develop' into HEAD
This commit is contained in:
		
						commit
						ce50f05fc1
					
				| @ -61,7 +61,7 @@ The following elementary types exist: | |||||||
| - ``bool``: equivalent to ``uint8`` restricted to the values 0 and 1. For computing the function selector, ``bool`` is used. | - ``bool``: equivalent to ``uint8`` restricted to the values 0 and 1. For computing the function selector, ``bool`` is used. | ||||||
| 
 | 
 | ||||||
| - ``fixed<M>x<N>``: signed fixed-point decimal number of ``M`` bits, ``8 <= M <= 256``, | - ``fixed<M>x<N>``: signed fixed-point decimal number of ``M`` bits, ``8 <= M <= 256``, | ||||||
|   ``M % 8 ==0``, and ``0 < N <= 80``, which denotes the value ``v`` as ``v / (10 ** N)``. |   ``M % 8 == 0``, and ``0 < N <= 80``, which denotes the value ``v`` as ``v / (10 ** N)``. | ||||||
| 
 | 
 | ||||||
| - ``ufixed<M>x<N>``: unsigned variant of ``fixed<M>x<N>``. | - ``ufixed<M>x<N>``: unsigned variant of ``fixed<M>x<N>``. | ||||||
| 
 | 
 | ||||||
| @ -76,6 +76,9 @@ The following (fixed-size) array type exists: | |||||||
| 
 | 
 | ||||||
| - ``<type>[M]``: a fixed-length array of ``M`` elements, ``M >= 0``, of the given type. | - ``<type>[M]``: a fixed-length array of ``M`` elements, ``M >= 0``, of the given type. | ||||||
| 
 | 
 | ||||||
|  |     .. note:: | ||||||
|  |         While this ABI specification can express fixed-length arrays with zero elements, they're not supported by the compiler. | ||||||
|  | 
 | ||||||
| The following non-fixed-size types exist: | The following non-fixed-size types exist: | ||||||
| 
 | 
 | ||||||
| - ``bytes``: dynamic sized byte sequence. | - ``bytes``: dynamic sized byte sequence. | ||||||
| @ -108,7 +111,7 @@ them. | |||||||
| +-------------------------------+-----------------------------------------------------------------------------+ | +-------------------------------+-----------------------------------------------------------------------------+ | ||||||
| |:ref:`enum<enums>`             |smallest ``uint`` type that is large enough to hold all values               | | |:ref:`enum<enums>`             |smallest ``uint`` type that is large enough to hold all values               | | ||||||
| |                               |                                                                             | | |                               |                                                                             | | ||||||
| |                               |For example, an ``enum`` of 255 values or less is mapped to ``uint8`` and    | | |                               |For example, an ``enum`` of 256 values or less is mapped to ``uint8`` and    | | ||||||
| |                               |an ``enum`` of 256 values is mapped to ``uint16``.                           | | |                               |an ``enum`` of 256 values is mapped to ``uint16``.                           | | ||||||
| +-------------------------------+-----------------------------------------------------------------------------+ | +-------------------------------+-----------------------------------------------------------------------------+ | ||||||
| |:ref:`struct<structs>`         |``tuple``                                                                    | | |:ref:`struct<structs>`         |``tuple``                                                                    | | ||||||
|  | |||||||
| @ -47,8 +47,6 @@ set(sources | |||||||
| 	ast/ASTAnnotations.h | 	ast/ASTAnnotations.h | ||||||
| 	ast/ASTEnums.h | 	ast/ASTEnums.h | ||||||
| 	ast/ASTForward.h | 	ast/ASTForward.h | ||||||
| 	ast/AsmJsonImporter.cpp |  | ||||||
| 	ast/AsmJsonImporter.h |  | ||||||
| 	ast/ASTJsonConverter.cpp | 	ast/ASTJsonConverter.cpp | ||||||
| 	ast/ASTJsonConverter.h | 	ast/ASTJsonConverter.h | ||||||
| 	ast/ASTUtils.cpp | 	ast/ASTUtils.cpp | ||||||
|  | |||||||
| @ -22,18 +22,20 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <libsolidity/ast/ASTJsonImporter.h> | #include <libsolidity/ast/ASTJsonImporter.h> | ||||||
| #include <libsolidity/ast/AsmJsonImporter.h> | 
 | ||||||
| #include <liblangutil/Scanner.h> | #include <libyul/AsmJsonImporter.h> | ||||||
|  | #include <libyul/AsmParser.h> | ||||||
| #include <libyul/Dialect.h> | #include <libyul/Dialect.h> | ||||||
|  | #include <libyul/backends/evm/EVMDialect.h> | ||||||
|  | 
 | ||||||
|  | #include <liblangutil/ErrorReporter.h> | ||||||
|  | #include <liblangutil/Exceptions.h> | ||||||
|  | #include <liblangutil/Scanner.h> | ||||||
|  | #include <liblangutil/SourceLocation.h> | ||||||
|  | #include <liblangutil/Token.h> | ||||||
|  | 
 | ||||||
| #include <boost/algorithm/string/split.hpp> | #include <boost/algorithm/string/split.hpp> | ||||||
| #include <boost/algorithm/string.hpp> | #include <boost/algorithm/string.hpp> | ||||||
| #include <liblangutil/Token.h> |  | ||||||
| #include <libyul/AsmParser.h> |  | ||||||
| #include <libyul/backends/evm/EVMDialect.h> |  | ||||||
| #include <liblangutil/SourceLocation.h> |  | ||||||
| #include <liblangutil/Exceptions.h> |  | ||||||
| #include <liblangutil/ErrorReporter.h> |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| using namespace std; | using namespace std; | ||||||
| 
 | 
 | ||||||
| @ -582,7 +584,7 @@ ASTPointer<InlineAssembly> ASTJsonImporter::createInlineAssembly(Json::Value con | |||||||
| 	astAssert(m_evmVersion == evmVersion, "Imported tree evm version differs from configured evm version!"); | 	astAssert(m_evmVersion == evmVersion, "Imported tree evm version differs from configured evm version!"); | ||||||
| 
 | 
 | ||||||
| 	yul::Dialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(evmVersion.value()); | 	yul::Dialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(evmVersion.value()); | ||||||
| 	shared_ptr<yul::Block> operations = make_shared<yul::Block>(AsmJsonImporter(m_currentSourceName).createBlock(member(_node, "AST"))); | 	shared_ptr<yul::Block> operations = make_shared<yul::Block>(yul::AsmJsonImporter(m_currentSourceName).createBlock(member(_node, "AST"))); | ||||||
| 	return createASTNode<InlineAssembly>( | 	return createASTNode<InlineAssembly>( | ||||||
| 		_node, | 		_node, | ||||||
| 		nullOrASTString(_node, "documentation"), | 		nullOrASTString(_node, "documentation"), | ||||||
|  | |||||||
| @ -22,30 +22,29 @@ | |||||||
| 
 | 
 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <libsolidity/ast/AsmJsonImporter.h> | #include <libyul/AsmJsonImporter.h> | ||||||
| #include <libsolidity/ast/ASTJsonImporter.h> |  | ||||||
| #include <libsolidity/ast/Types.h> |  | ||||||
| #include <libyul/AsmData.h> | #include <libyul/AsmData.h> | ||||||
| #include <libyul/AsmDataForward.h> | #include <libyul/AsmDataForward.h> | ||||||
| #include <liblangutil/Exceptions.h> | #include <libyul/Exceptions.h> | ||||||
|  | 
 | ||||||
| #include <liblangutil/Scanner.h> | #include <liblangutil/Scanner.h> | ||||||
| #include <vector> |  | ||||||
| 
 | 
 | ||||||
| #include <boost/algorithm/string/split.hpp> | #include <boost/algorithm/string/split.hpp> | ||||||
| #include <boost/algorithm/string.hpp> | #include <boost/algorithm/string.hpp> | ||||||
| 
 | 
 | ||||||
|  | #include <vector> | ||||||
| 
 | 
 | ||||||
| using namespace std; | using namespace std; | ||||||
| using namespace solidity::yul; | using namespace solidity::langutil; | ||||||
| 
 | 
 | ||||||
| namespace solidity::frontend | namespace solidity::yul | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| using SourceLocation = langutil::SourceLocation; | using SourceLocation = langutil::SourceLocation; | ||||||
| 
 | 
 | ||||||
| SourceLocation const AsmJsonImporter::createSourceLocation(Json::Value const& _node) | SourceLocation const AsmJsonImporter::createSourceLocation(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	astAssert(member(_node, "src").isString(), "'src' must be a string"); | 	yulAssert(member(_node, "src").isString(), "'src' must be a string"); | ||||||
| 
 | 
 | ||||||
| 	return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_sourceName); | 	return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_sourceName); | ||||||
| } | } | ||||||
| @ -55,7 +54,7 @@ T AsmJsonImporter::createAsmNode(Json::Value const& _node) | |||||||
| { | { | ||||||
| 	T r; | 	T r; | ||||||
| 	r.location = createSourceLocation(_node); | 	r.location = createSourceLocation(_node); | ||||||
| 	astAssert( | 	yulAssert( | ||||||
| 		r.location.source && 0 <= r.location.start && r.location.start <= r.location.end, | 		r.location.source && 0 <= r.location.start && r.location.start <= r.location.end, | ||||||
| 		"Invalid source location in Asm AST" | 		"Invalid source location in Asm AST" | ||||||
| 	); | 	); | ||||||
| @ -69,21 +68,21 @@ Json::Value AsmJsonImporter::member(Json::Value const& _node, string const& _nam | |||||||
| 	return _node[_name]; | 	return _node[_name]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::TypedName AsmJsonImporter::createTypedName(Json::Value const& _node) | TypedName AsmJsonImporter::createTypedName(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	auto typedName = createAsmNode<yul::TypedName>(_node); | 	auto typedName = createAsmNode<TypedName>(_node); | ||||||
| 	typedName.type = YulString{member(_node, "type").asString()}; | 	typedName.type = YulString{member(_node, "type").asString()}; | ||||||
| 	typedName.name = YulString{member(_node, "name").asString()}; | 	typedName.name = YulString{member(_node, "name").asString()}; | ||||||
| 	return typedName; | 	return typedName; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::Statement AsmJsonImporter::createStatement(Json::Value const& _node) | Statement AsmJsonImporter::createStatement(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	Json::Value jsonNodeType = member(_node, "nodeType"); | 	Json::Value jsonNodeType = member(_node, "nodeType"); | ||||||
| 	astAssert(jsonNodeType.isString(), "Expected \"nodeType\" to be of type string!"); | 	yulAssert(jsonNodeType.isString(), "Expected \"nodeType\" to be of type string!"); | ||||||
| 	string nodeType = jsonNodeType.asString(); | 	string nodeType = jsonNodeType.asString(); | ||||||
| 
 | 
 | ||||||
| 	astAssert(nodeType.substr(0, 3) == "Yul", "Invalid nodeType prefix"); | 	yulAssert(nodeType.substr(0, 3) == "Yul", "Invalid nodeType prefix"); | ||||||
| 	nodeType = nodeType.substr(3); | 	nodeType = nodeType.substr(3); | ||||||
| 
 | 
 | ||||||
| 	if (nodeType == "ExpressionStatement") | 	if (nodeType == "ExpressionStatement") | ||||||
| @ -109,16 +108,16 @@ yul::Statement AsmJsonImporter::createStatement(Json::Value const& _node) | |||||||
| 	else if (nodeType == "Block") | 	else if (nodeType == "Block") | ||||||
| 		return createBlock(_node); | 		return createBlock(_node); | ||||||
| 	else | 	else | ||||||
| 		astAssert(false, "Invalid nodeType as statement"); | 		yulAssert(false, "Invalid nodeType as statement"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::Expression AsmJsonImporter::createExpression(Json::Value const& _node) | Expression AsmJsonImporter::createExpression(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	Json::Value jsonNodeType = member(_node, "nodeType"); | 	Json::Value jsonNodeType = member(_node, "nodeType"); | ||||||
| 	astAssert(jsonNodeType.isString(), "Expected \"nodeType\" to be of type string!"); | 	yulAssert(jsonNodeType.isString(), "Expected \"nodeType\" to be of type string!"); | ||||||
| 	string nodeType = jsonNodeType.asString(); | 	string nodeType = jsonNodeType.asString(); | ||||||
| 
 | 
 | ||||||
| 	astAssert(nodeType.substr(0, 3) == "Yul", "Invalid nodeType prefix"); | 	yulAssert(nodeType.substr(0, 3) == "Yul", "Invalid nodeType prefix"); | ||||||
| 	nodeType = nodeType.substr(3); | 	nodeType = nodeType.substr(3); | ||||||
| 
 | 
 | ||||||
| 	if (nodeType == "FunctionCall") | 	if (nodeType == "FunctionCall") | ||||||
| @ -128,35 +127,35 @@ yul::Expression AsmJsonImporter::createExpression(Json::Value const& _node) | |||||||
| 	else if (nodeType == "Literal") | 	else if (nodeType == "Literal") | ||||||
| 		return createLiteral(_node); | 		return createLiteral(_node); | ||||||
| 	else | 	else | ||||||
| 		astAssert(false, "Invalid nodeType as expression"); | 		yulAssert(false, "Invalid nodeType as expression"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| vector<yul::Expression> AsmJsonImporter::createExpressionVector(Json::Value const& _array) | vector<Expression> AsmJsonImporter::createExpressionVector(Json::Value const& _array) | ||||||
| { | { | ||||||
| 	vector<yul::Expression> ret; | 	vector<Expression> ret; | ||||||
| 	for (auto& var: _array) | 	for (auto& var: _array) | ||||||
| 		ret.emplace_back(createExpression(var)); | 		ret.emplace_back(createExpression(var)); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| vector<yul::Statement> AsmJsonImporter::createStatementVector(Json::Value const& _array) | vector<Statement> AsmJsonImporter::createStatementVector(Json::Value const& _array) | ||||||
| { | { | ||||||
| 	vector<yul::Statement> ret; | 	vector<Statement> ret; | ||||||
| 	for (auto& var: _array) | 	for (auto& var: _array) | ||||||
| 		ret.emplace_back(createStatement(var)); | 		ret.emplace_back(createStatement(var)); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::Block AsmJsonImporter::createBlock(Json::Value const& _node) | Block AsmJsonImporter::createBlock(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	auto block = createAsmNode<yul::Block>(_node); | 	auto block = createAsmNode<Block>(_node); | ||||||
| 	block.statements = createStatementVector(_node["statements"]); | 	block.statements = createStatementVector(_node["statements"]); | ||||||
| 	return block; | 	return block; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::Literal AsmJsonImporter::createLiteral(Json::Value const& _node) | Literal AsmJsonImporter::createLiteral(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	auto lit = createAsmNode<yul::Literal>(_node); | 	auto lit = createAsmNode<Literal>(_node); | ||||||
| 	string kind = member(_node, "kind").asString(); | 	string kind = member(_node, "kind").asString(); | ||||||
| 
 | 
 | ||||||
| 	lit.value = YulString{member(_node, "value").asString()}; | 	lit.value = YulString{member(_node, "value").asString()}; | ||||||
| @ -165,8 +164,8 @@ yul::Literal AsmJsonImporter::createLiteral(Json::Value const& _node) | |||||||
| 	if (kind == "number") | 	if (kind == "number") | ||||||
| 	{ | 	{ | ||||||
| 		langutil::Scanner scanner{langutil::CharStream(lit.value.str(), "")}; | 		langutil::Scanner scanner{langutil::CharStream(lit.value.str(), "")}; | ||||||
| 		lit.kind = yul::LiteralKind::Number; | 		lit.kind = LiteralKind::Number; | ||||||
| 		astAssert( | 		yulAssert( | ||||||
| 			scanner.currentToken() == Token::Number, | 			scanner.currentToken() == Token::Number, | ||||||
| 			"Expected number but got " + langutil::TokenTraits::friendlyName(scanner.currentToken()) + string(" while scanning ") + lit.value.str() | 			"Expected number but got " + langutil::TokenTraits::friendlyName(scanner.currentToken()) + string(" while scanning ") + lit.value.str() | ||||||
| 		); | 		); | ||||||
| @ -174,8 +173,8 @@ yul::Literal AsmJsonImporter::createLiteral(Json::Value const& _node) | |||||||
| 	else if (kind == "bool") | 	else if (kind == "bool") | ||||||
| 	{ | 	{ | ||||||
| 		langutil::Scanner scanner{langutil::CharStream(lit.value.str(), "")}; | 		langutil::Scanner scanner{langutil::CharStream(lit.value.str(), "")}; | ||||||
| 		lit.kind = yul::LiteralKind::Boolean; | 		lit.kind = LiteralKind::Boolean; | ||||||
| 		astAssert( | 		yulAssert( | ||||||
| 			scanner.currentToken() == Token::TrueLiteral || | 			scanner.currentToken() == Token::TrueLiteral || | ||||||
| 			scanner.currentToken() == Token::FalseLiteral, | 			scanner.currentToken() == Token::FalseLiteral, | ||||||
| 			"Expected true/false literal!" | 			"Expected true/false literal!" | ||||||
| @ -183,45 +182,45 @@ yul::Literal AsmJsonImporter::createLiteral(Json::Value const& _node) | |||||||
| 	} | 	} | ||||||
| 	else if (kind == "string") | 	else if (kind == "string") | ||||||
| 	{ | 	{ | ||||||
| 		lit.kind = yul::LiteralKind::String; | 		lit.kind = LiteralKind::String; | ||||||
| 		astAssert( | 		yulAssert( | ||||||
| 			lit.value.str().size() <= 32, | 			lit.value.str().size() <= 32, | ||||||
| 			"String literal too long (" + to_string(lit.value.str().size()) + " > 32)" | 			"String literal too long (" + to_string(lit.value.str().size()) + " > 32)" | ||||||
| 		); | 		); | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 		solAssert(false, "unknown type of literal"); | 		yulAssert(false, "unknown type of literal"); | ||||||
| 
 | 
 | ||||||
| 	return lit; | 	return lit; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::Leave AsmJsonImporter::createLeave(Json::Value const& _node) | Leave AsmJsonImporter::createLeave(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	return createAsmNode<yul::Leave>(_node); | 	return createAsmNode<Leave>(_node); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::Identifier AsmJsonImporter::createIdentifier(Json::Value const& _node) | Identifier AsmJsonImporter::createIdentifier(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	auto identifier = createAsmNode<yul::Identifier>(_node); | 	auto identifier = createAsmNode<Identifier>(_node); | ||||||
| 	identifier.name = YulString(member(_node, "name").asString()); | 	identifier.name = YulString(member(_node, "name").asString()); | ||||||
| 	return identifier; | 	return identifier; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::Assignment AsmJsonImporter::createAssignment(Json::Value const& _node) | Assignment AsmJsonImporter::createAssignment(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	auto assignment = createAsmNode<yul::Assignment>(_node); | 	auto assignment = createAsmNode<Assignment>(_node); | ||||||
| 
 | 
 | ||||||
| 	if (_node.isMember("variableNames")) | 	if (_node.isMember("variableNames")) | ||||||
| 		for (auto const& var: member(_node, "variableNames")) | 		for (auto const& var: member(_node, "variableNames")) | ||||||
| 			assignment.variableNames.emplace_back(createIdentifier(var)); | 			assignment.variableNames.emplace_back(createIdentifier(var)); | ||||||
| 
 | 
 | ||||||
| 	assignment.value = make_unique<yul::Expression>(createExpression(member(_node, "value"))); | 	assignment.value = make_unique<Expression>(createExpression(member(_node, "value"))); | ||||||
| 	return assignment; | 	return assignment; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::FunctionCall AsmJsonImporter::createFunctionCall(Json::Value const& _node) | FunctionCall AsmJsonImporter::createFunctionCall(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	auto functionCall = createAsmNode<yul::FunctionCall>(_node); | 	auto functionCall = createAsmNode<FunctionCall>(_node); | ||||||
| 
 | 
 | ||||||
| 	for (auto const& var: member(_node, "arguments")) | 	for (auto const& var: member(_node, "arguments")) | ||||||
| 		functionCall.arguments.emplace_back(createExpression(var)); | 		functionCall.arguments.emplace_back(createExpression(var)); | ||||||
| @ -231,25 +230,25 @@ yul::FunctionCall AsmJsonImporter::createFunctionCall(Json::Value const& _node) | |||||||
| 	return functionCall; | 	return functionCall; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::ExpressionStatement AsmJsonImporter::createExpressionStatement(Json::Value const& _node) | ExpressionStatement AsmJsonImporter::createExpressionStatement(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	auto statement = createAsmNode<yul::ExpressionStatement>(_node); | 	auto statement = createAsmNode<ExpressionStatement>(_node); | ||||||
| 	statement.expression = createExpression(member(_node, "expression")); | 	statement.expression = createExpression(member(_node, "expression")); | ||||||
| 	return statement; | 	return statement; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::VariableDeclaration AsmJsonImporter::createVariableDeclaration(Json::Value const& _node) | VariableDeclaration AsmJsonImporter::createVariableDeclaration(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	auto varDec = createAsmNode<yul::VariableDeclaration>(_node); | 	auto varDec = createAsmNode<VariableDeclaration>(_node); | ||||||
| 	for (auto const& var: member(_node, "variables")) | 	for (auto const& var: member(_node, "variables")) | ||||||
| 		varDec.variables.emplace_back(createTypedName(var)); | 		varDec.variables.emplace_back(createTypedName(var)); | ||||||
| 	varDec.value = make_unique<yul::Expression>(createExpression(member(_node, "value"))); | 	varDec.value = make_unique<Expression>(createExpression(member(_node, "value"))); | ||||||
| 	return varDec; | 	return varDec; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::FunctionDefinition AsmJsonImporter::createFunctionDefinition(Json::Value const& _node) | FunctionDefinition AsmJsonImporter::createFunctionDefinition(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	auto funcDef = createAsmNode<yul::FunctionDefinition>(_node); | 	auto funcDef = createAsmNode<FunctionDefinition>(_node); | ||||||
| 	funcDef.name = YulString{member(_node, "name").asString()}; | 	funcDef.name = YulString{member(_node, "name").asString()}; | ||||||
| 
 | 
 | ||||||
| 	if (_node.isMember("parameters")) | 	if (_node.isMember("parameters")) | ||||||
| @ -264,53 +263,53 @@ yul::FunctionDefinition AsmJsonImporter::createFunctionDefinition(Json::Value co | |||||||
| 	return funcDef; | 	return funcDef; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::If AsmJsonImporter::createIf(Json::Value const& _node) | If AsmJsonImporter::createIf(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	auto ifStatement = createAsmNode<yul::If>(_node); | 	auto ifStatement = createAsmNode<If>(_node); | ||||||
| 	ifStatement.condition = make_unique<yul::Expression>(createExpression(member(_node, "condition"))); | 	ifStatement.condition = make_unique<Expression>(createExpression(member(_node, "condition"))); | ||||||
| 	ifStatement.body = createBlock(member(_node, "body")); | 	ifStatement.body = createBlock(member(_node, "body")); | ||||||
| 	return ifStatement; | 	return ifStatement; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::Case AsmJsonImporter::createCase(Json::Value const& _node) | Case AsmJsonImporter::createCase(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	auto caseStatement = createAsmNode<yul::Case>(_node); | 	auto caseStatement = createAsmNode<Case>(_node); | ||||||
| 	auto const& value = member(_node, "value"); | 	auto const& value = member(_node, "value"); | ||||||
| 	if (value.isString()) | 	if (value.isString()) | ||||||
| 		astAssert(value.asString() == "default", "Expected default case"); | 		yulAssert(value.asString() == "default", "Expected default case"); | ||||||
| 	else | 	else | ||||||
| 		caseStatement.value = make_unique<yul::Literal>(createLiteral(value)); | 		caseStatement.value = make_unique<Literal>(createLiteral(value)); | ||||||
| 	caseStatement.body = createBlock(member(_node, "body")); | 	caseStatement.body = createBlock(member(_node, "body")); | ||||||
| 	return caseStatement; | 	return caseStatement; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::Switch AsmJsonImporter::createSwitch(Json::Value const& _node) | Switch AsmJsonImporter::createSwitch(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	auto switchStatement = createAsmNode<yul::Switch>(_node); | 	auto switchStatement = createAsmNode<Switch>(_node); | ||||||
| 	switchStatement.expression = make_unique<yul::Expression>(createExpression(member(_node, "expression"))); | 	switchStatement.expression = make_unique<Expression>(createExpression(member(_node, "expression"))); | ||||||
| 	for (auto const& var: member(_node, "cases")) | 	for (auto const& var: member(_node, "cases")) | ||||||
| 		switchStatement.cases.emplace_back(createCase(var)); | 		switchStatement.cases.emplace_back(createCase(var)); | ||||||
| 	return switchStatement; | 	return switchStatement; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::ForLoop AsmJsonImporter::createForLoop(Json::Value const& _node) | ForLoop AsmJsonImporter::createForLoop(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	auto forLoop = createAsmNode<yul::ForLoop>(_node); | 	auto forLoop = createAsmNode<ForLoop>(_node); | ||||||
| 	forLoop.pre = createBlock(member(_node, "pre")); | 	forLoop.pre = createBlock(member(_node, "pre")); | ||||||
| 	forLoop.condition = make_unique<yul::Expression>(createExpression(member(_node, "condition"))); | 	forLoop.condition = make_unique<Expression>(createExpression(member(_node, "condition"))); | ||||||
| 	forLoop.post = createBlock(member(_node, "post")); | 	forLoop.post = createBlock(member(_node, "post")); | ||||||
| 	forLoop.body = createBlock(member(_node, "body")); | 	forLoop.body = createBlock(member(_node, "body")); | ||||||
| 	return forLoop; | 	return forLoop; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::Break AsmJsonImporter::createBreak(Json::Value const& _node) | Break AsmJsonImporter::createBreak(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	return createAsmNode<yul::Break>(_node); | 	return createAsmNode<Break>(_node); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| yul::Continue AsmJsonImporter::createContinue(Json::Value const& _node) | Continue AsmJsonImporter::createContinue(Json::Value const& _node) | ||||||
| { | { | ||||||
| 	return createAsmNode<yul::Continue>(_node); | 	return createAsmNode<Continue>(_node); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| @ -29,7 +29,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
| namespace solidity::frontend | namespace solidity::yul | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -6,6 +6,8 @@ add_library(yul | |||||||
| 	AsmDataForward.h | 	AsmDataForward.h | ||||||
| 	AsmJsonConverter.h | 	AsmJsonConverter.h | ||||||
| 	AsmJsonConverter.cpp | 	AsmJsonConverter.cpp | ||||||
|  | 	AsmJsonImporter.h | ||||||
|  | 	AsmJsonImporter.cpp | ||||||
| 	AsmParser.cpp | 	AsmParser.cpp | ||||||
| 	AsmParser.h | 	AsmParser.h | ||||||
| 	AsmPrinter.cpp | 	AsmPrinter.cpp | ||||||
|  | |||||||
| @ -154,12 +154,12 @@ TestCase::TestResult SemanticTest::runTest(ostream& _stream, string const& _line | |||||||
| 		{ | 		{ | ||||||
| 			if (constructed) | 			if (constructed) | ||||||
| 			{ | 			{ | ||||||
| 				soltestAssert(!test.call().isLibrary, "Libraries have to be deployed before any other call."); | 				soltestAssert(test.call().kind != FunctionCall::Kind::Library, "Libraries have to be deployed before any other call."); | ||||||
| 				soltestAssert( | 				soltestAssert( | ||||||
| 					!test.call().isConstructor, | 					test.call().kind != FunctionCall::Kind::Constructor, | ||||||
| 					"Constructor has to be the first function call expect for library deployments."); | 					"Constructor has to be the first function call expect for library deployments."); | ||||||
| 			} | 			} | ||||||
| 			else if (test.call().isLibrary) | 			else if (test.call().kind == FunctionCall::Kind::Library) | ||||||
| 			{ | 			{ | ||||||
| 				soltestAssert( | 				soltestAssert( | ||||||
| 					deploy(test.call().signature, 0, {}, libraries) && m_transactionSuccessful, | 					deploy(test.call().signature, 0, {}, libraries) && m_transactionSuccessful, | ||||||
| @ -169,14 +169,23 @@ TestCase::TestResult SemanticTest::runTest(ostream& _stream, string const& _line | |||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				if (test.call().isConstructor) | 				if (test.call().kind == FunctionCall::Kind::Constructor) | ||||||
| 					deploy("", test.call().value.value, test.call().arguments.rawBytes(), libraries); | 					deploy("", test.call().value.value, test.call().arguments.rawBytes(), libraries); | ||||||
| 				else | 				else | ||||||
| 					soltestAssert(deploy("", 0, bytes(), libraries), "Failed to deploy contract."); | 					soltestAssert(deploy("", 0, bytes(), libraries), "Failed to deploy contract."); | ||||||
| 				constructed = true; | 				constructed = true; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (test.call().isConstructor) | 			if (test.call().kind == FunctionCall::Kind::Storage) | ||||||
|  | 			{ | ||||||
|  | 				test.setFailure(false); | ||||||
|  | 				bytes result(1, !storageEmpty(m_contractAddress)); | ||||||
|  | 				test.setRawBytes(result); | ||||||
|  | 				soltestAssert(test.call().expectations.rawBytes().size() == 1, ""); | ||||||
|  | 				if (test.call().expectations.rawBytes() != result) | ||||||
|  | 					success = false; | ||||||
|  | 			} | ||||||
|  | 			else if (test.call().kind == FunctionCall::Kind::Constructor) | ||||||
| 			{ | 			{ | ||||||
| 				if (m_transactionSuccessful == test.call().expectations.failure) | 				if (m_transactionSuccessful == test.call().expectations.failure) | ||||||
| 					success = false; | 					success = false; | ||||||
| @ -187,17 +196,20 @@ TestCase::TestResult SemanticTest::runTest(ostream& _stream, string const& _line | |||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				bytes output; | 				bytes output; | ||||||
| 				if (test.call().useCallWithoutSignature) | 				if (test.call().kind == FunctionCall::Kind::LowLevel) | ||||||
| 					output = callLowLevel(test.call().arguments.rawBytes(), test.call().value.value); | 					output = callLowLevel(test.call().arguments.rawBytes(), test.call().value.value); | ||||||
| 				else | 				else | ||||||
| 				{ | 				{ | ||||||
| 					soltestAssert( | 					soltestAssert( | ||||||
| 						m_allowNonExistingFunctions || m_compiler.methodIdentifiers(m_compiler.lastContractName()) | 						m_allowNonExistingFunctions || | ||||||
| 								   .isMember(test.call().signature), | 						m_compiler.methodIdentifiers(m_compiler.lastContractName()).isMember(test.call().signature), | ||||||
| 						"The function " + test.call().signature + " is not known to the compiler"); | 						"The function " + test.call().signature + " is not known to the compiler" | ||||||
|  | 					); | ||||||
| 
 | 
 | ||||||
| 					output = callContractFunctionWithValueNoEncoding( | 					output = callContractFunctionWithValueNoEncoding( | ||||||
| 						test.call().signature, test.call().value.value, test.call().arguments.rawBytes() | 						test.call().signature, | ||||||
|  | 						test.call().value.value, | ||||||
|  | 						test.call().arguments.rawBytes() | ||||||
| 					); | 					); | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -41,6 +41,10 @@ contract c { | |||||||
| // ==== | // ==== | ||||||
| // compileViaYul: also | // compileViaYul: also | ||||||
| // ---- | // ---- | ||||||
|  | // storage: empty | ||||||
| // test_short() -> 1780731860627700044960722568376587075150542249149356309979516913770823710 | // test_short() -> 1780731860627700044960722568376587075150542249149356309979516913770823710 | ||||||
|  | // storage: nonempty | ||||||
| // test_long() -> 67 | // test_long() -> 67 | ||||||
|  | // storage: nonempty | ||||||
| // test_pop() -> 1780731860627700044960722568376592200742329637303199754547598369979433020 | // test_pop() -> 1780731860627700044960722568376592200742329637303199754547598369979433020 | ||||||
|  | // storage: nonempty | ||||||
|  | |||||||
| @ -0,0 +1,29 @@ | |||||||
|  | contract Test { | ||||||
|  |     bytes x; | ||||||
|  |     function set(bytes memory _a) public { x = _a; } | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // set(bytes): 0x20, 3, "abc" | ||||||
|  | // storage: nonempty | ||||||
|  | // set(bytes): 0x20, 0 | ||||||
|  | // storage: empty | ||||||
|  | // set(bytes): 0x20, 31, "1234567890123456789012345678901" | ||||||
|  | // storage: nonempty | ||||||
|  | // set(bytes): 0x20, 36, "12345678901234567890123456789012", "XXXX" | ||||||
|  | // storage: nonempty | ||||||
|  | // set(bytes): 0x20, 3, "abc" | ||||||
|  | // storage: nonempty | ||||||
|  | // set(bytes): 0x20, 0 | ||||||
|  | // storage: empty | ||||||
|  | // set(bytes): 0x20, 3, "abc" | ||||||
|  | // storage: nonempty | ||||||
|  | // set(bytes): 0x20, 36, "12345678901234567890123456789012", "XXXX" | ||||||
|  | // storage: nonempty | ||||||
|  | // set(bytes): 0x20, 0 | ||||||
|  | // storage: empty | ||||||
|  | // set(bytes): 0x20, 66, "12345678901234567890123456789012", "12345678901234567890123456789012", "12" | ||||||
|  | // storage: nonempty | ||||||
|  | // set(bytes): 0x20, 3, "abc" | ||||||
|  | // storage: nonempty | ||||||
|  | // set(bytes): 0x20, 0 | ||||||
|  | // storage: empty | ||||||
| @ -58,6 +58,7 @@ namespace solidity::frontend::test | |||||||
| 	K(Library, "library", 0)       \ | 	K(Library, "library", 0)       \ | ||||||
| 	K(Right, "right", 0)           \ | 	K(Right, "right", 0)           \ | ||||||
| 	K(Failure, "FAILURE", 0)       \ | 	K(Failure, "FAILURE", 0)       \ | ||||||
|  | 	K(Storage, "storage", 0) \ | ||||||
| 
 | 
 | ||||||
| namespace soltest | namespace soltest | ||||||
| { | { | ||||||
| @ -275,16 +276,23 @@ struct FunctionCall | |||||||
| 		MultiLine | 		MultiLine | ||||||
| 	}; | 	}; | ||||||
| 	DisplayMode displayMode = DisplayMode::SingleLine; | 	DisplayMode displayMode = DisplayMode::SingleLine; | ||||||
|  | 
 | ||||||
|  | 	enum class Kind { | ||||||
|  | 		Regular, | ||||||
| 		/// Marks this function call as the constructor.
 | 		/// Marks this function call as the constructor.
 | ||||||
| 	bool isConstructor = false; | 		Constructor, | ||||||
| 		/// If this function call's signature has no name and no arguments,
 | 		/// If this function call's signature has no name and no arguments,
 | ||||||
| 		/// a low-level call with unstructured calldata will be issued.
 | 		/// a low-level call with unstructured calldata will be issued.
 | ||||||
| 	bool useCallWithoutSignature = false; | 		LowLevel, | ||||||
|  | 		/// Marks a library deployment call.
 | ||||||
|  | 		Library, | ||||||
|  | 		/// Check that the storage of the current contract is empty or non-empty.
 | ||||||
|  | 		Storage | ||||||
|  | 	}; | ||||||
|  | 	Kind kind = Kind::Regular; | ||||||
| 	/// Marks this function call as "short-handed", meaning
 | 	/// Marks this function call as "short-handed", meaning
 | ||||||
| 	/// no `->` declared.
 | 	/// no `->` declared.
 | ||||||
| 	bool omitsArrow = true; | 	bool omitsArrow = true; | ||||||
| 	/// Marks a library deployment call.
 |  | ||||||
| 	bool isLibrary = false; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -82,12 +82,31 @@ vector<solidity::frontend::test::FunctionCall> TestFileParser::parseFunctionCall | |||||||
| 						expect(Token::Colon); | 						expect(Token::Colon); | ||||||
| 						call.signature = m_scanner.currentLiteral(); | 						call.signature = m_scanner.currentLiteral(); | ||||||
| 						expect(Token::Identifier); | 						expect(Token::Identifier); | ||||||
| 						call.isLibrary = true; | 						call.kind = FunctionCall::Kind::Library; | ||||||
| 						call.expectations.failure = false; | 						call.expectations.failure = false; | ||||||
| 					} | 					} | ||||||
|  | 					else if (accept(Token::Storage, true)) | ||||||
|  | 					{ | ||||||
|  | 						expect(Token::Colon); | ||||||
|  | 						call.expectations.failure = false; | ||||||
|  | 						call.expectations.result.push_back(Parameter()); | ||||||
|  | 						// empty / non-empty is encoded as false / true
 | ||||||
|  | 						if (m_scanner.currentLiteral() == "empty") | ||||||
|  | 							call.expectations.result.back().rawBytes = bytes(1, uint8_t(false)); | ||||||
|  | 						else if (m_scanner.currentLiteral() == "nonempty") | ||||||
|  | 							call.expectations.result.back().rawBytes = bytes(1, uint8_t(true)); | ||||||
|  | 						else | ||||||
|  | 							throw TestParserError("Expected \"empty\" or \"nonempty\"."); | ||||||
|  | 						call.kind = FunctionCall::Kind::Storage; | ||||||
|  | 						m_scanner.scanNextToken(); | ||||||
|  | 					} | ||||||
| 					else | 					else | ||||||
| 					{ | 					{ | ||||||
| 						tie(call.signature, call.useCallWithoutSignature) = parseFunctionSignature(); | 						bool lowLevelCall = false; | ||||||
|  | 						tie(call.signature, lowLevelCall) = parseFunctionSignature(); | ||||||
|  | 						if (lowLevelCall) | ||||||
|  | 							call.kind = FunctionCall::Kind::LowLevel; | ||||||
|  | 
 | ||||||
| 						if (accept(Token::Comma, true)) | 						if (accept(Token::Comma, true)) | ||||||
| 							call.value = parseFunctionCallValue(); | 							call.value = parseFunctionCallValue(); | ||||||
| 
 | 
 | ||||||
| @ -124,8 +143,7 @@ vector<solidity::frontend::test::FunctionCall> TestFileParser::parseFunctionCall | |||||||
| 						call.expectations.comment = parseComment(); | 						call.expectations.comment = parseComment(); | ||||||
| 
 | 
 | ||||||
| 						if (call.signature == "constructor()") | 						if (call.signature == "constructor()") | ||||||
| 							call.isConstructor = true; | 							call.kind = FunctionCall::Kind::Constructor; | ||||||
| 
 |  | ||||||
| 					} | 					} | ||||||
| 
 | 
 | ||||||
| 					calls.emplace_back(std::move(call)); | 					calls.emplace_back(std::move(call)); | ||||||
| @ -481,6 +499,7 @@ void TestFileParser::Scanner::scanNextToken() | |||||||
| 		if (_literal == "right") return TokenDesc{Token::Right, _literal}; | 		if (_literal == "right") return TokenDesc{Token::Right, _literal}; | ||||||
| 		if (_literal == "hex") return TokenDesc{Token::Hex, _literal}; | 		if (_literal == "hex") return TokenDesc{Token::Hex, _literal}; | ||||||
| 		if (_literal == "FAILURE") return TokenDesc{Token::Failure, _literal}; | 		if (_literal == "FAILURE") return TokenDesc{Token::Failure, _literal}; | ||||||
|  | 		if (_literal == "storage") return TokenDesc{Token::Storage, _literal}; | ||||||
| 		return TokenDesc{Token::Identifier, _literal}; | 		return TokenDesc{Token::Identifier, _literal}; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -44,7 +44,8 @@ namespace solidity::frontend::test | |||||||
|  * // h(uint256), 1 ether: 42
 |  * // h(uint256), 1 ether: 42
 | ||||||
|  * // -> FAILURE                # If REVERT or other EVM failure was detected #
 |  * // -> FAILURE                # If REVERT or other EVM failure was detected #
 | ||||||
|  * // ()                        # Call fallback function #
 |  * // ()                        # Call fallback function #
 | ||||||
|  * // (), 1 ether               # Call ether function #
 |  * // (), 1 ether               # Call receive ether function #
 | ||||||
|  |  * // EMPTY_STORAGE             # Check that storage is empty
 | ||||||
|  * ... |  * ... | ||||||
|  */ |  */ | ||||||
| class TestFileParser | class TestFileParser | ||||||
|  | |||||||
| @ -82,8 +82,8 @@ void testFunctionCall( | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BOOST_REQUIRE_EQUAL(_call.isConstructor, _isConstructor); | 	BOOST_REQUIRE_EQUAL(_call.kind == FunctionCall::Kind::Constructor, _isConstructor); | ||||||
| 	BOOST_REQUIRE_EQUAL(_call.isLibrary, _isLibrary); | 	BOOST_REQUIRE_EQUAL(_call.kind == FunctionCall::Kind::Library, _isLibrary); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_SUITE(TestFileParserTest) | BOOST_AUTO_TEST_SUITE(TestFileParserTest) | ||||||
| @ -953,6 +953,28 @@ BOOST_AUTO_TEST_CASE(library) | |||||||
| 	); | 	); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | BOOST_AUTO_TEST_CASE(empty_storage) | ||||||
|  | { | ||||||
|  | 	char const* source = R"( | ||||||
|  | 		// storage: empty
 | ||||||
|  | 	)"; | ||||||
|  | 	auto const calls = parse(source); | ||||||
|  | 	BOOST_REQUIRE_EQUAL(calls.size(), 1); | ||||||
|  | 	BOOST_CHECK(calls.at(0).kind == FunctionCall::Kind::Storage); | ||||||
|  | 	BOOST_CHECK(calls.at(0).expectations.result.front().rawBytes == bytes(1, 0)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | BOOST_AUTO_TEST_CASE(nonempty_storage) | ||||||
|  | { | ||||||
|  | 	char const* source = R"( | ||||||
|  | 		// storage: nonempty
 | ||||||
|  | 	)"; | ||||||
|  | 	auto const calls = parse(source); | ||||||
|  | 	BOOST_REQUIRE_EQUAL(calls.size(), 1); | ||||||
|  | 	BOOST_CHECK(calls.at(0).kind == FunctionCall::Kind::Storage); | ||||||
|  | 	BOOST_CHECK(calls.at(0).expectations.result.front().rawBytes == bytes(1, 1)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -56,11 +56,25 @@ string TestFunctionCall::format( | |||||||
| 		string newline = formatToken(Token::Newline); | 		string newline = formatToken(Token::Newline); | ||||||
| 		string failure = formatToken(Token::Failure); | 		string failure = formatToken(Token::Failure); | ||||||
| 
 | 
 | ||||||
| 		if (m_call.isLibrary) | 		if (m_call.kind == FunctionCall::Kind::Library) | ||||||
| 		{ | 		{ | ||||||
| 			stream << _linePrefix << newline << ws << "library:" << ws << m_call.signature; | 			stream << _linePrefix << newline << ws << "library:" << ws << m_call.signature; | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  | 		else if (m_call.kind == FunctionCall::Kind::Storage) | ||||||
|  | 		{ | ||||||
|  | 			stream << _linePrefix << newline << ws << "storage" << colon << ws; | ||||||
|  | 			soltestAssert(m_rawBytes.size() == 1, ""); | ||||||
|  | 			soltestAssert(m_call.expectations.rawBytes().size() == 1, ""); | ||||||
|  | 			bool isEmpty = _renderResult ? m_rawBytes.front() == 0 : m_call.expectations.rawBytes().front() == 0; | ||||||
|  | 			string output = isEmpty ? "empty" : "nonempty"; | ||||||
|  | 			if (_renderResult && !matchesExpectation()) | ||||||
|  | 				AnsiColorized(stream, highlight, {util::formatting::RED_BACKGROUND}) << output; | ||||||
|  | 			else | ||||||
|  | 				stream << output; | ||||||
|  | 
 | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		/// Formats the function signature. This is the same independent from the display-mode.
 | 		/// Formats the function signature. This is the same independent from the display-mode.
 | ||||||
| 		stream << _linePrefix << newline << ws << m_call.signature; | 		stream << _linePrefix << newline << ws << m_call.signature; | ||||||
|  | |||||||
| @ -115,8 +115,6 @@ uint64_t popcnt(uint64_t _v) | |||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| using u512 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<512, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>; |  | ||||||
| 
 |  | ||||||
| u256 EwasmBuiltinInterpreter::evalBuiltin( | u256 EwasmBuiltinInterpreter::evalBuiltin( | ||||||
| 	YulString _functionName, | 	YulString _functionName, | ||||||
| 	vector<Expression> const& _arguments, | 	vector<Expression> const& _arguments, | ||||||
| @ -144,7 +142,7 @@ u256 EwasmBuiltinInterpreter::evalBuiltin( | |||||||
| 	else if (fun == "datacopy") | 	else if (fun == "datacopy") | ||||||
| 	{ | 	{ | ||||||
| 		// This is identical to codecopy.
 | 		// This is identical to codecopy.
 | ||||||
| 		if (accessMemory(_evaluatedArguments.at(0), _evaluatedArguments.at(2))) | 		accessMemory(_evaluatedArguments.at(0), _evaluatedArguments.at(2)); | ||||||
| 		copyZeroExtended( | 		copyZeroExtended( | ||||||
| 			m_state.memory, | 			m_state.memory, | ||||||
| 			m_state.code, | 			m_state.code, | ||||||
| @ -324,7 +322,7 @@ u256 EwasmBuiltinInterpreter::evalEthBuiltin(string const& _fun, vector<uint64_t | |||||||
| 	{ | 	{ | ||||||
| 		if (arg[1] + arg[2] < arg[1] || arg[1] + arg[2] > m_state.calldata.size()) | 		if (arg[1] + arg[2] < arg[1] || arg[1] + arg[2] > m_state.calldata.size()) | ||||||
| 			throw ExplicitlyTerminated(); | 			throw ExplicitlyTerminated(); | ||||||
| 		if (accessMemory(arg[0], arg[2])) | 		accessMemory(arg[0], arg[2]); | ||||||
| 		copyZeroExtended( | 		copyZeroExtended( | ||||||
| 			m_state.memory, m_state.calldata, | 			m_state.memory, m_state.calldata, | ||||||
| 			size_t(arg[0]), size_t(arg[1]), size_t(arg[2]) | 			size_t(arg[0]), size_t(arg[1]), size_t(arg[2]) | ||||||
| @ -377,7 +375,7 @@ u256 EwasmBuiltinInterpreter::evalEthBuiltin(string const& _fun, vector<uint64_t | |||||||
| 	} | 	} | ||||||
| 	else if (_fun == "codeCopy") | 	else if (_fun == "codeCopy") | ||||||
| 	{ | 	{ | ||||||
| 		if (accessMemory(arg[0], arg[2])) | 		accessMemory(arg[0], arg[2]); | ||||||
| 		copyZeroExtended( | 		copyZeroExtended( | ||||||
| 			m_state.memory, m_state.code, | 			m_state.memory, m_state.code, | ||||||
| 			size_t(arg[0]), size_t(arg[1]), size_t(arg[2]) | 			size_t(arg[0]), size_t(arg[1]), size_t(arg[2]) | ||||||
| @ -407,7 +405,7 @@ u256 EwasmBuiltinInterpreter::evalEthBuiltin(string const& _fun, vector<uint64_t | |||||||
| 	else if (_fun == "externalCodeCopy") | 	else if (_fun == "externalCodeCopy") | ||||||
| 	{ | 	{ | ||||||
| 		readAddress(arg[0]); | 		readAddress(arg[0]); | ||||||
| 		if (accessMemory(arg[1], arg[3])) | 		accessMemory(arg[1], arg[3]); | ||||||
| 		// TODO this way extcodecopy and codecopy do the same thing.
 | 		// TODO this way extcodecopy and codecopy do the same thing.
 | ||||||
| 		copyZeroExtended( | 		copyZeroExtended( | ||||||
| 			m_state.memory, m_state.code, | 			m_state.memory, m_state.code, | ||||||
| @ -454,7 +452,7 @@ u256 EwasmBuiltinInterpreter::evalEthBuiltin(string const& _fun, vector<uint64_t | |||||||
| 	else if (_fun == "finish") | 	else if (_fun == "finish") | ||||||
| 	{ | 	{ | ||||||
| 		bytes data; | 		bytes data; | ||||||
| 		if (accessMemory(arg[0], arg[1])) | 		accessMemory(arg[0], arg[1]); | ||||||
| 		data = readMemory(arg[0], arg[1]); | 		data = readMemory(arg[0], arg[1]); | ||||||
| 		logTrace(evmasm::Instruction::RETURN, {}, data); | 		logTrace(evmasm::Instruction::RETURN, {}, data); | ||||||
| 		throw ExplicitlyTerminated(); | 		throw ExplicitlyTerminated(); | ||||||
| @ -462,7 +460,7 @@ u256 EwasmBuiltinInterpreter::evalEthBuiltin(string const& _fun, vector<uint64_t | |||||||
| 	else if (_fun == "revert") | 	else if (_fun == "revert") | ||||||
| 	{ | 	{ | ||||||
| 		bytes data; | 		bytes data; | ||||||
| 		if (accessMemory(arg[0], arg[1])) | 		accessMemory(arg[0], arg[1]); | ||||||
| 		data = readMemory(arg[0], arg[1]); | 		data = readMemory(arg[0], arg[1]); | ||||||
| 		logTrace(evmasm::Instruction::REVERT, {}, data); | 		logTrace(evmasm::Instruction::REVERT, {}, data); | ||||||
| 		throw ExplicitlyTerminated(); | 		throw ExplicitlyTerminated(); | ||||||
| @ -473,7 +471,7 @@ u256 EwasmBuiltinInterpreter::evalEthBuiltin(string const& _fun, vector<uint64_t | |||||||
| 	{ | 	{ | ||||||
| 		if (arg[1] + arg[2] < arg[1] || arg[1] + arg[2] > m_state.returndata.size()) | 		if (arg[1] + arg[2] < arg[1] || arg[1] + arg[2] > m_state.returndata.size()) | ||||||
| 			throw ExplicitlyTerminated(); | 			throw ExplicitlyTerminated(); | ||||||
| 		if (accessMemory(arg[0], arg[2])) | 		accessMemory(arg[0], arg[2]); | ||||||
| 		copyZeroExtended( | 		copyZeroExtended( | ||||||
| 			m_state.memory, m_state.calldata, | 			m_state.memory, m_state.calldata, | ||||||
| 			size_t(arg[0]), size_t(arg[1]), size_t(arg[2]) | 			size_t(arg[0]), size_t(arg[1]), size_t(arg[2]) | ||||||
| @ -494,18 +492,15 @@ u256 EwasmBuiltinInterpreter::evalEthBuiltin(string const& _fun, vector<uint64_t | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool EwasmBuiltinInterpreter::accessMemory(u256 const& _offset, u256 const& _size) | void EwasmBuiltinInterpreter::accessMemory(u256 const& _offset, u256 const& _size) | ||||||
| { | { | ||||||
| 	if (((_offset + _size) >= _offset) && ((_offset + _size + 0x1f) >= (_offset + _size))) | 	// Single WebAssembly page.
 | ||||||
| 	{ | 	// TODO: Support expansion in this interpreter.
 | ||||||
| 		u256 newSize = (_offset + _size + 0x1f) & ~u256(0x1f); | 	m_state.msize = 65536; | ||||||
| 		m_state.msize = max(m_state.msize, newSize); |  | ||||||
| 		return _size <= 0xffff; |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 		m_state.msize = u256(-1); |  | ||||||
| 
 | 
 | ||||||
| 	return false; | 	if (((_offset + _size) < _offset) || ((_offset + _size) > m_state.msize)) | ||||||
|  | 		// Ewasm throws out of bounds exception as opposed to the EVM.
 | ||||||
|  | 		throw ExplicitlyTerminated(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bytes EwasmBuiltinInterpreter::readMemory(uint64_t _offset, uint64_t _size) | bytes EwasmBuiltinInterpreter::readMemory(uint64_t _offset, uint64_t _size) | ||||||
|  | |||||||
| @ -91,8 +91,7 @@ private: | |||||||
| 
 | 
 | ||||||
| 	/// Checks if the memory access is not too large for the interpreter and adjusts
 | 	/// Checks if the memory access is not too large for the interpreter and adjusts
 | ||||||
| 	/// msize accordingly.
 | 	/// msize accordingly.
 | ||||||
| 	/// @returns false if the amount of bytes read is lager than 0xffff
 | 	void accessMemory(u256 const& _offset, u256 const& _size = 32); | ||||||
| 	bool accessMemory(u256 const& _offset, u256 const& _size = 32); |  | ||||||
| 	/// @returns the memory contents at the provided address.
 | 	/// @returns the memory contents at the provided address.
 | ||||||
| 	/// Does not adjust msize, use @a accessMemory for that
 | 	/// Does not adjust msize, use @a accessMemory for that
 | ||||||
| 	bytes readMemory(uint64_t _offset, uint64_t _size = 32); | 	bytes readMemory(uint64_t _offset, uint64_t _size = 32); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user