举个例子,如下:
public class C {
public int a = 2;
public void test(int b) {
int c = 3;
for (int d = 3; a < 6; a++) {
}
}
}
形成的Scope作用域如下图:
属性table中存储的具体数据如下截图:
关于Scope的定义如下:
/** A scope represents an area of visibility in a Java program. The
* Scope class is a container for symbols which provides
* efficient access to symbols given their names.
*
* Scopes are implemented as hash tables with "open addressing" and "double hashing".
* Scopes can be nested; the next field of a scope points
* to its next outer scope. Nested scopes can share their hash tables.
*
*/
public class Scope {
/** The number of scopes that share this scope's hash table.
*/
private int shared;
/** Next enclosing scope (with whom this scope may share a hashtable)
*
* 参考博文:https://www.cnblogs.com/extjs4/p/6386572.html
*/
public Scope next;
/** The scope's ownerSymbol.
*/
public Symbol ownerSymbol;
/** A hash table for the scope's entries.
*/
Entry[] table;
/** Mask for hash codes, always equal to (table.length - 1).
*/
int hashMask;
/** A linear list that also contains all entries in
* reverse order of appearance (i.e later entries are pushed on top).
*/
public Entry elems;
/** The number of elements in this scope.
* This includes deleted elements, whose value is the sentinel.
*/
int nelems = 0;
// ...
}
Scope是符号的容器,通过Scope来查找及决定符号的访问。创建Scope对象有三种途径:
(1)调用构造函数创建
/** The hash table's initial size.
*/
private static final int INITIAL_SIZE = 0x10;
/** A value for the empty scope.
*/
public static final Scope emptyScope = new Scope(null, null, new Entry[]{});
/** Construct a new scope, within scope next, with given owner, using
* given table. The table's length must be an exponent of 2.
*/
protected Scope(Scope next, Symbol owner, Entry[] table) {
this.next = next;
Assert.check(emptyScope == null || owner != null);
this.ownerSymbol = owner;
this.table = table;
this.hashMask = table.length - 1;
}
/** Construct a new scope, within scope next, with given owner,
* using a fresh table of length INITIAL_SIZE.
*/
public Scope(Symbol owner) {
this(null, owner, new Entry[INITIAL_SIZE]);
}
第一个为基本的构造函数,一般不对外开放调用,由于是protected权限,所以一般是子类通过super()方法来调用,而通过调用下面的构造函数来得到一个全新的Scope对象。
(2)调用dup()方法
/** Convenience constructor used for dup and dupUnshared. */
private Scope(Scope next, Symbol owner, Entry[] table, int nelems) {
this(next, owner, table);
this.nelems = nelems;
}
/** Construct a fresh scope within this scope, with same ownerSymbol,
* which shares its table with the outer scope. Used in connection with
* method leave if scope access is stack-like in order to avoid allocation
* of fresh tables.
*/
public Scope dup() {
return dup(this.ownerSymbol);
}
/** Construct a fresh scope within this scope, with new ownerSymbol,
* which shares its table with the outer scope. Used in connection with
* method leave if scope access is stack-like in order to avoid allocation
* of fresh tables.
* 如果范围访问是堆栈式的,则使用方法离开,以避免重新分配新表。
*/
public Scope dup(Symbol newOwner) {
Scope result = new Scope(this, newOwner, this.table, this.nelems);
shared++;
// System.out.println("====> duping scope " + this.hashCode() + " owned by " + newOwner + " to " + result.hashCode());
// new Error().printStackTrace(System.out);
return result;
}
共有几处调用这个dup()方法,如下截图:
(3)调用dupUnshared()方法
/** Construct a fresh scope within this scope, with same ownerSymbol,
* with a new hash table, whose contents initially are those of
* the table of its outer scope.
*/
public Scope dupUnshared() {
return new Scope(this, this.ownerSymbol, this.table.clone(), this.nelems);
}
与dup()方法比起来,克隆了this.table的值,举个例子如下:
public class Test1 {
static class Entry{
int a = 0;
int[] arr = null;
public Entry(int a,int[] arr){
this.a = a;
this.arr = arr;
}
@Override
public String toString() {
return "Entry [a=" + a + ", arr=" + Arrays.toString(arr) + "]";
}
}
public static void main(String[] args) {
Entry[] ens = new Entry[2];
ens[0] = new Entry(2,new int[]{2,3});
Entry[] ensC = ens.clone();
ensC[0].arr[0] = 33;
ensC[1] = new Entry(3,new int[]{2,3});
System.out.println(Arrays.toString(ens));
System.out.println(Arrays.toString(ensC));
}
}
运行结果如下:
result:
[Entry [a=2, arr=[33, 3]], null]
[Entry [a=2, arr=[33, 3]], Entry [a=3, arr=[2, 3]]]
可以看到,调用了clone()方法后,往table中加入新的Entry,不会影响到原来table中的值。这就是所说的不共享。
GJC中调用dupUnshared()方法的地方如下图所示。
其中有些重要的属性如下:
1、属性next
/** Next enclosing scope (with whom this scope may share a hashtable)
*
*/
public Scope next;
从上面的例子可以清楚的看到next指向上一层作用域范围。作用域是通过块形成的,例如:
2、属性owner
/** The scope's owner.
*/
public Symbol owner;
表示的是这个作用域所属的符号。
3、属性table
/** A hash table for the scope's entries.
*/
Entry[] table;
这个属性比较重要,主要存储了这个Scope作用域内的符号,并且通过"open addressing"和"double hashing"来计算具体的某个Entry存储的位置。看一下Entry中除了存储符号Symbol还存储了哪些信息,定义如下:
/** A class for scope entries.
*
* shadowed指针指向桶中的下一个表项,shadowed意为隐蔽之义,sibling指针指向下一个填入哈希表中的表项,和符号的范围scope
*/
public class Entry {
/** The referenced symbol. 被引用的符号
* sym == null iff(if and only if 当且仅当) this == sentinel
*/
public Symbol sym;
/** An entry with the same hash code, or sentinel.
*/
public Entry shadowed;
/** Next entry in same scope.
*/
public Entry sibling;
/** The entry's scope.
* scope == null iff this == sentinel
* for an entry in an import scope, this is the scope where the entry came from (i.e. was imported from).
*/
public Scope scope;
...
}
由于table属性可以共享,也就是被enclosing封闭的作用域可以和外层的作用域共享table,从上面举的例子中就可以看出。如果要共享,那么还需要保证被封闭的作用域的符号不能
被外层作用域取到,所以必须在Entry中指定这个Symbol到底是属于哪个作用域Scope的。通过如下截图就可以清楚的看到各个Symbol是在哪个作用域内定义的。
sibling属性将Entry连接为单向链表,如同一个作用域内定义了3个Symbol,有3个Entry,按倒序链接起来,也就是后加入的在前面。先加入的在后面。
public class C {
public int a = 2;
public void test(int b) {
int c = 3;
int d = 4;
}
}
在方法内定义了两个变量c和d,通过如下截图可以清楚看到d的sibling指向c,因为c先定义的。
shadowed属性,举个例子,如下:
public class C {
public int a = 2;
public void test() {
int a = 2;
class a {}
}
}
截图如下:
可以看到,对于类名为a和变量名为a的符号存储到了同一个hash桶中,通过shadowed形成了链。
再看个例子,如下:
public class C {
public int a = 2;
class a {
}
public void a() {
}
}
截图如下: