当前位置 : 主页 > 编程语言 > ruby >

Ruby如何区分VALUE与值和指针?

来源:互联网 收集:自由互联 发布时间:2021-06-23
对于诸如true,nil或small整数的值, Ruby会进行优化.它不是使用VALUE指针作为指针,而是直接使用VALUE来存储数据. 我想知道Ruby如何在这些用途之间产生影响: def foo(x) ... 与x将关联到VALUE.从低
对于诸如true,nil或small整数的值, Ruby会进行优化.它不是使用VALUE指针作为指针,而是直接使用VALUE来存储数据.

我想知道Ruby如何在这些用途之间产生影响:

def foo(x)
  ...

与x将关联到VALUE.从低级别来看,它们只是一个数字.如何判断某个数字是否是指向对象的指针?所有我想到的是限制指针将MSB设置为0,并将MSB的直接值设置为1.但这只是我的猜测.它是如何在Ruby中完成的?

Ruby有许多不同的实现. Ruby语言规范没有规定对象的任何特定内部表示 – 为什么要这样做?毕竟,这是一个内部表征!

例如,JRuby根本不将对象表示为C指针,它将它们表示为Java对象. IronRuby将它们表示为.NET对象. Opal将它们表示为ECMAScript对象. MagLev将它们表示为Smalltalk对象.

但是,确实有一些实现使用您描述的策略.现在放弃的核磁共振成像就是这样做的,YARV和Rubinius也这样做了.

这实际上是一个非常古老的技巧,至少可以追溯到20世纪60年代.它被称为标记指针表示,并且如名称所示,您需要使用一些额外的元数据标记指针,以便知道它实际上是指向对象的指针还是某些其他数据类型的编码.

某些CPU具有专门用于此目的的特殊标记位. (例如,在AS / 400上,CPU甚至没有指针,它有128位对象引用,即使原始CPU仅为48位宽,而较新的基于POWER的CPU为64位;使用额外位编码所有类型的元数据,如类型,所有者,访问限制等.)某些CPU具有用于其他目的的标记位,可以为此目的“滥用”.但是,大多数现代主流CPU都没有标签位.

但是,你可以使用一招!在许多现代CPU上,未对齐的内存访问(访问不在字边界处开始的地址)实际上很慢(在某些情况下,甚至根本不可能),这意味着在32位CPU上,所有指针都是实际使用,以两个00位结束,在64位CPU上以三千位结束.您可以将这些位用作标记位:以00结尾的指针确实是指针,以01,10或11结尾的指针是某些其他数据类型的编码.

在MRI中,以1结尾的指针用于编码31/63位Fixnums.在YARV中,它们用于编码31/63位Fixnum,即根据公式2n 1(算术地说)或(n <1)|编码为实际机器整数的整数. 1(作为位模式).在64位平台上,YARV还使用以10结尾的指针来使用类似的方案编码62位flonums. (如果你想知道为什么YARV中Fixnum的object_id是2n 1,现在你知道:YARV使用内存地址作为对象ID,2n 1是n的“内存地址”.) 现在,那是什么,虚假和真实?那么,在我们目前的计划中,它们没有空间.但是,通常为操作系统内核保留非常低的内存地址,这意味着在程序中不能实际出现像0或2或4这样的指针. YARV使用该空间来编码nil,false和true:false编码为0(这很方便,因为它也是C中的false编码),nil编码为0b1000,true编码为0b10100(以前为0,引入flonums之前的旧版本中的0b10和0b100). 从理论上讲,还有很多空间来编码其他对象,但YARV并没有这样做.例如,一些Smalltalk或Lisp VM在那里编码ASCII或BMP Unicode字符对象,或者一些常用的对象,如空列表,空数组或空字符串. 但是仍然有一些部分缺失:没有对象头,只有裸位模式,VM如何访问类,方法,实例变量等?好吧,它不能.这些必须是特殊的,并且硬编码到VM中. VM只需知道以1结尾的指针是编码的Fixnum,并且必须知道该类是Fixnum并且可以在那里找到方法.至于变量?好吧,你可以将它们与侧面字典中的对象分开存储.或者你走Ruby路线并完全不允许它们.

网友评论