热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

基于虚拟机源码分析move合约(六):整数、布尔值的引用

合约:publicfuntest_reference(){leta1;letref_a&a;letb*ref_a1;letmut_ref_b&mutb;*mut_re

合约:

public fun test_reference(){let a = 1;let ref_a = &a;let b = *ref_a +1;let mut_ref_b = &mut b;*mut_ref_b = 3;let owner = false;let _ref_owner = &owner;let _mut_ref_owner = &mut owner;}

这个合约演示了针对整数、布尔值的引用操作。引用分为两种:

& : 表示不可修改的引用

&mut :表示可以进行修改的引用

* :解引用

我们通过下面的命令执行反编译:

move disassemble --name test_move

我们可以得到如下指令:

// Move bytecode v5
module f2.test_move {public test_reference() {
L0: _mut_ref_owner: &mut bool
L1: _mut_ref_v: &mut vector
L2: _ref_owner: &bool
L3: _ref_v: &vector
L4: a: u64
L5: b: u64
L6: mut_ref_b: &mut u64
L7: owner: bool
L8: ref_a: &u64
L9: v: vector
B0:0: LdU64(1)1: StLoc[4](a: u64)2: ImmBorrowLoc[4](a: u64)3: StLoc[8](ref_a: &u64)4: MoveLoc[8](ref_a: &u64)5: ReadRef6: LdU64(1)7: Add8: StLoc[5](b: u64)9: MutBorrowLoc[5](b: u64)10: StLoc[6](mut_ref_b: &mut u64)11: LdU64(3)12: MoveLoc[6](mut_ref_b: &mut u64)13: WriteRef14: LdFalse15: StLoc[7](owner: bool)16: ImmBorrowLoc[7](owner: bool)17: Pop18: MutBorrowLoc[7](owner: bool)19: Pop20: Ret
}
}

LdU64(1):加载整数1到栈上

StLoc[4](a: u64):将整数1从栈上取出,存入寄存器4

ImmBorrowLoc[4](a: u64)

这个指令用来对整数进行引用,具体代码如下:

Bytecode::MutBorrowLoc(idx) | Bytecode::ImmBorrowLoc(idx) => {let instr = match instruction {Bytecode::MutBorrowLoc(_) => S::MutBorrowLoc,_ => S::ImmBorrowLoc,};gas_meter.charge_simple_instr(instr)?;interpreter.operand_stack.push(self.locals.borrow_loc(*idx as usize)?)?;
}

可以看到两种引用都会走locals.borrow_loc:

impl Locals {pub fn borrow_loc(&self, idx: usize) -> PartialVMResult {// TODO: this is very similar to SharedContainer::borrow_elem. Find a way to// reuse that code?let v = self.0.borrow();if idx >= v.len() {return Err(PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR).with_message(format!("index out of bounds when borrowing local: got: {}, len: {}",idx,v.len()),),);}match &v[idx] {ValueImpl::Container(c) => Ok(Value(ValueImpl::ContainerRef(ContainerRef::Local(c.copy_by_ref(),)))),ValueImpl::U8(_)| ValueImpl::U64(_)| ValueImpl::U128(_)| ValueImpl::Bool(_)| ValueImpl::Address(_) => Ok(Value(ValueImpl::IndexedRef(IndexedRef {container_ref: ContainerRef::Local(Container::Locals(Rc::clone(&self.0))),idx,}))),ValueImpl::ContainerRef(_) | ValueImpl::Invalid | ValueImpl::IndexedRef(_) => Err(PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR).with_message(format!("cannot borrow local {:?}", &v[idx])),),}}
}

针对U64类型,走的是下面的分支:

ValueImpl::U8(_)| ValueImpl::U64(_)| ValueImpl::U128(_)| ValueImpl::Bool(_)| ValueImpl::Address(_) => Ok(Value(ValueImpl::IndexedRef(IndexedRef {container_ref: ContainerRef::Local(Container::Locals(Rc::clone(&self.0))),idx,}))),

可以看到最内层是&self.0,这是rust对整数类型的引用,然后使用Rc::clone返回一个Rc引用,然后生成一个Container::Locals:

enum Container {Locals(Rc>>),Vec(Rc>>),Struct(Rc>>),VecU8(Rc>>),VecU64(Rc>>),VecU128(Rc>>),VecBool(Rc>>),VecAddress(Rc>>),
}

可以看到这是Container中的一种,其实就是基本类型Container,然后生成一个ContainerRef::Local:

enum ContainerRef {Local(Container),Global {status: Rc>,container: Container,},
}

这是对Container生成的引用,分为Local和Global,其中Local是本地变量,Gloabl是链上的变量。

最后生成IndexedRef:

enum ValueImpl {Invalid,U8(u8),U64(u64),U128(u128),Bool(bool),Address(AccountAddress),Container(Container),ContainerRef(ContainerRef),IndexedRef(IndexedRef),
}struct IndexedRef {idx: usize,container_ref: ContainerRef,
}

这个IndexedRef才是Move中的引用对应的数据结构。

最终,这个IndexedRef会被压入栈上。

StLoc[8](ref_a: &u64):从栈上把上面生成的IndexedRef取出来,放入寄存器8

MoveLoc[8](ref_a: &u64):从寄存器8取出IndexedRef,也就是ref_a对应的数据结构,然后压入栈上

ReadRef

这个指令时用来读取引用所指向的值的,具体代码如下:

Bytecode::ReadRef => {let reference = interpreter.operand_stack.pop_as::()?;gas_meter.charge_read_ref(reference.value_view())?;let value = reference.read_ref()?;interpreter.operand_stack.push(value)?;
}

首先从栈上弹出一个引用,这里的Reference其实就是IndexedRef:

pub struct Reference(ReferenceImpl);enum ReferenceImpl {IndexedRef(IndexedRef),ContainerRef(ContainerRef),
}

然后调用read_ref读取实际的值:

impl Reference {pub fn read_ref(self) -> PartialVMResult {self.0.read_ref()}
}
impl ReferenceImpl {fn read_ref(self) -> PartialVMResult {match self {Self::ContainerRef(r) => r.read_ref(),Self::IndexedRef(r) => r.read_ref(),}}
}impl IndexedRef {fn read_ref(self) -> PartialVMResult {use Container::*;let res = match self.container_ref.container() {Locals(r) | Vec(r) | Struct(r) => r.borrow()[self.idx].copy_value()?,VecU8(r) => ValueImpl::U8(r.borrow()[self.idx]),VecU64(r) => ValueImpl::U64(r.borrow()[self.idx]),VecU128(r) => ValueImpl::U128(r.borrow()[self.idx]),VecBool(r) => ValueImpl::Bool(r.borrow()[self.idx]),VecAddress(r) => ValueImpl::Address(r.borrow()[self.idx]),};Ok(Value(res))}
}

我们知道,我们的变量是Container::Locals类型的,因此走的下面的分支:

Locals(r) | Vec(r) | Struct(r) => r.borrow()[self.idx].copy_value()?,

这里的r其实是Rc>>,因此最终走的是ValueImpl的copy_value:

impl ValueImpl {fn copy_value(&self) -> PartialVMResult {use ValueImpl::*;Ok(match self {Invalid => Invalid,U8(x) => U8(*x),U64(x) => U64(*x),U128(x) => U128(*x),Bool(x) => Bool(*x),Address(x) => Address(*x),ContainerRef(r) => ContainerRef(r.copy_value()),IndexedRef(r) => IndexedRef(r.copy_value()),// When cloning a container, we need to make sure we make a deep// copy of the data instead of a shallow copy of the Rc.Container(c) => Container(c.copy_value()?),})}
}

我们的是U64类型,因此直接使用*x进行解引用,拿到实际的值返回。

最终这个值会压入栈上。

LdU64(1):将数据1压入栈上

Add:栈上两个数据取出,进行加法运算,结果存入栈上

StLoc[5](b: u64):取出栈上的数据,存入寄存器5

MutBorrowLoc[5](b: u64):这个和上面的ImmBorrowLoc一样,最终会生成IndexedRef存入栈上

StLoc[6](mut_ref_b: &mut u64):从栈上取出引用,存入寄存器6

LdU64(3):将数据3压入栈上

MoveLoc[6](mut_ref_b: &mut u64):从寄存器6取出引用,压入栈上

WriteRef

这个指令时用来向引用所指向的数据进行写入操作,具体代码如下:

Bytecode::WriteRef => {let reference = interpreter.operand_stack.pop_as::()?;let value = interpreter.operand_stack.pop()?;gas_meter.charge_write_ref(&value)?;reference.write_ref(value)?;
}

首先从栈上取出引用,然后从栈上取出要写入的数据,最后调用write_ref写入数据:

impl Reference {pub fn write_ref(self, x: Value) -> PartialVMResult<()> {self.0.write_ref(x)}
}impl ReferenceImpl {fn write_ref(self, x: Value) -> PartialVMResult<()> {match self {Self::ContainerRef(r) => r.write_ref(x),Self::IndexedRef(r) => r.write_ref(x),}}
}impl IndexedRef {fn write_ref(self, x: Value) -> PartialVMResult<()> {match &x.0 {ValueImpl::IndexedRef(_)| ValueImpl::ContainerRef(_)| ValueImpl::Invalid| ValueImpl::Container(_) => {return Err(PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR).with_message(format!("cannot write value {:?} to indexed ref {:?}",x, self)),)}_ => (),}match (self.container_ref.container(), &x.0) {(Container::Locals(r), _) | (Container::Vec(r), _) | (Container::Struct(r), _) => {let mut v = r.borrow_mut();v[self.idx] = x.0;}(Container::VecU8(r), ValueImpl::U8(x)) => r.borrow_mut()[self.idx] = *x,(Container::VecU64(r), ValueImpl::U64(x)) => r.borrow_mut()[self.idx] = *x,(Container::VecU128(r), ValueImpl::U128(x)) => r.borrow_mut()[self.idx] = *x,(Container::VecBool(r), ValueImpl::Bool(x)) => r.borrow_mut()[self.idx] = *x,(Container::VecAddress(r), ValueImpl::Address(x)) => r.borrow_mut()[self.idx] = *x,(Container::VecU8(_), _)| (Container::VecU64(_), _)| (Container::VecU128(_), _)| (Container::VecBool(_), _)| (Container::VecAddress(_), _) => {return Err(PartialVMError::new(StatusCode::INTERNAL_TYPE_ERROR).with_message(format!("cannot write value {:?} to indexed ref {:?}",x, self)),)}}self.container_ref.mark_dirty();Ok(())}
}

实际走的是下面的分支:

(Container::Locals(r), _) | (Container::Vec(r), _) | (Container::Struct(r), _) => {let mut v = r.borrow_mut();v[self.idx] = x.0;}

这里的r其实是Rc>>,通过borrow_mut获得引用针对Vec的可写引用,然后直接覆盖对应位置的值。

LdFalse:加载布尔值false到栈上

StLoc[7](owner: bool):将布尔值从栈上取出,存入寄存器7

ImmBorrowLoc[7](owner: bool):由上面的分析可以知道,最终会生成一个IndexedRef存入栈上

Pop:由于这个引用没有用到,因此生命周期结束,直接pop掉

MutBorrowLoc[7](owner: bool):由上面的分析可以知道,最终会生成一个IndexedRef存入栈上

Pop:由于这个引用没有用到,因此生命周期结束,直接pop掉

Ret:函数结束,直接返回


推荐阅读
  • [转载]从零开始学习OpenGL ES之四 – 光效
    继续我们的iPhoneOpenGLES之旅,我们将讨论光效。目前,我们没有加入任何光效。幸运的是,OpenGL在没有设置光效的情况下仍然可 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 阿里Treebased Deep Match(TDM) 学习笔记及技术发展回顾
    本文介绍了阿里Treebased Deep Match(TDM)的学习笔记,同时回顾了工业界技术发展的几代演进。从基于统计的启发式规则方法到基于内积模型的向量检索方法,再到引入复杂深度学习模型的下一代匹配技术。文章详细解释了基于统计的启发式规则方法和基于内积模型的向量检索方法的原理和应用,并介绍了TDM的背景和优势。最后,文章提到了向量距离和基于向量聚类的索引结构对于加速匹配效率的作用。本文对于理解TDM的学习过程和了解匹配技术的发展具有重要意义。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • WhenIusepythontoapplythepymysqlmoduletoaddafieldtoatableinthemysqldatabase,itdo ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 本文介绍了在处理不规则数据时如何使用Python自动提取文本中的时间日期,包括使用dateutil.parser模块统一日期字符串格式和使用datefinder模块提取日期。同时,还介绍了一段使用正则表达式的代码,可以支持中文日期和一些特殊的时间识别,例如'2012年12月12日'、'3小时前'、'在2012/12/13哈哈'等。 ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • 本文介绍了Oracle存储过程的基本语法和写法示例,同时还介绍了已命名的系统异常的产生原因。 ... [详细]
  • 本文详细介绍了使用C#实现Word模版打印的方案。包括添加COM引用、新建Word操作类、开启Word进程、加载模版文件等步骤。通过该方案可以实现C#对Word文档的打印功能。 ... [详细]
  • node.jsurlsearchparamsAPI哎哎哎 ... [详细]
author-avatar
国国国国涛
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有