forked from mozilla/rhino
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSuperBlock.java
More file actions
163 lines (146 loc) · 4.62 KB
/
SuperBlock.java
File metadata and controls
163 lines (146 loc) · 4.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.classfile;
/**
* A super block is defined as a contiguous chunk of code with a single entry
* point and multiple exit points (therefore ending in an unconditional jump
* or the end of the method). This is used to emulate OpenJDK's compiler, which
* outputs stack map frames at the start of every super block except the method
* start.
*/
final class SuperBlock {
SuperBlock(int index, int start, int end, int[] initialLocals) {
this.index = index;
this.start = start;
this.end = end;
locals = new int[initialLocals.length];
System.arraycopy(initialLocals, 0, locals, 0, initialLocals.length);
stack = new int[0];
isInitialized = false;
isInQueue = false;
}
int getIndex() {
return index;
}
int[] getLocals() {
int[] copy = new int[locals.length];
System.arraycopy(locals, 0, copy, 0, locals.length);
return copy;
}
/**
* Get a copy of the super block's locals without any trailing TOP types.
*
* This is useful for actual writing stack maps; during the computation of
* stack map types, all local arrays have the same size; the max locals for
* the method. In addition, DOUBLE and LONG types have trailing TOP types
* because they occupy two words. For writing purposes, these are not
* useful.
*/
int[] getTrimmedLocals() {
int last = locals.length - 1;
// Exclude all of the trailing TOPs not bound to a DOUBLE/LONG
while (last >= 0 && locals[last] == TypeInfo.TOP &&
!TypeInfo.isTwoWords(locals[last - 1])) {
last--;
}
last++;
// Exclude trailing TOPs following a DOUBLE/LONG
int size = last;
for (int i = 0; i < last; i++) {
if (TypeInfo.isTwoWords(locals[i])) {
size--;
}
}
int[] copy = new int[size];
for (int i = 0, j = 0; i < size; i++, j++) {
copy[i] = locals[j];
if (TypeInfo.isTwoWords(locals[j])) {
j++;
}
}
return copy;
}
int[] getStack() {
int[] copy = new int[stack.length];
System.arraycopy(stack, 0, copy, 0, stack.length);
return copy;
}
boolean merge(int[] locals, int localsTop, int[] stack, int stackTop,
ConstantPool pool) {
if (!isInitialized) {
System.arraycopy(locals, 0, this.locals, 0, localsTop);
this.stack = new int[stackTop];
System.arraycopy(stack, 0, this.stack, 0, stackTop);
isInitialized = true;
return true;
} else if (this.locals.length == localsTop &&
this.stack.length == stackTop) {
boolean localsChanged = mergeState(this.locals, locals, localsTop,
pool);
boolean stackChanged = mergeState(this.stack, stack, stackTop,
pool);
return localsChanged || stackChanged;
} else {
if (ClassFileWriter.StackMapTable.DEBUGSTACKMAP) {
System.out.println("bad merge");
System.out.println("current type state:");
TypeInfo.print(this.locals, this.stack, pool);
System.out.println("incoming type state:");
TypeInfo.print(locals, localsTop, stack, stackTop, pool);
}
throw new IllegalArgumentException("bad merge attempt");
}
}
/**
* Merge an operand stack or local variable array with incoming state.
*
* They are treated the same way; by this point, it should already be
* ensured that the array sizes are the same, which is the only additional
* constraint that is imposed on merging operand stacks (the local variable
* array is always the same size).
*/
private static boolean mergeState(int[] current, int[] incoming, int size,
ConstantPool pool) {
boolean changed = false;
for (int i = 0; i < size; i++) {
int currentType = current[i];
current[i] = TypeInfo.merge(current[i], incoming[i], pool);
if (currentType != current[i]) {
changed = true;
}
}
return changed;
}
int getStart() {
return start;
}
int getEnd() {
return end;
}
@Override
public String toString() {
return "sb " + index;
}
boolean isInitialized() {
return isInitialized;
}
void setInitialized(boolean b) {
isInitialized = b;
}
boolean isInQueue() {
return isInQueue;
}
void setInQueue(boolean b) {
isInQueue = b;
}
private int index;
private int start;
private int end;
private int[] locals;
private int[] stack;
private boolean isInitialized;
private boolean isInQueue;
}