基于虚拟机源码分析move合约(四):布尔值和比较大小

11 篇文章 1 订阅
7 篇文章 0 订阅

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:函数结束,返回

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值