在符号表中,很重要的一项内容就是符号的名字。名字的管理,要解决的主要问题就是名字的变长问题。在javac中,所有的符号名字放到了一个公用字符池中,对于相同的名字只保存一个。

其中涉及到的主要类及关系如下图。

每个名字都是一个Name对象,所有的Name对象全部存储到了Name类的内部类Table中。这个table就是上面提到的公用字符池。

看一下Table的实现类SharedNameTable类中重要的属性,如下:

 /** The hash table for names.
     */
    private NameImpl[] hashes;

    /** The shared byte array holding all encountered names.
     */
    public byte[] bytes;

    /** The mask to be used for hashing
     */
    private int hashMask;

    /** The number of filled bytes in `names'.
     *
     *  `names'中的填充字节数
     */
    private int nc = 0;

这个bytes数组将存储所有的name。其中的某个name是通过起始位置的偏移index和name的长度length来划分的。看一下Name的实现类NameImpl就知道了,如下:

       /**
         * The next name occupying the same hash bucket.
         */
        NameImpl next;

        /** The index where the bytes of this name are stored in the global name buffer `byte'.
         */
        int index;

        /** The number of bytes in this name.
         */
        int length;

那么问题又来了,我如何存储一个新的NameImple以及查找NameImpl呢?看到SharedNameTable类中的hashes属性了吧。为了加快查找速度,通过计算Name的hash值将其映射到n个桶中,每个

桶中的名字构成一个单项列表,使用NameImpl中的属性next相连。

来看一看具体的代码实现就一目了然了。如下:

 @Override
    public Name fromChars(char[] cs, int start, int len) {

        int nc = this.nc; // The number of filled bytes in `names'.
        byte[] bytes = this.bytes; // The shared byte array holding all encountered names.
        // 对公用字符池进行扩容操作
        while (nc + len * 3 >= bytes.length) {
            // System.err.println("doubling name buffer of length " + names.length + " to fit " + len + " chars");//DEBUG
            byte[] newnames = new byte[bytes.length * 2];
            System.arraycopy(bytes, 0, newnames, 0, bytes.length);
            bytes = this.bytes = newnames;
        }
        // chars2utf(char[] src, int sindex, byte[] dst, int dindex, int len)
        int nbytes = Convert.chars2utf(cs, start, bytes, nc, len) - nc;
        int h = hashValue(bytes, nc, nbytes) & hashMask;
        NameImpl n = hashes[h];
        while (
        		n != null &&
        		(n.getByteLength() != nbytes || !equals(bytes, n.index, bytes, nc, nbytes))
        ){
            n = n.next;
        }
        // 没有查找到时,存储这个新的Name
        if (n == null) {
            n = new NameImpl(this);
            n.index = nc;
            n.length = nbytes;
            n.next = hashes[h];
            hashes[h] = n;
            this.nc = nc + nbytes;
            if (nbytes == 0) {
                this.nc++;
            }
        }

        return n; // 返回查找到的Name
    }

fromChars()方法兼有存储和查找的功能。主要的逻辑就是首先算出Name的hash值,然后去hashes中查找是否已经存储了这个Name属性,主要的判断就是:

n.getByteLength() != nbytes || !equals(bytes, n.index, bytes, nc, nbytes

如果存储了就直接返回,如果没有存储就新建一个NameImpl,并指定这个NameImpl的index和length属性。返回这个NameImpl。图示如下:

 

  

  

javac符号名字的管理的更多相关文章

  1. 第六章-Javac符号表

    需要参考: (1)Architecture of a Java Compiler (2)关于符号Symbol第一篇 (3)关于符号Symbol第二篇 (4)关于类型Type (5)关于作用域范围Sco ...

  2. Scanner类中的nextToken()方法解读

    下面看一下nextToken()方法的源码实现. 1.Java中的控制字符 case ' ': // (Spec 3.6) case '\t': // (Spec 3.6) case FF: // ( ...

  3. Javac源码解读-书目录

    1.Javac编译器 (1)Javac编译器介绍(主要介绍如何从java源代码到class的一个转换过程) (2)Javac的源码(说明其中哪个功能由哪个主要的类来完成) (3)Javac支持的命令及 ...

  4. ELF Format 笔记(十五)—— 符号哈希表

    ilocker:关注 Android 安全(新手) QQ: 2597294287 符号哈希表用于支援符号表的访问,能够提高符号搜索速度. 下表用于解释该哈希表的组织,但该格式并不属于 ELF 规范. ...

  5. 【Cocos2d-x 3.x】内存管理机制与源码分析

    侯捷先生说过这么一句话 :  源码之前,了无秘密. 要了解Cocos2d-x的内存管理机制,就得阅读源码. 接触Cocos2d-x时, Cocos2d-x的最新版本已经到了3.2的时代,在学习Coco ...

  6. OFM管理

    OMF:oracle management files 作用:不用指定文件的路径大小名字 OMF管理数据文件:db_create_file_dest 传统方式:SQL>create tables ...

  7. C++名字空间/C++命名空间

    0.序言 名字空间是C++提供的一种解决符号名字冲突的方法. 一个命令空间是一个作用域,在不同名字空间中命名相同的符号代表不同的实体. 通常,利用定义名字空间的办法,可以使模块划分更加方便,减少模块间 ...

  8. Django与supervisor 管理进程

    1.前言 在Django项目中,我们需要用到一些独立于Django框架外的脚本.这样一些脚本可能需要独立的持续运行,且具有很强的可维护性,这个时候supervisor就可以排上用场了. 基于pytho ...

  9. Python 进程管理工具 Supervisor 使用教程

    Supervisor 是基于 Python 的进程管理工具,只能运行在 Unix-Like 的系统上,也就是无法运行在 Windows 上.Supervisor 官方版目前只能运行在 Python 2 ...

随机推荐

  1. JVM GC 机制与性能优化

    目录(?)[+] 1 背景介绍 与C/C++相比,JAVA并不要求我们去人为编写代码进行内存回收和垃圾清理.JAVA提供了垃圾回收器(garbage collector)来自动检测对象的作用域),可自 ...

  2. struts中request传递中文乱码问题

    系统本来是好好地,这两天升级后,各种问题不断,总而言之,一句话,心惊胆战. 今天,搜索任何中文,都是有乱码,在action中转码就ok了.公司系统那么多action,都转码,要累死吧.配置的过滤器都不 ...

  3. CentOS 7更换yum源

    1. 首先备份 sudo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2. 使用阿里云的 ...

  4. Cockroachdb 三、副本设置

    三 副本配置 CockroachDB 副本配置可分为三个等级,集群级别>数据库级别>表级别 格式 YAML range_min_bytes: <size-in-bytes> / ...

  5. 为Visual Studio添加一个“编码的UI测试生成器”的快捷方式

    在添加CodedUI测试用例时,经常需要查看捕获控件的属性.按照常规的方式,只有在添加一个全新的CodedUI编码测试时才能查看捕获控件的属性,这样很不方便. 下面介绍在Visual Studio工具 ...

  6. Navicat 连接阿里云RDS

    背景: Navicat 是一个非常优秀与易用的数据库可视化管理软件,相信很多人都用过.这次服务器升级,数据库用了阿里云的RDS,阿里云自带的数据库管理面板功能有限,用不习惯.所以还是想着用 Navic ...

  7. 异步和等待(async和await)

    在.Net 4.5中,通过async和await两个关键字,引入了一种新的基于任务的异步编程模型(TAP).在这种方式下,可以通过类似同步方式编写异步代码,极大简化了异步编程模型.如下式一个简单的实例 ...

  8. GO学习笔记 - 没有条件的 switch 同 switch true 一样。

    官方教程:https://tour.go-zh.org/flowcontrol/11 没有条件的 switch 同 switch true 一样. 这一构造使得可以用更清晰的形式来编写长的 if-th ...

  9. java—在dbutils中处理事务与不确定条件的查询(46)

    在dbutils中处理事务        事务是指用户的一次操作.这一次操作有可能是一个表,也有可能是多个表,也有可能是对一个表的多次操作. 只要是: 1:对数据数据库进行多次操作. 2:多个表,还是 ...

  10. python 去除字符串的首末两端的空白字符

    my_str = " adsffff adsfsad " my_str.strip() 使用strip()默认将 str 两端的空白字符去除掉 同时还有rstrip() 和 lst ...