mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Add eWasm externals.
This commit is contained in:
		
							parent
							
								
									f3bdc79187
								
							
						
					
					
						commit
						e3433aa4eb
					
				| @ -268,61 +268,96 @@ function signextend(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| } | ||||
| 
 | ||||
| function u256_to_i64(x1, x2, x3, x4) -> v { | ||||
| 	if i64.ne(0, i64.or(i64.or(x1, x2), x3)) { invalid() } | ||||
| 	v := x4 | ||||
| } | ||||
| 
 | ||||
| function u256_to_i32(x1, x2, x3, x4) -> v { | ||||
| 	if i64.ne(0, i64.or(i64.or(x1, x2), x3)) { invalid() } | ||||
| 	if i64.ne(0, i64.shr_u(x4, 32)) { invalid() } | ||||
| 	v := x4 | ||||
| } | ||||
| 
 | ||||
| function u256_to_i32ptr(x1, x2, x3, x4) -> v { | ||||
| 	v := u256_to_i32(x1, x2, x3, x4) | ||||
| } | ||||
| 
 | ||||
| function keccak256(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| } | ||||
| 
 | ||||
| function address() -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	let t1, t2, t3, t4 := save_temp_mem_32() | ||||
| 	eth.getAddress(0) | ||||
| 	z1, z2, z3, z4 := mload(0, 0, 0, 0) | ||||
| 	restore_temp_mem_32(t1, t2, t3, t4) | ||||
| } | ||||
| function balance(x1, x2, x3, x4) -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| } | ||||
| function origin() -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	let t1, t2, t3, t4 := save_temp_mem_32() | ||||
| 	eth.getTxOrigin(0) | ||||
| 	z1, z2, z3, z4 := mload(0, 0, 0, 0) | ||||
| 	restore_temp_mem_32(t1, t2, t3, t4) | ||||
| } | ||||
| function caller() -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	let t1, t2, t3, t4 := save_temp_mem_32() | ||||
| 	eth.getCaller(0) | ||||
| 	z1, z2, z3, z4 := mload(0, 0, 0, 0) | ||||
| 	restore_temp_mem_32(t1, t2, t3, t4) | ||||
| } | ||||
| function callvalue() -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	let t1, t2, t3, t4 := save_temp_mem_32() | ||||
| 	eth.getCallValue(0) | ||||
| 	z1, z2, z3, z4 := mload(0, 0, 0, 0) | ||||
| 	restore_temp_mem_32(t1, t2, t3, t4) | ||||
| } | ||||
| function calldataload(x1, x2, x3, x4) -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	let t1, t2, t3, t4 := save_temp_mem_32() | ||||
| 	eth.callDataCopy(0, u256_to_i32(x1, x2, x3, x4), 32) | ||||
| 	z1, z2, z3, z4 := mload(0, 0, 0, 0) | ||||
| 	restore_temp_mem_32(t1, t2, t3, t4) | ||||
| } | ||||
| function calldatasize() -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	z4 := eth.getCallDataSize() | ||||
| } | ||||
| function calldatacopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	eth.callDataCopy( | ||||
| 		u256_to_i32ptr(x1, x2, x3, x4), | ||||
| 		u256_to_i32(y1, y2, y3, y4), | ||||
| 		u256_to_i32(z1, z2, z3, z4) | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| // Needed?
 | ||||
| function codesize() -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	let t1, t2, t3, t4 := save_temp_mem_32() | ||||
| 	eth.getCodeSize(0) | ||||
| 	z1, z2, z3, z4 := mload(0, 0, 0, 0) | ||||
| 	restore_temp_mem_32(t1, t2, t3, t4) | ||||
| } | ||||
| function codecopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	eth.codeCopy( | ||||
| 		u256_to_i32ptr(x1, x2, x3, x4), | ||||
| 		u256_to_i32(y1, y2, y3, y4), | ||||
| 		u256_to_i32(z1, z2, z3, z4) | ||||
| 	) | ||||
| } | ||||
| function datacopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	// TODO correct?
 | ||||
| 	codecopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) | ||||
| } | ||||
| 
 | ||||
| function gasprice() -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	let t1, t2, t3, t4 := save_temp_mem_32() | ||||
| 	eth.getTxGasPrice(0) | ||||
| 	z1, z2, z3, z4 := mload(0, 0, 0, 0) | ||||
| 	restore_temp_mem_32(t1, t2, t3, t4) | ||||
| } | ||||
| function extcodesize(x1, x2, x3, x4) -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| @ -338,12 +373,14 @@ function extcodecopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) { | ||||
| } | ||||
| 
 | ||||
| function returndatasize() -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	z4 := eth.getReturnDataSize() | ||||
| } | ||||
| function returndatacopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	eth.returnDataCopy( | ||||
| 		u256_to_i32ptr(x1, x2, x3, x4), | ||||
| 		u256_to_i32(y1, y2, y3, y4), | ||||
| 		u256_to_i32(z1, z2, z3, z4) | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| function blockhash(x1, x2, x3, x4) -> z1, z2, z3, z4 { | ||||
| @ -355,34 +392,87 @@ function coinbase() -> z1, z2, z3, z4 { | ||||
| 	unreachable() | ||||
| } | ||||
| function timestamp() -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	z4 := eth.getBlockTimestamp() | ||||
| } | ||||
| function number() -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	z4 := eth.getBlockNumber() | ||||
| } | ||||
| function difficulty() -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	let t1, t2, t3, t4 := save_temp_mem_32() | ||||
| 	eth.getBlockDifficulty(0) | ||||
| 	z1, z2, z3, z4 := mload(0, 0, 0, 0) | ||||
| 	restore_temp_mem_32(t1, t2, t3, t4) | ||||
| } | ||||
| function gaslimit() -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	z4 := eth.getBlockGasLimit() | ||||
| } | ||||
| 
 | ||||
| function pop(x1, x2, x3, x4) { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| function endian_swap_16(x) -> y { | ||||
| 	let hi := i64.and(i64.shl(x, 8), 0xff00) | ||||
| 	let lo := i64.and(i64.shr_u(x, 8), 0xff) | ||||
| 	y := i64.or(hi, lo) | ||||
| } | ||||
| 
 | ||||
| function endian_swap_32(x) -> y { | ||||
| 	let hi := i64.shl(endian_swap_16(x), 16) | ||||
| 	let lo := endian_swap_16(i64.shr_u(x, 16)) | ||||
| 	y := i64.or(hi, lo) | ||||
| } | ||||
| 
 | ||||
| function endian_swap(x) -> y { | ||||
| 	let hi := i64.shl(endian_swap_32(x), 32) | ||||
| 	let lo := endian_swap_32(i64.shr_u(x, 32)) | ||||
| 	y := i64.or(hi, lo) | ||||
| } | ||||
| function save_temp_mem_32() -> t1, t2, t3, t4 { | ||||
| 	t1 := i64.load(0) | ||||
| 	t2 := i64.load(8) | ||||
| 	t3 := i64.load(16) | ||||
| 	t4 := i64.load(24) | ||||
| } | ||||
| function restore_temp_mem_32(t1, t2, t3, t4) { | ||||
| 	i64.store(0, t1) | ||||
| 	i64.store(8, t2) | ||||
| 	i64.store(16, t3) | ||||
| 	i64.store(24, t4) | ||||
| } | ||||
| function save_temp_mem_64() -> t1, t2, t3, t4, t5, t6, t7, t8 { | ||||
| 	t1 := i64.load(0) | ||||
| 	t2 := i64.load(8) | ||||
| 	t3 := i64.load(16) | ||||
| 	t4 := i64.load(24) | ||||
| 	t5 := i64.load(32) | ||||
| 	t6 := i64.load(40) | ||||
| 	t7 := i64.load(48) | ||||
| 	t8 := i64.load(54) | ||||
| } | ||||
| function restore_temp_mem_64(t1, t2, t3, t4, t5, t6, t7, t8) { | ||||
| 	i64.store(0, t1) | ||||
| 	i64.store(8, t2) | ||||
| 	i64.store(16, t3) | ||||
| 	i64.store(24, t4) | ||||
| 	i64.store(32, t5) | ||||
| 	i64.store(40, t6) | ||||
| 	i64.store(48, t7) | ||||
| 	i64.store(54, t8) | ||||
| } | ||||
| function mload(x1, x2, x3, x4) -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	let pos := u256_to_i32ptr(x1, x2, x3, x4) | ||||
| 	z1 := endian_swap(i64.load(pos)) | ||||
| 	z2 := endian_swap(i64.load(i64.add(pos, 8))) | ||||
| 	z3 := endian_swap(i64.load(i64.add(pos, 16))) | ||||
| 	z4 := endian_swap(i64.load(i64.add(pos, 24))) | ||||
| } | ||||
| function mstore(x1, x2, x3, x4, y1, y2, y3, y4) { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	let pos := u256_to_i32ptr(x1, x2, x3, x4) | ||||
| 	i64.store(pos, endian_swap(x1)) | ||||
| 	i64.store(i64.add(pos, 8), endian_swap(x2)) | ||||
| 	i64.store(i64.add(pos, 16), endian_swap(x3)) | ||||
| 	i64.store(i64.add(pos, 24), endian_swap(x4)) | ||||
| } | ||||
| function mstore8(x1, x2, x3, x4, y1, y2, y3, y4) { | ||||
| 	// TODO implement
 | ||||
| @ -394,12 +484,19 @@ function msize() -> z1, z2, z3, z4 { | ||||
| 	unreachable() | ||||
| } | ||||
| function sload(x1, x2, x3, x4) -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	let t1, t2, t3, t4, t5, t6, t7, t8 := save_temp_mem_64() | ||||
| 	mstore(0, 0, 0, 0, x1, x2, x3, x4) | ||||
| 	eth.storageLoad(0, 16) | ||||
| 	z1, z2, z3, z4 := mload(0, 0, 0, 16) | ||||
| 	restore_temp_mem_64(t1, t2, t3, t4, t5, t6, t7, t8) | ||||
| } | ||||
| 
 | ||||
| function sstore(x1, x2, x3, x4, y1, y2, y3, y4) { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	let t1, t2, t3, t4, t5, t6, t7, t8 := save_temp_mem_64() | ||||
| 	mstore(0, 0, 0, 0, x1, x2, x3, x4) | ||||
| 	mstore(0, 0, 0, 32, y1, y2, y3, y4) | ||||
| 	eth.storageStore(0, 32) | ||||
| 	restore_temp_mem_64(t1, t2, t3, t4, t5, t6, t7, t8) | ||||
| } | ||||
| 
 | ||||
| // Needed?
 | ||||
| @ -408,8 +505,7 @@ function pc() -> z1, z2, z3, z4 { | ||||
| 	unreachable() | ||||
| } | ||||
| function gas() -> z1, z2, z3, z4 { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	z4 := eth.getGasLeft() | ||||
| } | ||||
| 
 | ||||
| function log0(p1, p2, p3, p4, s1, s2, s3, s4) { | ||||
| @ -511,17 +607,22 @@ function create2( | ||||
| 	unreachable() | ||||
| } | ||||
| function selfdestruct(a1, a2, a3, a4) { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	mstore(0, 0, 0, 0, a1, a2, a3, a4) | ||||
| 	// In EVM, addresses are padded to 32 bytes, so discard the first 12.
 | ||||
| 	eth.selfDestruct(12) | ||||
| } | ||||
| 
 | ||||
| function return(x1, x2, x3, x4, y1, y2, y3, y4) { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	eth.finish( | ||||
| 		u256_to_i32ptr(x1, x2, x3, x4), | ||||
| 		u256_to_i32(y1, y2, y3, y4) | ||||
| 	) | ||||
| } | ||||
| function revert(x1, x2, x3, x4, y1, y2, y3, y4) { | ||||
| 	// TODO implement
 | ||||
| 	unreachable() | ||||
| 	eth.revert( | ||||
| 		u256_to_i32ptr(x1, x2, x3, x4), | ||||
| 		u256_to_i32(y1, y2, y3, y4) | ||||
| 	) | ||||
| } | ||||
| function invalid() { | ||||
| 	unreachable() | ||||
|  | ||||
| @ -70,6 +70,13 @@ struct Continue { Label label; }; | ||||
| 
 | ||||
| struct VariableDeclaration { std::string variableName; }; | ||||
| struct GlobalVariableDeclaration { std::string variableName; }; | ||||
| struct FunctionImport { | ||||
| 	std::string module; | ||||
| 	std::string externalName; | ||||
| 	std::string internalName; | ||||
| 	std::vector<std::string> paramTypes; | ||||
| 	std::unique_ptr<std::string> returnType; | ||||
| }; | ||||
| 
 | ||||
| struct FunctionDefinition | ||||
| { | ||||
|  | ||||
| @ -52,7 +52,14 @@ string EWasmCodeTransform::run(Dialect const& _dialect, yul::Block const& _ast) | ||||
| 			functions.emplace_back(transform.translateFunction(boost::get<yul::FunctionDefinition>(statement))); | ||||
| 	} | ||||
| 
 | ||||
| 	return EWasmToText{}.run(transform.m_globalVariables, functions); | ||||
| 	std::vector<wasm::FunctionImport> imports; | ||||
| 	for (auto& imp: transform.m_functionsToImport) | ||||
| 		imports.emplace_back(std::move(imp.second)); | ||||
| 	return EWasmToText{}.run( | ||||
| 		transform.m_globalVariables, | ||||
| 		imports, | ||||
| 		functions | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| wasm::Expression EWasmCodeTransform::generateMultiAssignment( | ||||
| @ -128,7 +135,25 @@ wasm::Expression EWasmCodeTransform::operator()(FunctionCall const& _call) | ||||
| { | ||||
| 	if (BuiltinFunction const* builtin = m_dialect.builtin(_call.functionName.name)) | ||||
| 	{ | ||||
| 		if (builtin->literalArguments) | ||||
| 		if (_call.functionName.name.str().substr(0, 4) == "eth.") | ||||
| 		{ | ||||
| 			yulAssert(builtin->returns.size() <= 1, ""); | ||||
| 			// Imported function, use regular call, but mark for import.
 | ||||
| 			if (!m_functionsToImport.count(builtin->name)) | ||||
| 			{ | ||||
| 				wasm::FunctionImport imp{ | ||||
| 					"ethereum", | ||||
| 					builtin->name.str().substr(4), | ||||
| 					builtin->name.str(), | ||||
| 					{}, | ||||
| 					builtin->returns.empty() ? nullptr : make_unique<string>(builtin->returns.front().str()) | ||||
| 				}; | ||||
| 				for (auto const& param: builtin->parameters) | ||||
| 					imp.paramTypes.emplace_back(param.str()); | ||||
| 				m_functionsToImport[builtin->name] = std::move(imp); | ||||
| 			} | ||||
| 		} | ||||
| 		else if (builtin->literalArguments) | ||||
| 		{ | ||||
| 			vector<wasm::Expression> literals; | ||||
| 			for (auto const& arg: _call.arguments) | ||||
| @ -138,12 +163,12 @@ wasm::Expression EWasmCodeTransform::operator()(FunctionCall const& _call) | ||||
| 		else | ||||
| 			return wasm::BuiltinCall{_call.functionName.name.str(), visit(_call.arguments)}; | ||||
| 	} | ||||
| 	else | ||||
| 		// If this function returns multiple values, then the first one will
 | ||||
| 		// be returned in the expression itself and the others in global variables.
 | ||||
| 		// The values have to be used right away in an assignment or variable declaration,
 | ||||
| 		// so it is handled there.
 | ||||
| 		return wasm::FunctionCall{_call.functionName.name.str(), visit(_call.arguments)}; | ||||
| 
 | ||||
| 	// If this function returns multiple values, then the first one will
 | ||||
| 	// be returned in the expression itself and the others in global variables.
 | ||||
| 	// The values have to be used right away in an assignment or variable declaration,
 | ||||
| 	// so it is handled there.
 | ||||
| 	return wasm::FunctionCall{_call.functionName.name.str(), visit(_call.arguments)}; | ||||
| } | ||||
| 
 | ||||
| wasm::Expression EWasmCodeTransform::operator()(Identifier const& _identifier) | ||||
|  | ||||
| @ -26,6 +26,7 @@ | ||||
| #include <libyul/optimiser/NameDispenser.h> | ||||
| 
 | ||||
| #include <stack> | ||||
| #include <map> | ||||
| 
 | ||||
| namespace yul | ||||
| { | ||||
| @ -90,6 +91,7 @@ private: | ||||
| 
 | ||||
| 	std::vector<wasm::VariableDeclaration> m_localVariables; | ||||
| 	std::vector<wasm::GlobalVariableDeclaration> m_globalVariables; | ||||
| 	std::map<YulString, wasm::FunctionImport> m_functionsToImport; | ||||
| 	std::stack<std::pair<std::string, std::string>> m_breakContinueLabelNames; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -28,15 +28,24 @@ | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace yul; | ||||
| using namespace dev; | ||||
| 
 | ||||
| string EWasmToText::run( | ||||
| 	vector<wasm::GlobalVariableDeclaration> const& _globals, | ||||
| 	vector<wasm::FunctionImport> const& _imports, | ||||
| 	vector<wasm::FunctionDefinition> const& _functions | ||||
| ) | ||||
| { | ||||
| 	string ret = "(module\n"; | ||||
| 	// TODO Add all the interface functions:
 | ||||
| 	// ret += "    (import \"ethereum\" \"getBalance\"  (func $getBalance (param i32 i32)))\n";
 | ||||
| 	for (wasm::FunctionImport const& imp: _imports) | ||||
| 	{ | ||||
| 		ret += "    (import \"" + imp.module + "\" \"" + imp.externalName + "\" (func $" + imp.internalName; | ||||
| 		if (!imp.paramTypes.empty()) | ||||
| 			ret += " (param" + joinHumanReadablePrefixed(imp.paramTypes, " ", " ") + ")"; | ||||
| 		if (imp.returnType) | ||||
| 			ret += " (result " + *imp.returnType + ")"; | ||||
| 		ret += "))\n"; | ||||
| 	} | ||||
| 
 | ||||
| 	// allocate one 64k page of memory and make it available to the Ethereum client
 | ||||
| 	ret += "    (memory $memory (export \"memory\") 1)\n"; | ||||
|  | ||||
| @ -33,6 +33,7 @@ class EWasmToText: public boost::static_visitor<std::string> | ||||
| public: | ||||
| 	std::string run( | ||||
| 		std::vector<wasm::GlobalVariableDeclaration> const& _globals, | ||||
| 		std::vector<wasm::FunctionImport> const& _imports, | ||||
| 		std::vector<wasm::FunctionDefinition> const& _functions | ||||
| 	); | ||||
| 
 | ||||
|  | ||||
| @ -65,6 +65,8 @@ WasmDialect::WasmDialect(): | ||||
| 
 | ||||
| 	addFunction("datasize", 1, 4, true, true); | ||||
| 	addFunction("dataoffset", 1, 4, true, true); | ||||
| 
 | ||||
| 	addEthereumExternals(); | ||||
| } | ||||
| 
 | ||||
| BuiltinFunction const* WasmDialect::builtin(YulString _name) const | ||||
| @ -85,6 +87,69 @@ WasmDialect const& WasmDialect::instance() | ||||
| 	return *dialect; | ||||
| } | ||||
| 
 | ||||
| void WasmDialect::addEthereumExternals() | ||||
| { | ||||
| 	// These are not YulStrings because that would be too complicated with regards
 | ||||
| 	// to the YulStringRepository reset.
 | ||||
| 	static string const i64{"i64"}; | ||||
| 	static string const i32{"i32"}; | ||||
| 	static string const i32ptr{"i32"}; // Uses "i32" on purpose.
 | ||||
| 	struct External { string name; vector<string> parameters; vector<string> returns; }; | ||||
| 	static vector<External> externals{ | ||||
| 		{"getAddress", {i32ptr}, {}}, | ||||
| 		{"getExternalBalance", {i32ptr, i32ptr}, {}}, | ||||
| 		{"getBlockHash", {i64, i32ptr}, {i32}}, | ||||
| 		{"call", {i64, i32ptr, i32ptr, i32ptr, i32}, {i32}}, | ||||
| 		{"callDataCopy", {i32ptr, i32, i32}, {}}, | ||||
| 		{"getCallDataSize", {}, {i32}}, | ||||
| 		{"callCode", {i64, i32ptr, i32ptr, i32ptr, i32}, {i32}}, | ||||
| 		{"callDelegate", {i64, i32ptr, i32ptr, i32}, {i32}}, | ||||
| 		{"callStatic", {i64, i32ptr, i32ptr, i32}, {i32}}, | ||||
| 		{"storageStore", {i32ptr, i32ptr}, {}}, | ||||
| 		{"storageLoad", {i32ptr, i32ptr}, {}}, | ||||
| 		{"getCaller", {i32ptr}, {}}, | ||||
| 		{"getCallValue", {i32ptr}, {}}, | ||||
| 		{"codeCopy", {i32ptr, i32, i32}, {}}, | ||||
| 		{"getCodeSize", {i32ptr}, {}}, | ||||
| 		{"getBlockCoinbase", {i32ptr}, {}}, | ||||
| 		{"create", {i32ptr, i32ptr, i32, i32ptr}, {i32}}, | ||||
| 		{"getBlockDifficulty", {i32ptr}, {}}, | ||||
| 		{"externalCodeCopy", {i32ptr, i32ptr, i32, i32}, {}}, | ||||
| 		{"getExternalCodeSize", {i32ptr}, {i32}}, | ||||
| 		{"getGasLeft", {}, {i64}}, | ||||
| 		{"getBlockGasLimit", {}, {i64}}, | ||||
| 		{"getTxGasPrice", {i32ptr}, {}}, | ||||
| 		{"log", {i32ptr, i32, i32, i32ptr, i32ptr, i32ptr, i32ptr}, {}}, | ||||
| 		{"getBlockNumber", {}, {i64}}, | ||||
| 		{"getTxOrigin", {i32ptr}, {}}, | ||||
| 		{"finish", {i32ptr, i32}, {}}, | ||||
| 		{"revert", {i32ptr, i32}, {}}, | ||||
| 		{"getReturnDataSize", {}, {i32}}, | ||||
| 		{"returnDataCopy", {i32ptr, i32, i32}, {}}, | ||||
| 		{"selfDestruct", {i32ptr}, {}}, | ||||
| 		{"getBlockTimestamp", {}, {i64}} | ||||
| 	}; | ||||
| 	for (External const& ext: externals) | ||||
| 	{ | ||||
| 		YulString name{"eth." + ext.name}; | ||||
| 		BuiltinFunction& f = m_functions[name]; | ||||
| 		f.name = name; | ||||
| 		for (string const& p: ext.parameters) | ||||
| 			f.parameters.emplace_back(YulString(p)); | ||||
| 		for (string const& p: ext.returns) | ||||
| 			f.returns.emplace_back(YulString(p)); | ||||
| 		f.movable = false; | ||||
| 		// TODO some of them are side effect free.
 | ||||
| 		f.sideEffectFree = false; | ||||
| 		f.sideEffectFreeIfNoMSize = false; | ||||
| 		f.isMSize = false; | ||||
| 		f.invalidatesStorage = (ext.name == "storageStore"); | ||||
| 		// TODO some of them do not invalidate memory
 | ||||
| 		f.invalidatesMemory = true; | ||||
| 		f.literalArguments = false; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void WasmDialect::addFunction( | ||||
| 	string _name, | ||||
| 	size_t _params, | ||||
|  | ||||
| @ -53,6 +53,8 @@ struct WasmDialect: public Dialect | ||||
| 	static WasmDialect const& instance(); | ||||
| 
 | ||||
| private: | ||||
| 	void addEthereumExternals(); | ||||
| 
 | ||||
| 	void addFunction(std::string _name, size_t _params, size_t _returns, bool _movable = true, bool _literalArguments = false); | ||||
| 
 | ||||
| 	std::map<YulString, BuiltinFunction> m_functions; | ||||
|  | ||||
| @ -1,18 +1,160 @@ | ||||
| {"contracts":{"A":{"C":{"ewasm":{"wast":"(module | ||||
|     (import \"ethereum\" \"revert\" (func $eth.revert (param i32 i32))) | ||||
|     (memory $memory (export \"memory\") 1) | ||||
|     (export \"main\" (func $main)) | ||||
| 
 | ||||
| (func $main | ||||
|     (unreachable ) (unreachable ) | ||||
|     (local $_1 i64) | ||||
|     (local $pos i64) | ||||
|     (local $_2 i64) | ||||
|     (local $_3 i64) | ||||
|     (local $hi i64) | ||||
|     (local $_4 i64) | ||||
|     (local $hi_1 i64) | ||||
|     (local $hi_2 i64) | ||||
|     (local $hi_3 i64) | ||||
|     (local $hi_4 i64) | ||||
|     (set_local $_1 (i64.const 0)) | ||||
|     (set_local $pos (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (i64.const 64))) | ||||
|     (set_local $_2 (i64.const 32)) | ||||
|     (set_local $_3 (i64.shr_u (get_local $_1) (i64.const 16))) | ||||
|     (set_local $hi (i64.shl (i64.or (i64.shl (i64.or (i64.and (i64.shl (get_local $_1) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (get_local $_1) (i64.const 8)) (i64.const 255))) (i64.const 16)) (call $endian_swap_16 (get_local $_3))) (get_local $_2))) | ||||
|     (set_local $_4 (i64.shr_u (get_local $_1) (get_local $_2))) | ||||
|     (i64.store (get_local $pos) (i64.or (get_local $hi) (call $endian_swap_32 (get_local $_4)))) (set_local $hi_1 (i64.shl (call $endian_swap_16 (get_local $_1)) (i64.const 16))) | ||||
|     (set_local $hi_2 (i64.shl (i64.or (get_local $hi_1) (call $endian_swap_16 (get_local $_3))) (get_local $_2))) | ||||
|     (i64.store (i64.add (get_local $pos) (i64.const 8)) (i64.or (get_local $hi_2) (call $endian_swap_32 (get_local $_4)))) (set_local $hi_3 (i64.shl (call $endian_swap_32 (get_local $_1)) (get_local $_2))) | ||||
|     (i64.store (i64.add (get_local $pos) (i64.const 16)) (i64.or (get_local $hi_3) (call $endian_swap_32 (get_local $_4)))) (set_local $hi_4 (i64.shl (call $endian_swap_32 (i64.const 64)) (get_local $_2))) | ||||
|     (i64.store (i64.add (get_local $pos) (i64.const 24)) (i64.or (get_local $hi_4) (call $endian_swap_32 (i64.shr_u (i64.const 64) (get_local $_2))))) (call $eth.revert (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (get_local $_1)) (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (get_local $_1))) | ||||
| ) | ||||
| 
 | ||||
| (func $u256_to_i32 | ||||
|     (param $x1 i64) | ||||
|     (param $x2 i64) | ||||
|     (param $x3 i64) | ||||
|     (param $x4 i64) | ||||
|     (result i64) | ||||
|     (local $v i64) | ||||
|     (if (i64.ne (i64.const 0) (i64.or (i64.or (get_local $x1) (get_local $x2)) (get_local $x3))) (then | ||||
|         (unreachable ))) | ||||
|     (if (i64.ne (i64.const 0) (i64.shr_u (get_local $x4) (i64.const 32))) (then | ||||
|         (unreachable ))) | ||||
|     (set_local $v (get_local $x4)) | ||||
|     (get_local $v) | ||||
| ) | ||||
| 
 | ||||
| (func $endian_swap_16 | ||||
|     (param $x i64) | ||||
|     (result i64) | ||||
|     (local $y i64) | ||||
|     (set_local $y (i64.or (i64.and (i64.shl (get_local $x) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (get_local $x) (i64.const 8)) (i64.const 255)))) | ||||
|     (get_local $y) | ||||
| ) | ||||
| 
 | ||||
| (func $endian_swap_32 | ||||
|     (param $x i64) | ||||
|     (result i64) | ||||
|     (local $y i64) | ||||
|     (local $hi i64) | ||||
|     (set_local $hi (i64.shl (call $endian_swap_16 (get_local $x)) (i64.const 16))) | ||||
|     (set_local $y (i64.or (get_local $hi) (call $endian_swap_16 (i64.shr_u (get_local $x) (i64.const 16))))) | ||||
|     (get_local $y) | ||||
| ) | ||||
| 
 | ||||
| ) | ||||
| (module | ||||
|     (import \"ethereum\" \"codeCopy\" (func $eth.codeCopy (param i32 i32 i32))) | ||||
|     (import \"ethereum\" \"finish\" (func $eth.finish (param i32 i32))) | ||||
|     (memory $memory (export \"memory\") 1) | ||||
|     (export \"main\" (func $main)) | ||||
|     (global $global_ (mut i64) (i64.const 0)) | ||||
|     (global $global__1 (mut i64) (i64.const 0)) | ||||
|     (global $global__2 (mut i64) (i64.const 0)) | ||||
| 
 | ||||
| (func $main | ||||
|     (unreachable ) (unreachable ) (unreachable ) | ||||
|     (local $_1 i64) | ||||
|     (local $pos i64) | ||||
|     (local $hi i64) | ||||
|     (local $_2 i64) | ||||
|     (local $hi_1 i64) | ||||
|     (local $_3 i64) | ||||
|     (local $hi_2 i64) | ||||
|     (local $hi_3 i64) | ||||
|     (local $hi_4 i64) | ||||
|     (local $_4 i64) | ||||
|     (local $_5 i64) | ||||
|     (local $_6 i64) | ||||
|     (local $_7 i64) | ||||
|     (local $_8 i64) | ||||
|     (local $_9 i64) | ||||
|     (local $_10 i64) | ||||
|     (local $_11 i64) | ||||
|     (set_local $_1 (i64.const 0)) | ||||
|     (set_local $pos (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (i64.const 64))) | ||||
|     (set_local $hi (i64.shl (call $endian_swap_16 (get_local $_1)) (i64.const 16))) | ||||
|     (set_local $_2 (i64.shr_u (get_local $_1) (i64.const 16))) | ||||
|     (set_local $hi_1 (i64.shl (i64.or (get_local $hi) (call $endian_swap_16 (get_local $_2))) (i64.const 32))) | ||||
|     (set_local $_3 (i64.shr_u (get_local $_1) (i64.const 32))) | ||||
|     (i64.store (get_local $pos) (i64.or (get_local $hi_1) (call $endian_swap_32 (get_local $_3)))) (set_local $hi_2 (i64.shl (call $endian_swap_16 (get_local $_1)) (i64.const 16))) | ||||
|     (set_local $hi_3 (i64.shl (i64.or (get_local $hi_2) (call $endian_swap_16 (get_local $_2))) (i64.const 32))) | ||||
|     (i64.store (i64.add (get_local $pos) (i64.const 8)) (i64.or (get_local $hi_3) (call $endian_swap_32 (get_local $_3)))) (set_local $hi_4 (i64.shl (call $endian_swap_32 (get_local $_1)) (i64.const 32))) | ||||
|     (i64.store (i64.add (get_local $pos) (i64.const 16)) (i64.or (get_local $hi_4) (call $endian_swap_32 (get_local $_3)))) (i64.store (i64.add (get_local $pos) (i64.const 24)) (call $endian_swap (i64.const 64))) (block | ||||
|         (set_local $_4 (datasize \"C_2_deployed\")) | ||||
|         (set_local $_5 (get_global $global_)) | ||||
|         (set_local $_6 (get_global $global__1)) | ||||
|         (set_local $_7 (get_global $global__2)) | ||||
|      | ||||
|     ) | ||||
|     (block | ||||
|         (set_local $_8 (dataoffset \"C_2_deployed\")) | ||||
|         (set_local $_9 (get_global $global_)) | ||||
|         (set_local $_10 (get_global $global__1)) | ||||
|         (set_local $_11 (get_global $global__2)) | ||||
|      | ||||
|     ) | ||||
|     (call $eth.codeCopy (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (get_local $_1)) (call $u256_to_i32 (get_local $_8) (get_local $_9) (get_local $_10) (get_local $_11)) (call $u256_to_i32 (get_local $_4) (get_local $_5) (get_local $_6) (get_local $_7))) (call $eth.finish (call $u256_to_i32 (get_local $_1) (get_local $_1) (get_local $_1) (get_local $_1)) (call $u256_to_i32 (get_local $_4) (get_local $_5) (get_local $_6) (get_local $_7))) | ||||
| ) | ||||
| 
 | ||||
| (func $u256_to_i32 | ||||
|     (param $x1 i64) | ||||
|     (param $x2 i64) | ||||
|     (param $x3 i64) | ||||
|     (param $x4 i64) | ||||
|     (result i64) | ||||
|     (local $v i64) | ||||
|     (if (i64.ne (i64.const 0) (i64.or (i64.or (get_local $x1) (get_local $x2)) (get_local $x3))) (then | ||||
|         (unreachable ))) | ||||
|     (if (i64.ne (i64.const 0) (i64.shr_u (get_local $x4) (i64.const 32))) (then | ||||
|         (unreachable ))) | ||||
|     (set_local $v (get_local $x4)) | ||||
|     (get_local $v) | ||||
| ) | ||||
| 
 | ||||
| (func $endian_swap_16 | ||||
|     (param $x i64) | ||||
|     (result i64) | ||||
|     (local $y i64) | ||||
|     (set_local $y (i64.or (i64.and (i64.shl (get_local $x) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (get_local $x) (i64.const 8)) (i64.const 255)))) | ||||
|     (get_local $y) | ||||
| ) | ||||
| 
 | ||||
| (func $endian_swap_32 | ||||
|     (param $x i64) | ||||
|     (result i64) | ||||
|     (local $y i64) | ||||
|     (local $hi i64) | ||||
|     (set_local $hi (i64.shl (call $endian_swap_16 (get_local $x)) (i64.const 16))) | ||||
|     (set_local $y (i64.or (get_local $hi) (call $endian_swap_16 (i64.shr_u (get_local $x) (i64.const 16))))) | ||||
|     (get_local $y) | ||||
| ) | ||||
| 
 | ||||
| (func $endian_swap | ||||
|     (param $x i64) | ||||
|     (result i64) | ||||
|     (local $y i64) | ||||
|     (local $hi i64) | ||||
|     (set_local $hi (i64.shl (call $endian_swap_32 (get_local $x)) (i64.const 32))) | ||||
|     (set_local $y (i64.or (get_local $hi) (call $endian_swap_32 (i64.shr_u (get_local $x) (i64.const 32))))) | ||||
|     (get_local $y) | ||||
| ) | ||||
| 
 | ||||
| ) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user