Move合约:
module test_05::test_move{
public fun test_bool(){
let a = true;
let b = false;
let c = a && b;
let d = a || b;
let k = !a;
let m = 10;
let n = 20;
let result = m==n;
result = m!=n;
result = m>n;
result = m>=n;
result = m <n;
result = m<=n;
}
}
这个合约演示了布尔变量的3种运算和整数的比较大小
我们通过下面的命令执行反编译:
move disassemble --name test_move
我们通过反编译可以得到如下指令:
// Move bytecode v5
module f2.test_move {
public test_bool() {
L0: a: bool
L1: b: bool
L2: c: bool
L3: d: bool
L4: k: bool
L5: m: u64
L6: n: u64
L7: result: bool
B0:
0: LdTrue
1: StLoc[0](a: bool)
2: LdFalse
3: StLoc[1](b: bool)
4: CopyLoc[0](a: bool)
5: CopyLoc[1](b: bool)
6: And
7: Pop
8: CopyLoc[0](a: bool)
9: MoveLoc[1](b: bool)
10: Or
11: Pop
12: MoveLoc[0](a: bool)
13: Not
14: Pop
15: LdU64(10)
16: StLoc[5](m: u64)
17: LdU64(20)
18: StLoc[6](n: u64)
19: CopyLoc[5](m: u64)
20: CopyLoc[6](n: u64)
21: Eq
22: Pop
23: CopyLoc[5](m: u64)
24: CopyLoc[6](n: u64)
25: Neq
26: Pop
27: CopyLoc[5](m: u64)
28: CopyLoc[6](n: u64)
29: Gt
30: Pop
31: CopyLoc[5](m: u64)
32: CopyLoc[6](n: u64)
33: Ge
34: Pop
35: CopyLoc[5](m: u64)
36: CopyLoc[6](n: u64)
37: Lt
38: Pop
39: MoveLoc[5](m: u64)
40: MoveLoc[6](n: u64)
41: Le
42: Pop
43: Ret
}
}
LdTrue
这个指令用来加载布尔值true到栈上:
Bytecode::LdTrue => {
gas_meter.charge_simple_instr(S::LdTrue)?;
interpreter.operand_stack.push(Value::bool(true))?;
}
StLoc[0](a: bool):将上面的true从栈上取出来,存入寄存器0
LdFalse
这个指令用来加载布尔值false到栈上:
Bytecode::LdFalse => {
gas_meter.charge_simple_instr(S::LdFalse)?;
interpreter.operand_stack.push(Value::bool(false))?;
}
StLoc[1](b: bool):将上面的false从栈上取出来,存入寄存器1
CopyLoc[0](a: bool):从寄存器0复制一份数据到栈上
CopyLoc[1](b: bool):从寄存器1复制一份数据到栈上
And
这个指令用来进行布尔值的与操作,代码如下:
Bytecode::And => {
gas_meter.charge_simple_instr(S::And)?;
interpreter.binop_bool(|l, r| Ok(l && r))?
}
调用的是binop_bool这个函数,传入的是个function:
fn binop_bool<F, T>(&mut self, f: F) -> PartialVMResult<()>
where
Value: VMValueCast<T>,
F: FnOnce(T, T) -> PartialVMResult<bool>,
{
self.binop(|lhs, rhs| Ok(Value::bool(f(lhs, rhs)?)))
}
fn binop<F, T>(&mut self, f: F) -> PartialVMResult<()>
where
Value: VMValueCast<T>,
F: FnOnce(T, T) -> PartialVMResult<Value>,
{
let rhs = self.operand_stack.pop_as::<T>()?;
let lhs = self.operand_stack.pop_as::<T>()?;
let result = f(lhs, rhs)?;
self.operand_stack.push(result)
}
可以看到,它首先会从栈上弹出两个值,这里分别是上面存入的true和false,然后就是执行l && r的表达式,最后把结果存入栈上。
Pop:由于这个结果没有被后续用到,因此生命周期已经结束,这里直接pop掉
CopyLoc[0](a: bool):从寄存器0复制一份数据到栈上,变量a后续还会用到,因此使用了copy操作
MoveLoc[1](b: bool):从寄存器1删除一份数据,并把这个数据存入到栈上,由于变量b在后续都不再被用到,因此这里用了move操作而不是copy操作
Or
这个指令用来进行布尔值的或操作,代码如下:
Bytecode::Or => {
gas_meter.charge_simple_instr(S::Or)?;
interpreter.binop_bool(|l, r| Ok(l || r))?
}
原理和与操作类似,不再赘述。
Pop:由于这个结果没有被后续用到,因此生命周期已经结束,这里直接pop掉
MoveLoc[0](a: bool):从寄存器0删除一份数据,并把这个数据存入到栈上,由于变量a在后续都不再被用到,因此这里用了move操作而不是copy操作
Not
这个指令用来进行布尔值的非操作,代码如下:
Bytecode::Not => {
gas_meter.charge_simple_instr(S::Not)?;
let value = !interpreter.operand_stack.pop_as::<bool>()?;
interpreter.operand_stack.push(Value::bool(value))?;
}
我们可以看到它会从栈上取一个值,然后执行逻辑非操作后,存入栈上。
Pop:由于这个结果没有被后续用到,因此生命周期已经结束,这里直接pop掉
LdU64(10):加载数据10到栈上
StLoc[5](m: u64):将栈上的数据10取出,然后存入寄存器5
LdU64(20):加载数据20到栈上
StLoc[6](n: u64):将栈上的数据20取出,然后存入寄存器6
CopyLoc[5](m: u64):复制寄存器5的值,然后存入栈
CopyLoc[6](n: u64):复制寄存器6的值,然后存入栈
Eq
这个操作是整数进行相等比较的操作,代码如下:
Bytecode::Eq => {
let lhs = interpreter.operand_stack.pop()?;
let rhs = interpreter.operand_stack.pop()?;
gas_meter.charge_eq(&lhs, &rhs)?;
interpreter.operand_stack
.push(Value::bool(lhs.equals(&rhs)?))?;
}
可以看到它先从栈上pop两个值,然后直接调用equals方法进行比较,最后将结果存入栈。
Pop:由于比较结果后续不会再被用到,因此生命周期已经结果,这里直接pop掉
CopyLoc[5](m: u64):复制寄存器5的值,然后存入栈
CopyLoc[6](n: u64):复制寄存器6的值,然后存入栈
Neq
这个操作是整数进行不比较的操作,代码如下:
Bytecode::Neq => {
let lhs = interpreter.operand_stack.pop()?;
let rhs = interpreter.operand_stack.pop()?;
gas_meter.charge_neq(&lhs, &rhs)?;
interpreter.operand_stack
.push(Value::bool(!lhs.equals(&rhs)?))?;
}
这个和相等比较的操作类似,不再赘述
Pop:由于比较结果后续不会再被用到,因此生命周期已经结果,这里直接pop掉
CopyLoc[5](m: u64):复制寄存器5的值,然后存入栈
CopyLoc[6](n: u64):复制寄存器6的值,然后存入栈
Gt
这个操作是整数进行大于比较的操作,代码如下:
Bytecode::Gt => {
gas_meter.charge_simple_instr(S::Gt)?;
interpreter.binop_bool(IntegerValue::gt)?
}
pub fn gt(self, other: Self) -> PartialVMResult<bool> {
use IntegerValue::*;
Ok(match (self, other) {
(U8(l), U8(r)) => l > r,
(U64(l), U64(r)) => l > r,
(U128(l), U128(r)) => l > r,
(l, r) => {
let msg = format!(
"Cannot compare {:?} and {:?}: incompatible integer types",
l, r
);
return Err(PartialVMError::new(StatusCode::INTERNAL_TYPE_ERROR).with_message(msg));
}
})
}
分别对不同类型的整数进行比较,如果类型不同就会报错。
最终比较结果会压入栈
Pop:由于比较结果后续不会再被用到,因此生命周期已经结果,这里直接pop掉
CopyLoc[5](m: u64):复制寄存器5的值,然后存入栈
CopyLoc[6](n: u64):复制寄存器6的值,然后存入栈
Ge
这个操作是整数进行大于等于比较的操作,代码如下:
Bytecode::Ge => {
gas_meter.charge_simple_instr(S::Ge)?;
interpreter.binop_bool(IntegerValue::ge)?
}
pub fn ge(self, other: Self) -> PartialVMResult<bool> {
use IntegerValue::*;
Ok(match (self, other) {
(U8(l), U8(r)) => l >= r,
(U64(l), U64(r)) => l >= r,
(U128(l), U128(r)) => l >= r,
(l, r) => {
let msg = format!(
"Cannot compare {:?} and {:?}: incompatible integer types",
l, r
);
return Err(PartialVMError::new(StatusCode::INTERNAL_TYPE_ERROR).with_message(msg));
}
})
}
可以看到和大于操作类似
Pop:由于比较结果后续不会再被用到,因此生命周期已经结果,这里直接pop掉
CopyLoc[5](m: u64):复制寄存器5的值,然后存入栈
CopyLoc[6](n: u64):复制寄存器6的值,然后存入栈
Lt
这个操作是整数进行小于比较的操作,代码如下:
Bytecode::Lt => {
gas_meter.charge_simple_instr(S::Lt)?;
interpreter.binop_bool(IntegerValue::lt)?
}
pub fn lt(self, other: Self) -> PartialVMResult<bool> {
use IntegerValue::*;
Ok(match (self, other) {
(U8(l), U8(r)) => l < r,
(U64(l), U64(r)) => l < r,
(U128(l), U128(r)) => l < r,
(l, r) => {
let msg = format!(
"Cannot compare {:?} and {:?}: incompatible integer types",
l, r
);
return Err(PartialVMError::new(StatusCode::INTERNAL_TYPE_ERROR).with_message(msg));
}
})
}
可以看到和大于操作类似
Pop:由于比较结果后续不会再被用到,因此生命周期已经结果,这里直接pop掉
MoveLoc[5](m: u64):删除并返回寄存器5的值,然后存入栈,这里由于m变量是最后一次使用,因此用move操作而不是copy操作
MoveLoc[6](n: u64):删除并返回寄存器6的值,然后存入栈,这里由于n变量是最后一次使用,因此用move操作而不是copy操作
Le
这个操作是整数进行小于等于比较的操作,代码如下:
Bytecode::Le => {
gas_meter.charge_simple_instr(S::Le)?;
interpreter.binop_bool(IntegerValue::le)?
}
pub fn le(self, other: Self) -> PartialVMResult<bool> {
use IntegerValue::*;
Ok(match (self, other) {
(U8(l), U8(r)) => l <= r,
(U64(l), U64(r)) => l <= r,
(U128(l), U128(r)) => l <= r,
(l, r) => {
let msg = format!(
"Cannot compare {:?} and {:?}: incompatible integer types",
l, r
);
return Err(PartialVMError::new(StatusCode::INTERNAL_TYPE_ERROR).with_message(msg));
}
})
}
和其他比较操作类似,不再赘述
Pop:由于比较结果后续不会再被用到,因此生命周期已经结果,这里直接pop掉
Ret:函数结束,返回