Lines 14-19
Link Here
|
14 |
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; |
14 |
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; |
15 |
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; |
15 |
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; |
16 |
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; |
16 |
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; |
|
|
17 |
import org.eclipse.jdt.internal.compiler.lookup.TagBits; |
18 |
|
17 |
|
19 |
|
18 |
/** |
20 |
/** |
19 |
* Record initialization status during definite assignment analysis |
21 |
* Record initialization status during definite assignment analysis |
Lines 22-828
Link Here
|
22 |
*/ |
24 |
*/ |
23 |
public class UnconditionalFlowInfo extends FlowInfo { |
25 |
public class UnconditionalFlowInfo extends FlowInfo { |
24 |
|
26 |
|
25 |
|
|
|
26 |
public long definiteInits; |
27 |
public long definiteInits; |
27 |
public long potentialInits; |
28 |
public long potentialInits; |
28 |
public long extraDefiniteInits[]; |
|
|
29 |
public long extraPotentialInits[]; |
30 |
|
29 |
|
31 |
public long definiteNulls; |
30 |
public long nullAssignmentStatusBit1; |
32 |
public long definiteNonNulls; |
31 |
public long nullAssignmentStatusBit2; |
33 |
public long extraDefiniteNulls[]; |
32 |
// 0 0 is potential (bit 1 is leftmost here) |
34 |
public long extraDefiniteNonNulls[]; |
33 |
// 1 0 is assigned |
35 |
|
34 |
// 0 1 is protected null (aka if (o == null) { // here o protected null...) |
36 |
public int reachMode; // by default |
35 |
// 1 1 is protected non null |
|
|
36 |
public long nullAssignmentValueBit1; |
37 |
public long nullAssignmentValueBit2; |
38 |
// information only relevant for potential and assigned |
39 |
// 0 0 is start -- nothing known at all |
40 |
// 0 1 is assigned non null or potential anything but null |
41 |
// 1 0 is assigned null or potential null |
42 |
// 1 1 is potential null and potential anything but null or definite unknown |
43 |
|
44 |
public static final int extraLength = 6; |
45 |
public long extra[][]; |
46 |
// extra bit fields for larger numbers of fields/variables |
47 |
// extra[0] holds definiteInits values, extra[1] potentialInits, etc. |
48 |
// lifecycle is extra == null or else all extra[]'s are allocated |
49 |
// arrays which have the same size |
37 |
|
50 |
|
38 |
public int maxFieldCount; |
51 |
public int maxFieldCount; // limit between fields and locals |
39 |
|
52 |
|
40 |
// Constants |
53 |
// Constants |
41 |
public static final int BitCacheSize = 64; // 64 bits in a long. |
54 |
public static final int BitCacheSize = 64; // 64 bits in a long. |
42 |
|
55 |
|
43 |
UnconditionalFlowInfo() { |
56 |
public FlowInfo addInitializationsFrom(FlowInfo inits) { |
44 |
this.reachMode = REACHABLE; |
57 |
if (this == DEAD_END) |
45 |
} |
58 |
return this; |
46 |
|
59 |
if (inits == DEAD_END) |
47 |
// unions of both sets of initialization - used for try/finally |
60 |
return this; |
48 |
public FlowInfo addInitializationsFrom(FlowInfo inits) { |
61 |
UnconditionalFlowInfo otherInits = inits.unconditionalInits(); |
49 |
|
62 |
|
50 |
if (this == DEAD_END) |
63 |
// union of definitely assigned variables, |
51 |
return this; |
64 |
this.definiteInits |= otherInits.definiteInits; |
52 |
|
65 |
// union of potentially set ones |
53 |
UnconditionalFlowInfo otherInits = inits.unconditionalInits(); |
66 |
this.potentialInits |= otherInits.potentialInits; |
54 |
if (otherInits == DEAD_END) |
67 |
// combine null information |
55 |
return this; |
68 |
// note: we may have both forms of protection (null and non null) |
56 |
|
69 |
// coming with otherInits, because of loops |
57 |
// union of definitely assigned variables, |
70 |
boolean considerNulls = (otherInits.tagBits & NULL_FLAG_MASK) != 0; |
58 |
definiteInits |= otherInits.definiteInits; |
71 |
long a1, na1, a2, na2, a3, a4, na4, b1, b2, nb2, b3, nb3, b4, nb4; |
59 |
// union of potentially set ones |
72 |
if (considerNulls) { |
60 |
potentialInits |= otherInits.potentialInits; |
73 |
if ((this.tagBits & NULL_FLAG_MASK) == 0) { |
61 |
|
74 |
this.nullAssignmentStatusBit1 = otherInits.nullAssignmentStatusBit1; |
62 |
// union of definitely null variables, |
75 |
this.nullAssignmentStatusBit2 = otherInits.nullAssignmentStatusBit2; |
63 |
definiteNulls = (definiteNulls | otherInits.definiteNulls) & ~otherInits.definiteNonNulls; |
76 |
this.nullAssignmentValueBit1 = otherInits.nullAssignmentValueBit1; |
64 |
// union of definitely non null variables, |
77 |
this.nullAssignmentValueBit2 = otherInits.nullAssignmentValueBit2; |
65 |
definiteNonNulls = (definiteNonNulls | otherInits.definiteNonNulls) & ~otherInits.definiteNulls; |
78 |
} |
66 |
// fix-up null/non-null infos since cannot overlap: <defN1:0,defNoN1:1> + <defN2:1,defNoN2:0> --> <defN:0,defNon:0> |
79 |
else { |
67 |
|
80 |
this.nullAssignmentStatusBit1 = |
68 |
// treating extra storage |
81 |
(b1 = otherInits.nullAssignmentStatusBit1) | |
69 |
if (extraDefiniteInits != null) { |
82 |
(a1 = this.nullAssignmentStatusBit1) & |
70 |
if (otherInits.extraDefiniteInits != null) { |
83 |
((nb2 = ~(b2 = otherInits.nullAssignmentStatusBit2)) & |
|
|
84 |
(nb3 = ~(b3 = otherInits.nullAssignmentValueBit1)) & |
85 |
((nb4 = ~(b4 = otherInits.nullAssignmentValueBit2)) | |
86 |
((a2 = this.nullAssignmentStatusBit2) ^ |
87 |
(a4 = this.nullAssignmentValueBit2))) | |
88 |
nb4 & (na2 = ~a2) & (na4 = ~a4)); |
89 |
this.nullAssignmentStatusBit2 = |
90 |
b1 & b2 | |
91 |
~b1 & (((na1 = ~a1) | a4) & b2 | |
92 |
a2 & (b2 | |
93 |
a1 & (na4 = ~a4) & nb2 & nb3 | |
94 |
(~(a3 = this.nullAssignmentValueBit1) & nb3 | na1 & na4) & nb4)); |
95 |
this.nullAssignmentValueBit1 = |
96 |
nb2 & b3 | |
97 |
~b1 & ((a1 & na2 & na4 | na1 & a3) & (nb2 | nb4) | |
98 |
a1 & na2 & a3 & nb2 | |
99 |
(a1 | a2 | na4) & b3); |
100 |
this.nullAssignmentValueBit2 = |
101 |
b4 | |
102 |
a4 & (nb2 & nb3 | ~(b1 ^ b2)); |
103 |
} |
104 |
this.tagBits |= NULL_FLAG_MASK; // in all cases - avoid forgetting extras |
105 |
} |
106 |
// treating extra storage |
107 |
if (this.extra != null || otherInits.extra != null) { |
108 |
int mergeLimit = 0, copyLimit = 0; |
109 |
if (this.extra != null) { |
110 |
if (otherInits.extra != null) { |
71 |
// both sides have extra storage |
111 |
// both sides have extra storage |
72 |
int i = 0, length, otherLength; |
112 |
int length, otherLength; |
73 |
if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) { |
113 |
if ((length = this.extra[0].length) < |
|
|
114 |
(otherLength = otherInits.extra[0].length)) { |
74 |
// current storage is shorter -> grow current (could maybe reuse otherInits extra storage?) |
115 |
// current storage is shorter -> grow current (could maybe reuse otherInits extra storage?) |
75 |
System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length); |
116 |
for (int j = 0; j < extraLength; j++) { |
76 |
System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length); |
117 |
System.arraycopy(this.extra[j], 0, |
77 |
System.arraycopy(extraDefiniteNulls, 0, (extraDefiniteNulls = new long[otherLength]), 0, length); |
118 |
(this.extra[j] = new long[otherLength]), 0, length); |
78 |
System.arraycopy(extraDefiniteNonNulls, 0, (extraDefiniteNonNulls = new long[otherLength]), 0, length); |
|
|
79 |
for (; i < length; i++) { |
80 |
extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i]; |
81 |
extraPotentialInits[i] |= otherInits.extraPotentialInits[i]; |
82 |
extraDefiniteNulls[i] = (extraDefiniteNulls[i] | otherInits.extraDefiniteNulls[i]) & ~otherInits.extraDefiniteNonNulls[i]; |
83 |
extraDefiniteNonNulls[i] = (extraDefiniteNonNulls[i] | otherInits.extraDefiniteNonNulls[i]) & ~otherInits.extraDefiniteNulls[i]; |
84 |
} |
85 |
for (; i < otherLength; i++) { |
86 |
extraPotentialInits[i] = otherInits.extraPotentialInits[i]; |
87 |
} |
119 |
} |
|
|
120 |
mergeLimit = length; |
121 |
copyLimit = otherLength; |
88 |
} else { |
122 |
} else { |
89 |
// current storage is longer |
123 |
// current storage is longer |
90 |
for (; i < otherLength; i++) { |
124 |
mergeLimit = otherLength; |
91 |
extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i]; |
125 |
} |
92 |
extraPotentialInits[i] |= otherInits.extraPotentialInits[i]; |
126 |
} |
93 |
extraDefiniteNulls[i] = (extraDefiniteNulls[i] | otherInits.extraDefiniteNulls[i]) & ~otherInits.extraDefiniteNonNulls[i]; |
127 |
} |
94 |
extraDefiniteNonNulls[i] = (extraDefiniteNonNulls[i] | otherInits.extraDefiniteNonNulls[i]) & ~otherInits.extraDefiniteNulls[i]; |
128 |
else if (otherInits.extra != null) { |
95 |
} |
129 |
// no storage here, but other has extra storage. |
96 |
for (; i < length; i++) { |
130 |
// shortcut regular copy because array copy is better |
97 |
extraDefiniteInits[i] = 0; |
131 |
int otherLength; |
98 |
extraDefiniteNulls[i] = 0; |
132 |
this.extra = new long[extraLength][]; |
99 |
extraDefiniteNonNulls[i] = 0; |
133 |
System.arraycopy(otherInits.extra[0], 0, |
|
|
134 |
(this.extra[0] = new long[otherLength = |
135 |
otherInits.extra[0].length]), 0, otherLength); |
136 |
System.arraycopy(otherInits.extra[1], 0, |
137 |
(this.extra[1] = new long[otherLength]), 0, otherLength); |
138 |
if (considerNulls) { |
139 |
for (int j = 2; j < extraLength; j++) { |
140 |
System.arraycopy(otherInits.extra[j], 0, |
141 |
(this.extra[j] = new long[otherLength]), 0, otherLength); |
142 |
} |
143 |
} |
144 |
else { |
145 |
for (int j = 2; j < extraLength; j++) { |
146 |
this.extra[j] = new long[otherLength]; |
147 |
} |
148 |
} |
149 |
} |
150 |
int i = 0; |
151 |
for (; i < mergeLimit; i++) { |
152 |
this.extra[0][i] |= otherInits.extra[0][i]; |
153 |
this.extra[1][i] |= otherInits.extra[1][i]; |
154 |
if (considerNulls) { // could consider pushing the test outside the loop |
155 |
if (this.extra[2][i] == 0 && |
156 |
this.extra[3][i] == 0 && |
157 |
this.extra[4][i] == 0 && |
158 |
this.extra[5][i] == 0) { |
159 |
for (int j = 2; j < extraLength; j++) { |
160 |
this.extra[j][i] = otherInits.extra[j][i]; |
100 |
} |
161 |
} |
101 |
} |
162 |
} |
102 |
} else { |
163 |
else { |
103 |
// no extra storage on otherInits |
164 |
this.extra[2][i] = |
|
|
165 |
(b1 = otherInits.extra[2][i]) | |
166 |
(a1 = this.extra[2][i]) & |
167 |
((nb2 = ~(b2 = otherInits.extra[3][i])) & |
168 |
(nb3 = ~(b3 = otherInits.extra[4][i])) & |
169 |
((nb4 = ~(b4 = otherInits.extra[5][i])) | |
170 |
((a2 = this.extra[3][i]) ^ |
171 |
(a4 = this.extra[5][i]))) | |
172 |
nb4 & (na2 = ~a2) & (na4 = ~a4)); |
173 |
this.extra[3][i] = |
174 |
b1 & b2 | |
175 |
~b1 & (((na1 = ~a1) | a4) & b2 | |
176 |
a2 & (b2 | |
177 |
a1 & (na4 = ~a4) & nb2 & nb3 | |
178 |
(~(a3 = this.extra[4][i]) & nb3 | na1 & na4) & nb4)); |
179 |
this.extra[4][i] = |
180 |
nb2 & b3 | |
181 |
~b1 & ((a1 & na2 & na4 | na1 & a3) & (nb2 | nb4) | |
182 |
a1 & na2 & a3 & nb2 | |
183 |
(a1 | a2 | na4) & b3); |
184 |
this.extra[5][i] = |
185 |
b4 | |
186 |
a4 & (nb2 & nb3 | ~(b1 ^ b2)); |
187 |
} |
104 |
} |
188 |
} |
105 |
} else |
189 |
} |
106 |
if (otherInits.extraDefiniteInits != null) { |
190 |
for (; i < copyLimit; i++) { |
107 |
// no storage here, but other has extra storage. |
191 |
this.extra[0][i] = otherInits.extra[0][i]; |
108 |
int otherLength; |
192 |
this.extra[1][i] = otherInits.extra[1][i]; |
109 |
System.arraycopy(otherInits.extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length]), 0, otherLength); |
193 |
if (considerNulls) { |
110 |
System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength); |
194 |
for (int j = 2; j < extraLength; j++) { |
111 |
System.arraycopy(otherInits.extraDefiniteNulls, 0, (extraDefiniteNulls = new long[otherLength]), 0, otherLength); |
195 |
this.extra[j][i] = otherInits.extra[j][i]; |
112 |
System.arraycopy(otherInits.extraDefiniteNonNulls, 0, (extraDefiniteNonNulls = new long[otherLength]), 0, otherLength); |
196 |
} |
113 |
} |
197 |
} |
114 |
return this; |
198 |
} |
115 |
} |
199 |
} |
|
|
200 |
return this; |
201 |
} |
116 |
|
202 |
|
117 |
// unions of both sets of initialization - used for try/finally |
203 |
public FlowInfo addPotentialInitializationsFrom(FlowInfo inits) { |
118 |
public FlowInfo addPotentialInitializationsFrom(FlowInfo inits) { |
204 |
if (this == DEAD_END){ |
119 |
|
205 |
return this; |
120 |
if (this == DEAD_END){ |
206 |
} |
121 |
return this; |
207 |
if (inits == DEAD_END){ |
|
|
208 |
return this; |
209 |
} |
210 |
UnconditionalFlowInfo otherInits = inits.unconditionalInits(); |
211 |
// union of potentially set ones |
212 |
this.potentialInits |= otherInits.potentialInits; |
213 |
// treating extra storage |
214 |
if (this.extra != null) { |
215 |
if (otherInits.extra != null) { |
216 |
// both sides have extra storage |
217 |
int i = 0, length, otherLength; |
218 |
if ((length = this.extra[0].length) < (otherLength = otherInits.extra[0].length)) { |
219 |
// current storage is shorter -> grow current |
220 |
for (int j = 0; j < extraLength; j++) { |
221 |
System.arraycopy(this.extra[j], 0, |
222 |
(this.extra[j] = new long[otherLength]), 0, length); |
223 |
} |
224 |
for (; i < length; i++) { |
225 |
this.extra[1][i] |= otherInits.extra[1][i]; |
226 |
} |
227 |
for (; i < otherLength; i++) { |
228 |
this.extra[1][i] = otherInits.extra[1][i]; |
229 |
} |
230 |
} |
231 |
else { |
232 |
// current storage is longer |
233 |
for (; i < otherLength; i++) { |
234 |
this.extra[1][i] |= otherInits.extra[1][i]; |
235 |
} |
236 |
} |
237 |
} |
238 |
} |
239 |
else if (otherInits.extra != null) { |
240 |
// no storage here, but other has extra storage. |
241 |
int otherLength = otherInits.extra[0].length; |
242 |
this.extra = new long[extraLength][]; |
243 |
for (int j = 0; j < extraLength; j++) { |
244 |
this.extra[j] = new long[otherLength]; |
122 |
} |
245 |
} |
|
|
246 |
System.arraycopy(otherInits.extra[1], 0, this.extra[1], 0, |
247 |
otherLength); |
248 |
} |
249 |
this.addPotentialNullInfoFrom(otherInits); |
250 |
return this; |
251 |
} |
123 |
|
252 |
|
124 |
UnconditionalFlowInfo otherInits = inits.unconditionalInits(); |
253 |
/** |
125 |
if (otherInits == DEAD_END){ |
254 |
* Compose other inits over this flow info, then return this. The operation |
126 |
return this; |
255 |
* semantics are to wave into this flow info the consequences upon null |
127 |
} |
256 |
* information of a possible path into the operations that resulted into |
128 |
// union of potentially set ones |
257 |
* otherInits. The fact that this path may be left unexecuted under peculiar |
129 |
this.potentialInits |= otherInits.potentialInits; |
258 |
* conditions results into less specific results than |
130 |
// also merge null check information (affected by potential inits) |
259 |
* {@link #addInitializationsFrom(FlowInfo) addInitializationsFrom}; moreover, |
131 |
this.definiteNulls &= otherInits.definiteNulls; |
260 |
* only the null information is affected. |
132 |
this.definiteNonNulls &= otherInits.definiteNonNulls; |
261 |
* @param otherInits other null inits to compose over this |
133 |
|
262 |
* @return this, modified according to otherInits information |
134 |
// treating extra storage |
263 |
*/ |
135 |
if (this.extraDefiniteInits != null) { |
264 |
public UnconditionalFlowInfo addPotentialNullInfoFrom( |
136 |
if (otherInits.extraDefiniteInits != null) { |
265 |
UnconditionalFlowInfo otherInits) { |
137 |
// both sides have extra storage |
266 |
if ((this.tagBits & UNREACHABLE) != 0 || |
138 |
int i = 0, length, otherLength; |
267 |
(otherInits.tagBits & UNREACHABLE) != 0 || |
139 |
if ((length = this.extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) { |
268 |
(otherInits.tagBits & NULL_FLAG_MASK) == 0) { |
140 |
// current storage is shorter -> grow current (could maybe reuse otherInits extra storage?) |
269 |
return this; |
141 |
System.arraycopy(this.extraDefiniteInits, 0, (this.extraDefiniteInits = new long[otherLength]), 0, length); |
270 |
} |
142 |
System.arraycopy(this.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, length); |
271 |
// if we get here, otherInits has some null info |
143 |
System.arraycopy(this.extraDefiniteNulls, 0, (this.extraDefiniteNulls = new long[otherLength]), 0, length); |
272 |
boolean thisHasNulls = (this.tagBits & NULL_FLAG_MASK) != 0; |
144 |
System.arraycopy(this.extraDefiniteNonNulls, 0, (this.extraDefiniteNonNulls = new long[otherLength]), 0, length); |
273 |
if (thisHasNulls) { |
145 |
while (i < length) { |
274 |
long a1, a2, na2, a3, na3, a4, na4, b1, nb1, b2, nb2, b3, nb3, b4, nb4; |
146 |
this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i]; |
275 |
this.nullAssignmentStatusBit1 = |
147 |
this.extraDefiniteNulls[i] &= otherInits.extraDefiniteNulls[i]; |
276 |
((a1 = this.nullAssignmentStatusBit1) & |
148 |
this.extraDefiniteNonNulls[i] &= otherInits.extraDefiniteNonNulls[i++]; |
277 |
(na4 = ~(a4 = this.nullAssignmentValueBit2)) & |
|
|
278 |
((na3 = ~(a3 = this.nullAssignmentValueBit1)) | |
279 |
(a2 = this.nullAssignmentStatusBit2)) | |
280 |
a2 & na3 & a4) & |
281 |
(nb3 = ~(b3 = otherInits.nullAssignmentValueBit1)) & |
282 |
((b2 = otherInits.nullAssignmentStatusBit2) | |
283 |
(nb4 = ~(b4 = otherInits.nullAssignmentValueBit2))) | |
284 |
a1 & (na2 = ~a2) & |
285 |
(a4 & ((nb1 = ~(b1 = otherInits.nullAssignmentStatusBit1)) & |
286 |
nb3 | b1 & |
287 |
(b4 | b2)) | |
288 |
na4 & (nb1 & (((nb2 = ~b2) & nb4 | b2) & nb3 | b3 & nb4) | |
289 |
b1 & nb4 & (nb2 | nb3))); |
290 |
this.nullAssignmentStatusBit2 = |
291 |
a2 & (~a1 & na4 & nb4 | |
292 |
a1 & na3 & nb3 & (nb1 & (nb2 & nb4 | b2) | |
293 |
b1 & (nb4 |b2 & b4))); |
294 |
this.nullAssignmentValueBit1 = |
295 |
a3 | |
296 |
b1 & nb2 & nb4 | |
297 |
nb1 & b3 | |
298 |
a1 & na2 & (b1 & b3 | nb1 & b4); |
299 |
// b1 & (~b2 & ~b4 | a1 & ~a2 & b3) | |
300 |
// ~b1 & (b3 | a1 & ~a2 & b4); -- same op nb |
301 |
this.nullAssignmentValueBit2 = |
302 |
a4 & (na2 | a2 & na3) | |
303 |
b4 & (nb2 | b2 & nb3); |
304 |
// extra storage management |
305 |
if (otherInits.extra != null) { |
306 |
int mergeLimit = 0, copyLimit = 0; |
307 |
int otherLength = otherInits.extra[0].length; |
308 |
if (this.extra == null) { |
309 |
this.extra = new long[extraLength][]; |
310 |
for (int j = 0; j < extraLength; j++) { |
311 |
this.extra[j] = new long[otherLength]; |
312 |
} |
313 |
copyLimit = otherLength; |
314 |
} |
315 |
else { |
316 |
mergeLimit = otherLength; |
317 |
if (mergeLimit > this.extra[0].length) { |
318 |
copyLimit = mergeLimit; |
319 |
mergeLimit = this.extra[0].length; |
320 |
for (int j = 0; j < extraLength; j++) { |
321 |
System.arraycopy(this.extra[j], 0, |
322 |
this.extra[j] = new long[otherLength], 0, |
323 |
mergeLimit); |
149 |
} |
324 |
} |
150 |
while (i < otherLength) { |
325 |
} |
151 |
this.extraPotentialInits[i] = otherInits.extraPotentialInits[i]; |
326 |
int i; |
152 |
this.extraDefiniteNulls[i] &= otherInits.extraDefiniteNulls[i]; |
327 |
for (i = 0; i < mergeLimit; i++) { |
153 |
this.extraDefiniteNonNulls[i] &= otherInits.extraDefiniteNonNulls[i++]; |
328 |
this.extra[2][i] = |
|
|
329 |
((a1 = this.extra[2][i]) & |
330 |
(na4 = ~(a4 = this.extra[5][i])) & |
331 |
((na3 = ~(a3 = this.extra[4][i])) | |
332 |
(a2 = this.extra[3][i])) | |
333 |
a2 & na3 & a4) & |
334 |
(nb3 = ~(b3 = otherInits.extra[4][i])) & |
335 |
((b2 = otherInits.extra[3][i]) | |
336 |
(nb4 = ~(b4 = otherInits.extra[5][i]))) | |
337 |
a1 & (na2 = ~a2) & |
338 |
(a4 & ((nb1 = ~(b1 = otherInits.extra[2][i])) & |
339 |
nb3 | b1 & |
340 |
(b4 | b2)) | |
341 |
na4 & (nb1 & (((nb2 = ~b2) & nb4 | b2) & nb3 | b3 & nb4) | |
342 |
b1 & nb4 & (nb2 | nb3))); |
343 |
this.extra[3][i] = |
344 |
a2 & (~a1 & na4 & nb4 | |
345 |
a1 & na3 & nb3 & (nb1 & (nb2 & nb4 | b2) | |
346 |
b1 & (nb4 |b2 & b4))); |
347 |
this.extra[4][i] = |
348 |
a3 | |
349 |
b1 & nb2 & nb4 | |
350 |
nb1 & b3 | |
351 |
a1 & na2 & (b1 & b3 | nb1 & b4); |
352 |
this.extra[5][i] = |
353 |
a4 & (na2 | a2 & na3) | |
354 |
b4 & (nb2 | b2 & nb3); |
355 |
} |
356 |
for (; i < copyLimit; i++) { |
357 |
if (otherInits.extra[4][i] != 0 || |
358 |
otherInits.extra[5][i] != 0) { |
359 |
this.tagBits |= NULL_FLAG_MASK; |
360 |
this.extra[4][i] = |
361 |
otherInits.extra[4][i] & |
362 |
~(otherInits.extra[2][i] & |
363 |
~otherInits.extra[3][i] & |
364 |
otherInits.extra[5][i]); |
365 |
this.extra[5][i] = |
366 |
otherInits.extra[5][i]; |
154 |
} |
367 |
} |
155 |
} else { |
368 |
} |
156 |
// current storage is longer |
369 |
} |
157 |
while (i < otherLength) { |
370 |
} |
158 |
this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i]; |
371 |
} |
159 |
this.extraDefiniteNulls[i] &= otherInits.extraDefiniteNulls[i]; |
372 |
else { |
160 |
this.extraDefiniteNonNulls[i] &= otherInits.extraDefiniteNonNulls[i++]; |
373 |
if (otherInits.nullAssignmentValueBit1 != 0 || |
|
|
374 |
otherInits.nullAssignmentValueBit2 != 0) { |
375 |
// add potential values |
376 |
this.nullAssignmentValueBit1 = |
377 |
otherInits.nullAssignmentValueBit1 & |
378 |
~(otherInits.nullAssignmentStatusBit1 & |
379 |
~otherInits.nullAssignmentStatusBit2 & |
380 |
otherInits.nullAssignmentValueBit2); // exclude assigned unknown |
381 |
this.nullAssignmentValueBit2 = |
382 |
otherInits.nullAssignmentValueBit2; |
383 |
thisHasNulls = |
384 |
this.nullAssignmentValueBit1 != 0 || |
385 |
this.nullAssignmentValueBit2 != 0; |
386 |
} |
387 |
// extra storage management |
388 |
if (otherInits.extra != null) { |
389 |
int mergeLimit = 0, copyLimit = 0; |
390 |
int otherLength = otherInits.extra[0].length; |
391 |
if (this.extra == null) { |
392 |
copyLimit = otherLength; |
393 |
// cannot happen when called from addPotentialInitializationsFrom |
394 |
this.extra = new long[extraLength][]; |
395 |
for (int j = 0; j < extraLength; j++) { |
396 |
this.extra[j] = new long[otherLength]; |
397 |
} |
398 |
} |
399 |
else { |
400 |
mergeLimit = otherLength; |
401 |
if (mergeLimit > this.extra[0].length) { |
402 |
copyLimit = mergeLimit; |
403 |
mergeLimit = this.extra[0].length; |
404 |
System.arraycopy(this.extra[0], 0, |
405 |
this.extra[0] = new long[otherLength], 0, |
406 |
mergeLimit); |
407 |
System.arraycopy(this.extra[1], 0, |
408 |
this.extra[1] = new long[otherLength], 0, |
409 |
mergeLimit); |
410 |
for (int j = 2; j < extraLength; j++) { |
411 |
this.extra[j] = new long[otherLength]; |
161 |
} |
412 |
} |
162 |
} |
413 |
} |
163 |
} |
414 |
} |
164 |
} else |
415 |
int i; |
165 |
if (otherInits.extraDefiniteInits != null) { |
416 |
for (i = 0; i < mergeLimit; i++) { |
166 |
// no storage here, but other has extra storage. |
417 |
if (otherInits.extra[4][i] != 0 || |
167 |
int otherLength; |
418 |
otherInits.extra[5][i] != 0) { |
168 |
this.extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length]; |
419 |
this.extra[4][i] |= |
169 |
System.arraycopy(otherInits.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, otherLength); |
420 |
otherInits.extra[4][i] & |
170 |
this.extraDefiniteNulls = new long[otherLength]; |
421 |
~(otherInits.extra[2][i] & |
171 |
this.extraDefiniteNonNulls = new long[otherLength]; |
422 |
~otherInits.extra[3][i] & |
|
|
423 |
otherInits.extra[5][i]); |
424 |
this.extra[5][i] |= |
425 |
otherInits.extra[5][i]; |
426 |
thisHasNulls = thisHasNulls || |
427 |
this.extra[4][i] != 0 || |
428 |
this.extra[5][i] != 0; |
429 |
} |
430 |
} |
431 |
for (; i < copyLimit; i++) { |
432 |
if (otherInits.extra[4][i] != 0 || |
433 |
otherInits.extra[5][i] != 0) { |
434 |
this.extra[4][i] = |
435 |
otherInits.extra[4][i] & |
436 |
~(otherInits.extra[2][i] & |
437 |
~otherInits.extra[3][i] & |
438 |
otherInits.extra[5][i]); |
439 |
this.extra[5][i] = |
440 |
otherInits.extra[5][i]; |
441 |
thisHasNulls = thisHasNulls || |
442 |
this.extra[4][i] != 0 || |
443 |
this.extra[5][i] != 0; |
444 |
} |
172 |
} |
445 |
} |
173 |
return this; |
|
|
174 |
} |
175 |
|
176 |
/** |
177 |
* Answers a copy of the current instance |
178 |
*/ |
179 |
public FlowInfo copy() { |
180 |
|
181 |
// do not clone the DeadEnd |
182 |
if (this == DEAD_END) |
183 |
return this; |
184 |
|
185 |
// look for an unused preallocated object |
186 |
UnconditionalFlowInfo copy = new UnconditionalFlowInfo(); |
187 |
|
188 |
// copy slots |
189 |
copy.definiteInits = this.definiteInits; |
190 |
copy.potentialInits = this.potentialInits; |
191 |
copy.definiteNulls = this.definiteNulls; |
192 |
copy.definiteNonNulls = this.definiteNonNulls; |
193 |
copy.reachMode = this.reachMode; |
194 |
copy.maxFieldCount = this.maxFieldCount; |
195 |
|
196 |
if (this.extraDefiniteInits != null) { |
197 |
int length; |
198 |
System.arraycopy(this.extraDefiniteInits, 0, (copy.extraDefiniteInits = new long[length = extraDefiniteInits.length]), 0, length); |
199 |
System.arraycopy(this.extraPotentialInits, 0, (copy.extraPotentialInits = new long[length]), 0, length); |
200 |
System.arraycopy(this.extraDefiniteNulls, 0, (copy.extraDefiniteNulls = new long[length]), 0, length); |
201 |
System.arraycopy(this.extraDefiniteNonNulls, 0, (copy.extraDefiniteNonNulls = new long[length]), 0, length); |
202 |
} |
446 |
} |
203 |
return copy; |
|
|
204 |
} |
447 |
} |
205 |
|
448 |
if (thisHasNulls) { |
206 |
public UnconditionalFlowInfo discardFieldInitializations(){ |
449 |
this.tagBits |= NULL_FLAG_MASK; |
207 |
|
450 |
} |
208 |
int limit = this.maxFieldCount; |
451 |
else { |
209 |
|
452 |
this.tagBits &= NULL_FLAG_MASK; |
210 |
if (limit < BitCacheSize) { |
|
|
211 |
long mask = (1L << limit)-1; |
212 |
this.definiteInits &= ~mask; |
213 |
this.potentialInits &= ~mask; |
214 |
this.definiteNulls &= ~mask; |
215 |
this.definiteNonNulls &= ~mask; |
216 |
return this; |
217 |
} |
218 |
|
219 |
this.definiteInits = 0; |
220 |
this.potentialInits = 0; |
221 |
this.definiteNulls = 0; |
222 |
this.definiteNonNulls = 0; |
223 |
|
224 |
// use extra vector |
225 |
if (extraDefiniteInits == null) { |
226 |
return this; // if vector not yet allocated, then not initialized |
227 |
} |
228 |
int vectorIndex, length = this.extraDefiniteInits.length; |
229 |
if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) { |
230 |
return this; // not enough room yet |
231 |
} |
232 |
for (int i = 0; i < vectorIndex; i++) { |
233 |
this.extraDefiniteInits[i] = 0L; |
234 |
this.extraPotentialInits[i] = 0L; |
235 |
this.extraDefiniteNulls[i] = 0L; |
236 |
this.extraDefiniteNonNulls[i] = 0L; |
237 |
} |
238 |
long mask = (1L << (limit % BitCacheSize))-1; |
239 |
this.extraDefiniteInits[vectorIndex] &= ~mask; |
240 |
this.extraPotentialInits[vectorIndex] &= ~mask; |
241 |
this.extraDefiniteNulls[vectorIndex] &= ~mask; |
242 |
this.extraDefiniteNonNulls[vectorIndex] &= ~mask; |
243 |
return this; |
244 |
} |
453 |
} |
|
|
454 |
return this; |
455 |
} |
245 |
|
456 |
|
246 |
public UnconditionalFlowInfo discardNonFieldInitializations(){ |
457 |
public FlowInfo copy() { |
247 |
|
458 |
// do not clone the DeadEnd |
248 |
int limit = this.maxFieldCount; |
459 |
if (this == DEAD_END) { |
249 |
|
|
|
250 |
if (limit < BitCacheSize) { |
251 |
long mask = (1L << limit)-1; |
252 |
this.definiteInits &= mask; |
253 |
this.potentialInits &= mask; |
254 |
this.definiteNulls &= mask; |
255 |
this.definiteNonNulls &= mask; |
256 |
return this; |
257 |
} |
258 |
// use extra vector |
259 |
if (extraDefiniteInits == null) { |
260 |
return this; // if vector not yet allocated, then not initialized |
261 |
} |
262 |
int vectorIndex, length = this.extraDefiniteInits.length; |
263 |
if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) { |
264 |
return this; // not enough room yet |
265 |
} |
266 |
long mask = (1L << (limit % BitCacheSize))-1; |
267 |
this.extraDefiniteInits[vectorIndex] &= mask; |
268 |
this.extraPotentialInits[vectorIndex] &= mask; |
269 |
this.extraDefiniteNulls[vectorIndex] &= mask; |
270 |
this.extraDefiniteNonNulls[vectorIndex] &= mask; |
271 |
for (int i = vectorIndex+1; i < length; i++) { |
272 |
this.extraDefiniteInits[i] = 0L; |
273 |
this.extraPotentialInits[i] = 0L; |
274 |
this.extraDefiniteNulls[i] = 0L; |
275 |
this.extraDefiniteNonNulls[i] = 0L; |
276 |
} |
277 |
return this; |
460 |
return this; |
278 |
} |
461 |
} |
279 |
|
462 |
UnconditionalFlowInfo copy = new UnconditionalFlowInfo(); |
280 |
public UnconditionalFlowInfo discardNullRelatedInitializations(){ |
463 |
// copy slots |
281 |
|
464 |
copy.definiteInits = this.definiteInits; |
282 |
this.definiteNulls = 0; |
465 |
copy.potentialInits = this.potentialInits; |
283 |
this.definiteNonNulls = 0; |
466 |
boolean hasNullInfo = (this.tagBits & NULL_FLAG_MASK) != 0; |
284 |
|
467 |
if (hasNullInfo) { |
285 |
int length = this.extraDefiniteInits == null ? 0 : this.extraDefiniteInits.length; |
468 |
copy.nullAssignmentStatusBit1 = this.nullAssignmentStatusBit1; |
286 |
for (int i = 0; i < length; i++) { |
469 |
copy.nullAssignmentStatusBit2 = this.nullAssignmentStatusBit2; |
287 |
this.extraDefiniteNulls[i] = 0L; |
470 |
copy.nullAssignmentValueBit1 = this.nullAssignmentValueBit1; |
288 |
this.extraDefiniteNonNulls[i] = 0L; |
471 |
copy.nullAssignmentValueBit2 = this.nullAssignmentValueBit2; |
|
|
472 |
} |
473 |
copy.tagBits = this.tagBits; |
474 |
copy.maxFieldCount = this.maxFieldCount; |
475 |
if (this.extra != null) { |
476 |
int length; |
477 |
copy.extra = new long[extraLength][]; |
478 |
System.arraycopy(this.extra[0], 0, |
479 |
(copy.extra[0] = new long[length = this.extra[0].length]), 0, |
480 |
length); |
481 |
System.arraycopy(this.extra[1], 0, |
482 |
(copy.extra[1] = new long[length]), 0, length); |
483 |
if (hasNullInfo) { |
484 |
for (int j = 2; j < extraLength; j++) { |
485 |
System.arraycopy(this.extra[j], 0, |
486 |
(copy.extra[j] = new long[length]), 0, length); |
487 |
} |
488 |
} |
489 |
else { |
490 |
for (int j = 2; j < extraLength; j++) { |
491 |
copy.extra[j] = new long[length]; |
492 |
} |
289 |
} |
493 |
} |
290 |
return this; |
|
|
291 |
} |
494 |
} |
|
|
495 |
return copy; |
496 |
} |
292 |
|
497 |
|
293 |
public FlowInfo initsWhenFalse() { |
498 |
/** |
294 |
|
499 |
* Remove local variables information from this flow info and return this. |
295 |
return this; |
500 |
* @return this, deprived from any local variable information |
296 |
} |
501 |
*/ |
297 |
|
502 |
public UnconditionalFlowInfo discardNonFieldInitializations() { |
298 |
public FlowInfo initsWhenTrue() { |
503 |
int limit = this.maxFieldCount; |
299 |
|
504 |
if (limit < BitCacheSize) { |
300 |
return this; |
505 |
long mask = (1L << limit)-1; |
|
|
506 |
this.definiteInits &= mask; |
507 |
this.potentialInits &= mask; |
508 |
this.nullAssignmentStatusBit1 &= mask; |
509 |
this.nullAssignmentStatusBit2 &= mask; |
510 |
this.nullAssignmentValueBit1 &= mask; |
511 |
this.nullAssignmentValueBit2 &= mask; |
512 |
} |
513 |
// use extra vector |
514 |
if (this.extra == null) { |
515 |
return this; // if vector not yet allocated, then not initialized |
516 |
} |
517 |
int vectorIndex, length = this.extra[0].length; |
518 |
if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) { |
519 |
return this; // not enough room yet |
301 |
} |
520 |
} |
302 |
|
521 |
if (vectorIndex >= 0) { |
303 |
/** |
522 |
// else we only have complete non field array items left |
304 |
* Check status of definite assignment at a given position. |
523 |
long mask = (1L << (limit % BitCacheSize))-1; |
305 |
* It deals with the dual representation of the InitializationInfo2: |
524 |
for (int j = 0; j < extraLength; j++) { |
306 |
* bits for the first 64 entries, then an array of booleans. |
525 |
this.extra[j][vectorIndex] &= mask; |
307 |
*/ |
|
|
308 |
final private boolean isDefinitelyAssigned(int position) { |
309 |
|
310 |
// Dependant of CodeStream.isDefinitelyAssigned(..) |
311 |
// id is zero-based |
312 |
if (position < BitCacheSize) { |
313 |
return (definiteInits & (1L << position)) != 0; // use bits |
314 |
} |
526 |
} |
315 |
// use extra vector |
|
|
316 |
if (extraDefiniteInits == null) |
317 |
return false; // if vector not yet allocated, then not initialized |
318 |
int vectorIndex; |
319 |
if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteInits.length) |
320 |
return false; // if not enough room in vector, then not initialized |
321 |
return ((extraDefiniteInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0; |
322 |
} |
527 |
} |
323 |
|
528 |
for (int i = vectorIndex + 1; i < length; i++) { |
324 |
/** |
529 |
for (int j = 0; j < extraLength; j++) { |
325 |
* Check status of definite non-null assignment at a given position. |
530 |
this.extra[j][i] = 0; |
326 |
* It deals with the dual representation of the InitializationInfo2: |
|
|
327 |
* bits for the first 64 entries, then an array of booleans. |
328 |
*/ |
329 |
final private boolean isDefinitelyNonNull(int position) { |
330 |
|
331 |
// Dependant of CodeStream.isDefinitelyAssigned(..) |
332 |
// id is zero-based |
333 |
if (position < BitCacheSize) { |
334 |
return (definiteNonNulls & (1L << position)) != 0; // use bits |
335 |
} |
531 |
} |
336 |
// use extra vector |
|
|
337 |
if (extraDefiniteNonNulls == null) |
338 |
return false; // if vector not yet allocated, then not initialized |
339 |
int vectorIndex; |
340 |
if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteNonNulls.length) |
341 |
return false; // if not enough room in vector, then not initialized |
342 |
return ((extraDefiniteNonNulls[vectorIndex]) & (1L << (position % BitCacheSize))) != 0; |
343 |
} |
344 |
|
345 |
/** |
346 |
* Check status of definite null assignment at a given position. |
347 |
* It deals with the dual representation of the InitializationInfo2: |
348 |
* bits for the first 64 entries, then an array of booleans. |
349 |
*/ |
350 |
final private boolean isDefinitelyNull(int position) { |
351 |
|
352 |
// Dependant of CodeStream.isDefinitelyAssigned(..) |
353 |
// id is zero-based |
354 |
if (position < BitCacheSize) { |
355 |
return (definiteNulls & (1L << position)) != 0; // use bits |
356 |
} |
357 |
// use extra vector |
358 |
if (extraDefiniteNulls == null) |
359 |
return false; // if vector not yet allocated, then not initialized |
360 |
int vectorIndex; |
361 |
if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteNulls.length) |
362 |
return false; // if not enough room in vector, then not initialized |
363 |
return ((extraDefiniteNulls[vectorIndex]) & (1L << (position % BitCacheSize))) != 0; |
364 |
} |
365 |
|
366 |
/** |
367 |
* Check status of definite assignment for a field. |
368 |
*/ |
369 |
final public boolean isDefinitelyAssigned(FieldBinding field) { |
370 |
|
371 |
// Dependant of CodeStream.isDefinitelyAssigned(..) |
372 |
// We do not want to complain in unreachable code |
373 |
if ((this.reachMode & UNREACHABLE) != 0) |
374 |
return true; |
375 |
return isDefinitelyAssigned(field.id); |
376 |
} |
532 |
} |
377 |
|
533 |
return this; |
378 |
/** |
534 |
} |
379 |
* Check status of definite assignment for a local. |
535 |
|
380 |
*/ |
536 |
public FlowInfo initsWhenFalse() { |
381 |
final public boolean isDefinitelyAssigned(LocalVariableBinding local) { |
537 |
return this; |
382 |
|
538 |
} |
383 |
// Dependant of CodeStream.isDefinitelyAssigned(..) |
539 |
|
384 |
// We do not want to complain in unreachable code |
540 |
public FlowInfo initsWhenTrue() { |
385 |
if ((this.reachMode & UNREACHABLE) != 0) |
541 |
return this; |
386 |
return true; |
542 |
} |
387 |
|
543 |
|
388 |
// final constants are inlined, and thus considered as always initialized |
544 |
/** |
389 |
if (local.constant() != Constant.NotAConstant) { |
545 |
* Check status of definite assignment at a given position. |
390 |
return true; |
546 |
* It deals with the dual representation of the InitializationInfo2: |
391 |
} |
547 |
* bits for the first 64 entries, then an array of booleans. |
392 |
return isDefinitelyAssigned(local.id + maxFieldCount); |
548 |
*/ |
|
|
549 |
final private boolean isDefinitelyAssigned(int position) { |
550 |
if (position < BitCacheSize) { |
551 |
// use bits |
552 |
return (this.definiteInits & (1L << position)) != 0; |
553 |
} |
554 |
// use extra vector |
555 |
if (this.extra == null) |
556 |
return false; // if vector not yet allocated, then not initialized |
557 |
int vectorIndex; |
558 |
if ((vectorIndex = (position / BitCacheSize) - 1) |
559 |
>= this.extra[0].length) { |
560 |
return false; // if not enough room in vector, then not initialized |
393 |
} |
561 |
} |
394 |
|
562 |
return ((this.extra[0][vectorIndex]) & |
395 |
/** |
563 |
(1L << (position % BitCacheSize))) != 0; |
396 |
* Check status of definite non-null assignment for a field. |
564 |
} |
397 |
*/ |
565 |
|
398 |
final public boolean isDefinitelyNonNull(FieldBinding field) { |
566 |
final public boolean isDefinitelyAssigned(FieldBinding field) { |
399 |
|
567 |
// Dependant of CodeStream.isDefinitelyAssigned(..) |
400 |
// Dependant of CodeStream.isDefinitelyAssigned(..) |
568 |
// do not want to complain in unreachable code |
401 |
// We do not want to complain in unreachable code |
569 |
if ((this.tagBits & UNREACHABLE) != 0) { |
402 |
if ((this.reachMode & UNREACHABLE) != 0) |
570 |
return true; |
403 |
return false; |
|
|
404 |
return isDefinitelyNonNull(field.id); |
405 |
} |
571 |
} |
406 |
|
572 |
return isDefinitelyAssigned(field.id); |
407 |
/** |
573 |
} |
408 |
* Check status of definite non-null assignment for a local. |
574 |
|
409 |
*/ |
575 |
final public boolean isDefinitelyAssigned(LocalVariableBinding local) { |
410 |
final public boolean isDefinitelyNonNull(LocalVariableBinding local) { |
576 |
// do not want to complain in unreachable code |
411 |
|
577 |
if ((this.tagBits & UNREACHABLE) != 0) { |
412 |
// Dependant of CodeStream.isDefinitelyAssigned(..) |
578 |
return true; |
413 |
// We do not want to complain in unreachable code |
579 |
} |
414 |
if ((this.reachMode & UNREACHABLE) != 0) |
580 |
// final constants are inlined, and thus considered as always initialized |
415 |
return false; |
581 |
if (local.constant() != Constant.NotAConstant) { |
416 |
// final constants are inlined, and thus considered as always initialized |
582 |
return true; |
417 |
if (local.constant() != Constant.NotAConstant) { |
|
|
418 |
return true; |
419 |
} |
420 |
return isDefinitelyNonNull(local.id + maxFieldCount); |
421 |
} |
422 |
|
423 |
/** |
424 |
* Check status of definite null assignment for a field. |
425 |
*/ |
426 |
final public boolean isDefinitelyNull(FieldBinding field) { |
427 |
|
428 |
// Dependant of CodeStream.isDefinitelyAssigned(..) |
429 |
// We do not want to complain in unreachable code |
430 |
if ((this.reachMode & UNREACHABLE) != 0) |
431 |
return false; |
432 |
return isDefinitelyNull(field.id); |
433 |
} |
583 |
} |
434 |
|
584 |
return isDefinitelyAssigned(local.id + this.maxFieldCount); |
435 |
/** |
585 |
} |
436 |
* Check status of definite null assignment for a local. |
586 |
|
437 |
*/ |
587 |
final public boolean isDefinitelyNonNull(LocalVariableBinding local) { |
438 |
final public boolean isDefinitelyNull(LocalVariableBinding local) { |
588 |
// do not want to complain in unreachable code |
439 |
|
589 |
if ((this.tagBits & UNREACHABLE) != 0 || |
440 |
// Dependant of CodeStream.isDefinitelyAssigned(..) |
590 |
(this.tagBits & NULL_FLAG_MASK) == 0) { |
441 |
// We do not want to complain in unreachable code |
591 |
return false; |
442 |
if ((this.reachMode & UNREACHABLE) != 0) |
592 |
} |
443 |
return false; |
593 |
if ((local.type.tagBits & TagBits.IsBaseType) != 0 || |
444 |
return isDefinitelyNull(local.id + maxFieldCount); |
594 |
local.constant() != Constant.NotAConstant) { |
|
|
595 |
return true; |
596 |
} |
597 |
int position = local.id + this.maxFieldCount; |
598 |
long mask; |
599 |
if (position < BitCacheSize) { // use bits |
600 |
return |
601 |
(this.nullAssignmentStatusBit2 & |
602 |
(mask = 1L << position)) != 0 ? |
603 |
(this.nullAssignmentStatusBit1 & mask) != 0 : |
604 |
(this.nullAssignmentStatusBit1 & |
605 |
this.nullAssignmentValueBit2 & mask) != 0 && |
606 |
(this.nullAssignmentValueBit1 & mask) == 0; |
607 |
} |
608 |
// use extra vector |
609 |
if (this.extra == null) { |
610 |
return false; // if vector not yet allocated, then not initialized |
611 |
} |
612 |
int vectorIndex; |
613 |
if ((vectorIndex = (position / BitCacheSize) - 1) |
614 |
>= this.extra[0].length) { |
615 |
return false; // if not enough room in vector, then not initialized |
616 |
} |
617 |
return |
618 |
(this.extra[3][vectorIndex] & |
619 |
(mask = 1L << (position % BitCacheSize))) != 0 ? |
620 |
(this.extra[2][vectorIndex] & mask) != 0 : |
621 |
(this.extra[2][vectorIndex] & |
622 |
this.extra[5][vectorIndex] & mask) != 0 && |
623 |
(this.extra[4][vectorIndex] & mask) == 0; |
624 |
} |
625 |
|
626 |
final public boolean isDefinitelyNull(LocalVariableBinding local) { |
627 |
// do not want to complain in unreachable code |
628 |
if ((this.tagBits & UNREACHABLE) != 0 || |
629 |
(this.tagBits & NULL_FLAG_MASK) == 0 || |
630 |
(local.type.tagBits & TagBits.IsBaseType) != 0) { |
631 |
return false; |
632 |
} |
633 |
int position = local.id + this.maxFieldCount; |
634 |
long mask; |
635 |
if (position < BitCacheSize) { // use bits |
636 |
return |
637 |
(this.nullAssignmentStatusBit2 & (mask = 1L << position)) != 0 ? |
638 |
(this.nullAssignmentStatusBit1 & mask) == 0 : |
639 |
(this.nullAssignmentStatusBit1 & |
640 |
this.nullAssignmentValueBit1 & mask) != 0 && |
641 |
(this.nullAssignmentValueBit2 & mask) == 0; |
642 |
} |
643 |
// use extra vector |
644 |
if (this.extra == null) { |
645 |
return false; // if vector not yet allocated, then not initialized |
646 |
} |
647 |
int vectorIndex; |
648 |
if ((vectorIndex = (position / BitCacheSize) - 1) >= |
649 |
this.extra[0].length) { |
650 |
return false; // if not enough room in vector, then not initialized |
651 |
} |
652 |
return |
653 |
(this.extra[3][vectorIndex] & |
654 |
(mask = 1L << (position % BitCacheSize))) != 0 ? |
655 |
(this.extra[2][vectorIndex] & mask) == 0 : |
656 |
(this.extra[2][vectorIndex] & |
657 |
this.extra[4][vectorIndex] & mask) != 0 && |
658 |
(this.extra[5][vectorIndex] & mask) == 0; |
659 |
} |
660 |
|
661 |
final public boolean isDefinitelyUnknown(LocalVariableBinding local) { |
662 |
// do not want to complain in unreachable code |
663 |
if ((this.tagBits & UNREACHABLE) != 0 || |
664 |
(this.tagBits & NULL_FLAG_MASK) == 0) { |
665 |
return false; |
666 |
} |
667 |
int position = local.id + this.maxFieldCount; |
668 |
long mask; |
669 |
if (position < BitCacheSize) { // use bits |
670 |
return |
671 |
(this.nullAssignmentStatusBit2 & (mask = 1L << position)) != 0 ? |
672 |
false : |
673 |
(this.nullAssignmentStatusBit1 & |
674 |
this.nullAssignmentValueBit1 & |
675 |
this.nullAssignmentValueBit2 & mask) != 0; |
676 |
} |
677 |
// use extra vector |
678 |
if (this.extra == null) { |
679 |
return false; // if vector not yet allocated, then not initialized |
680 |
} |
681 |
int vectorIndex; |
682 |
if ((vectorIndex = (position / BitCacheSize) - 1) >= |
683 |
this.extra[0].length) { |
684 |
return false; // if not enough room in vector, then not initialized |
685 |
} |
686 |
return |
687 |
(this.extra[3][vectorIndex] & |
688 |
(mask = 1L << (position % BitCacheSize))) != 0 ? |
689 |
false : |
690 |
(this.extra[2][vectorIndex] & |
691 |
this.extra[4][vectorIndex] & |
692 |
this.extra[5][vectorIndex] & |
693 |
mask) != 0; |
694 |
} |
695 |
|
696 |
/** |
697 |
* Check status of potential assignment at a given position. |
698 |
* It deals with the dual representation of the InitializationInfo3: |
699 |
* bits for the first 64 entries, then an array of booleans. |
700 |
*/ |
701 |
final private boolean isPotentiallyAssigned(int position) { |
702 |
// id is zero-based |
703 |
if (position < BitCacheSize) { |
704 |
// use bits |
705 |
return (this.potentialInits & (1L << position)) != 0; |
706 |
} |
707 |
// use extra vector |
708 |
if (this.extra == null) { |
709 |
return false; // if vector not yet allocated, then not initialized |
710 |
} |
711 |
int vectorIndex; |
712 |
if ((vectorIndex = (position / BitCacheSize) - 1) |
713 |
>= this.extra[0].length) { |
714 |
return false; // if not enough room in vector, then not initialized |
445 |
} |
715 |
} |
|
|
716 |
return ((this.extra[1][vectorIndex]) & |
717 |
(1L << (position % BitCacheSize))) != 0; |
718 |
} |
719 |
|
720 |
/** |
721 |
* Check status of definite assignment for a field. |
722 |
*/ |
723 |
final public boolean isPotentiallyAssigned(FieldBinding field) { |
724 |
return isPotentiallyAssigned(field.id); |
725 |
} |
446 |
|
726 |
|
447 |
public boolean isReachable() { |
727 |
/** |
448 |
|
728 |
* Check status of potential assignment for a local. |
449 |
return this.reachMode == REACHABLE; |
729 |
*/ |
|
|
730 |
final public boolean isPotentiallyAssigned(LocalVariableBinding local) { |
731 |
// final constants are inlined, and thus considered as always initialized |
732 |
if (local.constant() != Constant.NotAConstant) { |
733 |
return true; |
450 |
} |
734 |
} |
451 |
|
735 |
return isPotentiallyAssigned(local.id + this.maxFieldCount); |
452 |
/** |
736 |
} |
453 |
* Check status of potential assignment at a given position. |
737 |
|
454 |
* It deals with the dual representation of the InitializationInfo3: |
738 |
final public boolean isPotentiallyNull(LocalVariableBinding local) { |
455 |
* bits for the first 64 entries, then an array of booleans. |
739 |
if ((this.tagBits & NULL_FLAG_MASK) == 0 || |
456 |
*/ |
740 |
(local.type.tagBits & TagBits.IsBaseType) != 0) { |
457 |
final private boolean isPotentiallyAssigned(int position) { |
741 |
return false; |
458 |
|
742 |
} |
459 |
// id is zero-based |
743 |
int position; |
460 |
if (position < BitCacheSize) { |
744 |
long mask; |
|
|
745 |
if ((position = local.id + this.maxFieldCount) < BitCacheSize) { |
746 |
// use bits |
747 |
return |
748 |
(this.nullAssignmentStatusBit2 & (mask = 1L << position)) != 0 ? |
749 |
(this.nullAssignmentStatusBit1 & mask) == 0 : // protected null |
750 |
(this.nullAssignmentValueBit1 & mask) != 0 && // null bit set and |
751 |
((this.nullAssignmentStatusBit1 & mask) == 0 || // (potential or |
752 |
(this.nullAssignmentValueBit2 & mask) == 0); |
753 |
// assigned, but not unknown) |
754 |
} |
755 |
// use extra vector |
756 |
if (this.extra == null) { |
757 |
return false; // if vector not yet allocated, then not initialized |
758 |
} |
759 |
int vectorIndex; |
760 |
if ((vectorIndex = (position / BitCacheSize) - 1) >= |
761 |
this.extra[0].length) { |
762 |
return false; // if not enough room in vector, then not initialized |
763 |
} |
764 |
return |
765 |
(this.extra[3][vectorIndex] & |
766 |
(mask = 1L << (position % BitCacheSize))) != 0 ? |
767 |
(this.extra[2][vectorIndex] & mask) == 0 : |
768 |
(this.extra[4][vectorIndex] & mask) != 0 && |
769 |
((this.extra[2][vectorIndex] & mask) == 0 || |
770 |
(this.extra[5][vectorIndex] & mask) == 0); |
771 |
} |
772 |
|
773 |
final public boolean isPotentiallyUnknown(LocalVariableBinding local) { |
774 |
// do not want to complain in unreachable code |
775 |
if ((this.tagBits & UNREACHABLE) != 0 || |
776 |
(this.tagBits & NULL_FLAG_MASK) == 0) { |
777 |
return false; |
778 |
} |
779 |
int position = local.id + this.maxFieldCount; |
780 |
long mask; |
781 |
if (position < BitCacheSize) { // use bits |
782 |
return |
783 |
(this.nullAssignmentStatusBit2 & (mask = 1L << position)) != 0 ? |
784 |
false : |
785 |
((this.nullAssignmentStatusBit1 & |
786 |
this.nullAssignmentValueBit1 | |
787 |
~this.nullAssignmentStatusBit1 & |
788 |
~this.nullAssignmentValueBit1) & |
789 |
this.nullAssignmentValueBit2 & mask) != 0; |
790 |
} |
791 |
// use extra vector |
792 |
if (this.extra == null) { |
793 |
return false; // if vector not yet allocated, then not initialized |
794 |
} |
795 |
int vectorIndex; |
796 |
if ((vectorIndex = (position / BitCacheSize) - 1) >= |
797 |
this.extra[0].length) { |
798 |
return false; // if not enough room in vector, then not initialized |
799 |
} |
800 |
return |
801 |
(this.extra[3][vectorIndex] & |
802 |
(mask = 1L << (position % BitCacheSize))) != 0 ? |
803 |
false : |
804 |
((this.extra[2][vectorIndex] & |
805 |
this.extra[4][vectorIndex] | |
806 |
~this.extra[2][vectorIndex] & |
807 |
~this.extra[4][vectorIndex]) & |
808 |
this.extra[5][vectorIndex] & |
809 |
mask) != 0; |
810 |
} |
811 |
|
812 |
final public boolean isProtectedNonNull(LocalVariableBinding local) { |
813 |
if ((this.tagBits & NULL_FLAG_MASK) == 0 || |
814 |
(local.type.tagBits & TagBits.IsBaseType) != 0) { |
815 |
return false; |
816 |
} |
817 |
int position; |
818 |
if ((position = local.id + this.maxFieldCount) < BitCacheSize) { |
819 |
// use bits |
820 |
return (this.nullAssignmentStatusBit1 & |
821 |
this.nullAssignmentStatusBit2 & (1L << position)) != 0; |
822 |
} |
823 |
// use extra vector |
824 |
if (this.extra == null) { |
825 |
return false; // if vector not yet allocated, then not initialized |
826 |
} |
827 |
int vectorIndex; |
828 |
if ((vectorIndex = (position / BitCacheSize) - 1) >= |
829 |
this.extra[0].length) { |
830 |
return false; // if not enough room in vector, then not initialized |
831 |
} |
832 |
return (this.extra[4][vectorIndex] & |
833 |
this.extra[5][vectorIndex] & |
834 |
(1L << (position % BitCacheSize))) != 0; |
835 |
} |
836 |
|
837 |
final public boolean isProtectedNull(LocalVariableBinding local) { |
838 |
if ((this.tagBits & NULL_FLAG_MASK) == 0 || |
839 |
(local.type.tagBits & TagBits.IsBaseType) != 0) { |
840 |
return false; |
841 |
} |
842 |
int position; |
843 |
if ((position = local.id + this.maxFieldCount) < BitCacheSize) { |
844 |
// use bits |
845 |
return (~this.nullAssignmentStatusBit1 & |
846 |
this.nullAssignmentStatusBit2 & (1L << position)) != 0; |
847 |
} |
848 |
// use extra vector |
849 |
if (this.extra == null) { |
850 |
return false; // if vector not yet allocated, then not initialized |
851 |
} |
852 |
int vectorIndex; |
853 |
if ((vectorIndex = (position / BitCacheSize) - 1) >= |
854 |
this.extra[0].length) { |
855 |
return false; // if not enough room in vector, then not initialized |
856 |
} |
857 |
return (~this.extra[4][vectorIndex] & |
858 |
this.extra[5][vectorIndex] & |
859 |
(1L << (position % BitCacheSize))) != 0; |
860 |
} |
861 |
|
862 |
public void markAsComparedEqualToNonNull(LocalVariableBinding local) { |
863 |
// protected from non-object locals in calling methods |
864 |
if (this != DEAD_END) { |
865 |
this.tagBits |= NULL_FLAG_MASK; |
866 |
int position; |
867 |
long mask; |
868 |
// position is zero-based |
869 |
if ((position = local.id + this.maxFieldCount) < BitCacheSize) { |
461 |
// use bits |
870 |
// use bits |
462 |
return (potentialInits & (1L << position)) != 0; |
871 |
if (((mask = 1L << position) & // leave assigned non null unchanged |
|
|
872 |
this.nullAssignmentStatusBit1 & |
873 |
~this.nullAssignmentStatusBit2 & |
874 |
~this.nullAssignmentValueBit1 & |
875 |
this.nullAssignmentValueBit2) == 0) { |
876 |
// set protected non null |
877 |
this.nullAssignmentStatusBit1 |= mask; |
878 |
this.nullAssignmentStatusBit2 |= mask; |
879 |
// clear potential null |
880 |
this.nullAssignmentValueBit1 &= ~mask; |
881 |
} |
882 |
} |
883 |
else { |
884 |
// use extra vector |
885 |
int vectorIndex = (position / BitCacheSize) - 1; |
886 |
if (this.extra == null) { |
887 |
int length = vectorIndex + 1; |
888 |
this.extra = new long[extraLength][]; |
889 |
for (int j = 0; j < extraLength; j++) { |
890 |
this.extra[j] = new long[length]; |
891 |
} |
892 |
} |
893 |
else { |
894 |
int oldLength; |
895 |
if (vectorIndex >= (oldLength = this.extra[0].length)) { |
896 |
int newLength = vectorIndex + 1; |
897 |
for (int j = 0; j < extraLength; j++) { |
898 |
System.arraycopy(this.extra[j], 0, |
899 |
(this.extra[j] = new long[newLength]), 0, |
900 |
oldLength); |
901 |
} |
902 |
} |
903 |
} |
904 |
if (((mask = 1L << (position % BitCacheSize)) & |
905 |
this.extra[2][vectorIndex] & |
906 |
~this.extra[3][vectorIndex] & |
907 |
~this.extra[4][vectorIndex] & |
908 |
this.extra[5][vectorIndex]) == 0) { |
909 |
this.extra[2][vectorIndex] |= mask; |
910 |
this.extra[3][vectorIndex] |= mask; |
911 |
this.extra[4][vectorIndex] &= ~mask; |
912 |
} |
463 |
} |
913 |
} |
464 |
// use extra vector |
|
|
465 |
if (extraPotentialInits == null) |
466 |
return false; // if vector not yet allocated, then not initialized |
467 |
int vectorIndex; |
468 |
if ((vectorIndex = (position / BitCacheSize) - 1) >= extraPotentialInits.length) |
469 |
return false; // if not enough room in vector, then not initialized |
470 |
return ((extraPotentialInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0; |
471 |
} |
472 |
|
473 |
/** |
474 |
* Check status of definite assignment for a field. |
475 |
*/ |
476 |
final public boolean isPotentiallyAssigned(FieldBinding field) { |
477 |
|
478 |
return isPotentiallyAssigned(field.id); |
479 |
} |
914 |
} |
480 |
|
915 |
} |
481 |
/** |
916 |
|
482 |
* Check status of potential assignment for a local. |
917 |
public void markAsComparedEqualToNull(LocalVariableBinding local) { |
483 |
*/ |
918 |
// protected from non-object locals in calling methods |
484 |
final public boolean isPotentiallyAssigned(LocalVariableBinding local) { |
919 |
if (this != DEAD_END) { |
485 |
|
920 |
this.tagBits |= NULL_FLAG_MASK; |
486 |
// final constants are inlined, and thus considered as always initialized |
921 |
int position; |
487 |
if (local.constant() != Constant.NotAConstant) { |
922 |
long mask, unknownAssigned; |
488 |
return true; |
923 |
// position is zero-based |
|
|
924 |
if ((position = local.id + this.maxFieldCount) < BitCacheSize) { |
925 |
// use bits |
926 |
mask = 1L << position; |
927 |
if ((mask & // leave assigned null unchanged |
928 |
this.nullAssignmentStatusBit1 & |
929 |
~this.nullAssignmentStatusBit2 & |
930 |
this.nullAssignmentValueBit1 & |
931 |
~this.nullAssignmentValueBit2) == 0) { |
932 |
unknownAssigned = this.nullAssignmentStatusBit1 & |
933 |
~this.nullAssignmentStatusBit2 & |
934 |
this.nullAssignmentValueBit1 & |
935 |
this.nullAssignmentValueBit2; |
936 |
// set protected |
937 |
this.nullAssignmentStatusBit2 |= mask; |
938 |
this.nullAssignmentStatusBit1 &= (mask = ~mask); |
939 |
// protected is null |
940 |
this.nullAssignmentValueBit1 &= mask | ~unknownAssigned; |
941 |
this.nullAssignmentValueBit2 &= mask; |
942 |
// clear potential anything but null |
943 |
} |
944 |
} |
945 |
else { |
946 |
// use extra vector |
947 |
int vectorIndex = (position / BitCacheSize) - 1; |
948 |
mask = 1L << (position % BitCacheSize); |
949 |
if (this.extra == null) { |
950 |
int length = vectorIndex + 1; |
951 |
this.extra = new long[extraLength][]; |
952 |
for (int j = 0; j < extraLength; j++) { |
953 |
this.extra[j] = new long[length ]; |
954 |
} |
955 |
} |
956 |
else { |
957 |
int oldLength; |
958 |
if (vectorIndex >= (oldLength = this.extra[0].length)) { |
959 |
int newLength = vectorIndex + 1; |
960 |
for (int j = 0; j < extraLength; j++) { |
961 |
System.arraycopy(this.extra[j], 0, |
962 |
(this.extra[j] = new long[newLength]), 0, |
963 |
oldLength); |
964 |
} |
965 |
} |
966 |
} |
967 |
if ((mask & |
968 |
this.extra[2][vectorIndex] & |
969 |
~this.extra[3][vectorIndex] & |
970 |
this.extra[4][vectorIndex] & |
971 |
~this.extra[5][vectorIndex]) == 0) { |
972 |
unknownAssigned = this.extra[2][vectorIndex] & |
973 |
~this.extra[3][vectorIndex] & |
974 |
this.extra[4][vectorIndex] & |
975 |
this.extra[5][vectorIndex]; |
976 |
this.extra[3][vectorIndex] |= mask; |
977 |
this.extra[2][vectorIndex] &= (mask = ~mask); |
978 |
this.extra[4][vectorIndex] &= mask | ~unknownAssigned; |
979 |
this.extra[5][vectorIndex] &= mask; |
980 |
} |
489 |
} |
981 |
} |
490 |
return isPotentiallyAssigned(local.id + maxFieldCount); |
|
|
491 |
} |
982 |
} |
|
|
983 |
} |
984 |
|
985 |
/** |
986 |
* Record a definite assignment at a given position. |
987 |
* It deals with the dual representation of the InitializationInfo2: |
988 |
* bits for the first 64 entries, then an array of booleans. |
989 |
*/ |
990 |
final private void markAsDefinitelyAssigned(int position) { |
492 |
|
991 |
|
493 |
/** |
992 |
if (this != DEAD_END) { |
494 |
* Record a definite assignment at a given position. |
993 |
// position is zero-based |
495 |
* It deals with the dual representation of the InitializationInfo2: |
994 |
if (position < BitCacheSize) { |
496 |
* bits for the first 64 entries, then an array of booleans. |
995 |
// use bits |
497 |
*/ |
996 |
long mask; |
498 |
final private void markAsDefinitelyAssigned(int position) { |
997 |
this.definiteInits |= (mask = 1L << position); |
499 |
|
998 |
this.potentialInits |= mask; |
500 |
if (this != DEAD_END) { |
999 |
} |
501 |
|
1000 |
else { |
502 |
// position is zero-based |
1001 |
// use extra vector |
503 |
if (position < BitCacheSize) { |
1002 |
int vectorIndex = (position / BitCacheSize) - 1; |
504 |
// use bits |
1003 |
if (this.extra == null) { |
505 |
long mask; |
1004 |
int length = vectorIndex + 1; |
506 |
definiteInits |= (mask = 1L << position); |
1005 |
this.extra = new long[extraLength][]; |
507 |
potentialInits |= mask; |
1006 |
for (int j = 0; j < extraLength; j++) { |
508 |
definiteNulls &= ~mask; |
1007 |
this.extra[j] = new long[length]; |
509 |
definiteNonNulls &= ~mask; |
1008 |
} |
510 |
} else { |
1009 |
} |
511 |
// use extra vector |
1010 |
else { |
512 |
int vectorIndex = (position / BitCacheSize) - 1; |
1011 |
int oldLength; // might need to grow the arrays |
513 |
if (extraDefiniteInits == null) { |
1012 |
if (vectorIndex >= (oldLength = this.extra[0].length)) { |
514 |
int length; |
1013 |
for (int j = 0; j < extraLength; j++) { |
515 |
extraDefiniteInits = new long[length = vectorIndex + 1]; |
1014 |
System.arraycopy(this.extra[j], 0, |
516 |
extraPotentialInits = new long[length]; |
1015 |
(this.extra[j] = new long[vectorIndex + 1]), 0, |
517 |
extraDefiniteNulls = new long[length]; |
1016 |
oldLength); |
518 |
extraDefiniteNonNulls = new long[length]; |
|
|
519 |
} else { |
520 |
int oldLength; // might need to grow the arrays |
521 |
if (vectorIndex >= (oldLength = extraDefiniteInits.length)) { |
522 |
System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[vectorIndex + 1]), 0, oldLength); |
523 |
System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[vectorIndex + 1]), 0, oldLength); |
524 |
System.arraycopy(extraDefiniteNulls, 0, (extraDefiniteNulls = new long[vectorIndex + 1]), 0, oldLength); |
525 |
System.arraycopy(extraDefiniteNonNulls, 0, (extraDefiniteNonNulls = new long[vectorIndex + 1]), 0, oldLength); |
526 |
} |
1017 |
} |
527 |
} |
1018 |
} |
528 |
long mask; |
|
|
529 |
extraDefiniteInits[vectorIndex] |= (mask = 1L << (position % BitCacheSize)); |
530 |
extraPotentialInits[vectorIndex] |= mask; |
531 |
extraDefiniteNulls[vectorIndex] &= ~mask; |
532 |
extraDefiniteNonNulls[vectorIndex] &= ~mask; |
533 |
} |
1019 |
} |
|
|
1020 |
long mask; |
1021 |
this.extra[0][vectorIndex] |= |
1022 |
(mask = 1L << (position % BitCacheSize)); |
1023 |
this.extra[1][vectorIndex] |= mask; |
534 |
} |
1024 |
} |
535 |
} |
1025 |
} |
536 |
|
1026 |
} |
537 |
/** |
1027 |
|
538 |
* Record a field got definitely assigned. |
1028 |
public void markAsDefinitelyAssigned(FieldBinding field) { |
539 |
*/ |
1029 |
if (this != DEAD_END) |
540 |
public void markAsDefinitelyAssigned(FieldBinding field) { |
1030 |
markAsDefinitelyAssigned(field.id); |
541 |
if (this != DEAD_END) |
1031 |
} |
542 |
markAsDefinitelyAssigned(field.id); |
1032 |
|
|
|
1033 |
public void markAsDefinitelyAssigned(LocalVariableBinding local) { |
1034 |
if (this != DEAD_END) |
1035 |
markAsDefinitelyAssigned(local.id + this.maxFieldCount); |
1036 |
} |
1037 |
|
1038 |
/** |
1039 |
* Record a definite non-null assignment at a given position. |
1040 |
*/ |
1041 |
final private void markAsDefinitelyNonNull(int position) { |
1042 |
// DEAD_END guarded above |
1043 |
this.tagBits |= NULL_FLAG_MASK; |
1044 |
long mask; |
1045 |
// position is zero-based |
1046 |
if (position < BitCacheSize) { |
1047 |
// use bits |
1048 |
this.nullAssignmentStatusBit1 |= (mask = 1L << position); |
1049 |
this.nullAssignmentValueBit2 |= mask; // set non null |
1050 |
this.nullAssignmentStatusBit2 &= ~mask; // clear protection |
1051 |
this.nullAssignmentValueBit1 &= ~mask; // clear null |
1052 |
} |
1053 |
else { |
1054 |
// use extra vector |
1055 |
int vectorIndex = (position / BitCacheSize) - 1; |
1056 |
this.extra[2][vectorIndex] |= |
1057 |
(mask = 1L << (position % BitCacheSize)); |
1058 |
this.extra[5][vectorIndex] |= mask; |
1059 |
this.extra[3][vectorIndex] &= ~mask; |
1060 |
this.extra[4][vectorIndex] &= ~mask; |
543 |
} |
1061 |
} |
544 |
|
1062 |
} |
545 |
/** |
1063 |
|
546 |
* Record a local got definitely assigned. |
1064 |
public void markAsDefinitelyNonNull(FieldBinding field) { |
547 |
*/ |
1065 |
if (this != DEAD_END) { |
548 |
public void markAsDefinitelyAssigned(LocalVariableBinding local) { |
1066 |
markAsDefinitelyNonNull(field.id); |
549 |
if (this != DEAD_END) |
|
|
550 |
markAsDefinitelyAssigned(local.id + maxFieldCount); |
551 |
} |
552 |
|
553 |
/** |
554 |
* Record a definite non-null assignment at a given position. |
555 |
* It deals with the dual representation of the InitializationInfo2: |
556 |
* bits for the first 64 entries, then an array of booleans. |
557 |
*/ |
558 |
final private void markAsDefinitelyNonNull(int position) { |
559 |
|
560 |
if (this != DEAD_END) { |
561 |
|
562 |
// position is zero-based |
563 |
if (position < BitCacheSize) { |
564 |
// use bits |
565 |
long mask; |
566 |
definiteNonNulls |= (mask = 1L << position); |
567 |
definiteNulls &= ~mask; |
568 |
} else { |
569 |
// use extra vector |
570 |
int vectorIndex = (position / BitCacheSize) - 1; |
571 |
long mask; |
572 |
extraDefiniteNonNulls[vectorIndex] |= (mask = 1L << (position % BitCacheSize)); |
573 |
extraDefiniteNulls[vectorIndex] &= ~mask; |
574 |
} |
575 |
} |
576 |
} |
1067 |
} |
|
|
1068 |
} |
577 |
|
1069 |
|
578 |
/** |
1070 |
public void markAsDefinitelyNonNull(LocalVariableBinding local) { |
579 |
* Record a field got definitely assigned to non-null value. |
1071 |
// protected from non-object locals in calling methods |
580 |
*/ |
1072 |
if (this != DEAD_END) { |
581 |
public void markAsDefinitelyNonNull(FieldBinding field) { |
1073 |
markAsDefinitelyNonNull(local.id + this.maxFieldCount); |
582 |
if (this != DEAD_END) |
|
|
583 |
markAsDefinitelyNonNull(field.id); |
584 |
} |
1074 |
} |
585 |
|
1075 |
} |
586 |
/** |
1076 |
|
587 |
* Record a local got definitely assigned to non-null value. |
1077 |
/** |
588 |
*/ |
1078 |
* Record a definite null assignment at a given position. |
589 |
public void markAsDefinitelyNonNull(LocalVariableBinding local) { |
1079 |
*/ |
590 |
if (this != DEAD_END) |
1080 |
final private void markAsDefinitelyNull(int position) { |
591 |
markAsDefinitelyNonNull(local.id + maxFieldCount); |
1081 |
// DEAD_END guarded above |
592 |
} |
1082 |
this.tagBits |= NULL_FLAG_MASK; |
593 |
|
1083 |
long mask; |
594 |
/** |
1084 |
if (position < BitCacheSize) { |
595 |
* Record a definite null assignment at a given position. |
1085 |
// use bits |
596 |
* It deals with the dual representation of the InitializationInfo2: |
1086 |
this.nullAssignmentStatusBit1 |= (mask = 1L << position); // set assignment |
597 |
* bits for the first 64 entries, then an array of booleans. |
1087 |
this.nullAssignmentStatusBit2 &= ~mask; // clear protection |
598 |
*/ |
1088 |
this.nullAssignmentValueBit1 |= mask; // set null |
599 |
final private void markAsDefinitelyNull(int position) { |
1089 |
this.nullAssignmentValueBit2 &= ~mask; // clear non null |
600 |
|
1090 |
} |
601 |
if (this != DEAD_END) { |
1091 |
else { |
602 |
|
1092 |
// use extra vector |
603 |
// position is zero-based |
1093 |
int vectorIndex = (position / BitCacheSize) - 1; |
604 |
if (position < BitCacheSize) { |
1094 |
this.extra[2][vectorIndex] |= |
605 |
// use bits |
1095 |
(mask = 1L << (position % BitCacheSize)); |
606 |
long mask; |
1096 |
this.extra[3][vectorIndex] &= ~mask; |
607 |
definiteNulls |= (mask = 1L << position); |
1097 |
this.extra[4][vectorIndex] |= mask; |
608 |
definiteNonNulls &= ~mask; |
1098 |
this.extra[5][vectorIndex] &= ~mask; |
609 |
} else { |
|
|
610 |
// use extra vector |
611 |
int vectorIndex = (position / BitCacheSize) - 1; |
612 |
long mask; |
613 |
extraDefiniteNulls[vectorIndex] |= (mask = 1L << (position % BitCacheSize)); |
614 |
extraDefiniteNonNulls[vectorIndex] &= ~mask; |
615 |
} |
616 |
} |
617 |
} |
1099 |
} |
|
|
1100 |
} |
618 |
|
1101 |
|
619 |
/** |
1102 |
public void markAsDefinitelyNull(FieldBinding field) { |
620 |
* Record a field got definitely assigned to null. |
1103 |
if (this != DEAD_END) { |
621 |
*/ |
1104 |
markAsDefinitelyNull(field.id); |
622 |
public void markAsDefinitelyNull(FieldBinding field) { |
|
|
623 |
if (this != DEAD_END) |
624 |
markAsDefinitelyAssigned(field.id); |
625 |
} |
1105 |
} |
626 |
|
1106 |
} |
627 |
/** |
1107 |
|
628 |
* Record a local got definitely assigned to null. |
1108 |
public void markAsDefinitelyNull(LocalVariableBinding local) { |
629 |
*/ |
1109 |
// protected from non-object locals in calling methods |
630 |
public void markAsDefinitelyNull(LocalVariableBinding local) { |
1110 |
if (this != DEAD_END) { |
631 |
if (this != DEAD_END) |
1111 |
markAsDefinitelyNull(local.id + this.maxFieldCount); |
632 |
markAsDefinitelyNull(local.id + maxFieldCount); |
|
|
633 |
} |
1112 |
} |
634 |
|
1113 |
} |
635 |
/** |
1114 |
|
636 |
* Clear initialization information at a given position. |
1115 |
/** |
637 |
* It deals with the dual representation of the InitializationInfo2: |
1116 |
* Mark a local as having been assigned to an unknown value. |
638 |
* bits for the first 64 entries, then an array of booleans. |
1117 |
* @param local the local to mark |
639 |
*/ |
1118 |
*/ |
640 |
final private void markAsDefinitelyNotAssigned(int position) { |
1119 |
// PREMATURE may try to get closer to markAsDefinitelyAssigned, but not |
641 |
if (this != DEAD_END) { |
1120 |
// obvious |
642 |
|
1121 |
public void markAsDefinitelyUnknown(LocalVariableBinding local) { |
643 |
// position is zero-based |
1122 |
// protected from non-object locals in calling methods |
644 |
if (position < BitCacheSize) { |
1123 |
if (this != DEAD_END) { |
645 |
// use bits |
1124 |
this.tagBits |= NULL_FLAG_MASK; |
646 |
long mask; |
1125 |
long mask; |
647 |
definiteInits &= ~(mask = 1L << position); |
1126 |
int position; |
648 |
potentialInits &= ~mask; |
1127 |
// position is zero-based |
649 |
definiteNulls &= ~mask; |
1128 |
if ((position = local.id + this.maxFieldCount) < BitCacheSize) { |
650 |
definiteNonNulls &= ~mask; |
1129 |
// use bits |
651 |
} else { |
1130 |
this.nullAssignmentValueBit1 |= (mask = 1L << position); |
652 |
// use extra vector |
1131 |
this.nullAssignmentValueBit2 |= mask; |
653 |
int vectorIndex = (position / BitCacheSize) - 1; |
1132 |
// set unknown |
654 |
if (extraDefiniteInits == null) { |
1133 |
this.nullAssignmentStatusBit1 |= mask; |
655 |
return; // nothing to do, it was not yet set |
1134 |
// set assignment |
656 |
} |
1135 |
this.nullAssignmentStatusBit2 &= ~mask; |
657 |
// might need to grow the arrays |
1136 |
// clear protection |
658 |
if (vectorIndex >= extraDefiniteInits.length) { |
1137 |
} |
659 |
return; // nothing to do, it was not yet set |
1138 |
else { |
660 |
} |
1139 |
// use extra vector |
661 |
long mask; |
1140 |
int vectorIndex = (position / BitCacheSize) - 1; |
662 |
extraDefiniteInits[vectorIndex] &= ~(mask = 1L << (position % BitCacheSize)); |
1141 |
this.extra[4][vectorIndex] |= |
663 |
extraPotentialInits[vectorIndex] &= ~mask; |
1142 |
(mask = 1L << (position % BitCacheSize)); |
664 |
extraDefiniteNulls[vectorIndex] &= ~mask; |
1143 |
this.extra[5][vectorIndex] |= mask; |
665 |
extraDefiniteNonNulls[vectorIndex] &= ~mask; |
1144 |
this.extra[2][vectorIndex] |= mask; |
666 |
} |
1145 |
this.extra[3][vectorIndex] &= ~mask; |
667 |
} |
1146 |
} |
668 |
} |
1147 |
} |
669 |
|
1148 |
} |
670 |
/** |
1149 |
|
671 |
* Clear the initialization info for a field |
1150 |
public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) { |
672 |
*/ |
1151 |
if ((otherInits.tagBits & UNREACHABLE) != 0 && this != DEAD_END) { |
673 |
public void markAsDefinitelyNotAssigned(FieldBinding field) { |
1152 |
// DEAD_END + unreachable other -> other |
674 |
|
1153 |
return this; |
675 |
if (this != DEAD_END) |
|
|
676 |
markAsDefinitelyNotAssigned(field.id); |
677 |
} |
1154 |
} |
678 |
|
1155 |
if ((this.tagBits & UNREACHABLE) != 0) { |
679 |
/** |
1156 |
return (UnconditionalFlowInfo) otherInits.copy(); // make sure otherInits won't be affected |
680 |
* Clear the initialization info for a local variable |
1157 |
} |
681 |
*/ |
1158 |
|
682 |
|
1159 |
// intersection of definitely assigned variables, |
683 |
public void markAsDefinitelyNotAssigned(LocalVariableBinding local) { |
1160 |
this.definiteInits &= otherInits.definiteInits; |
684 |
|
1161 |
// union of potentially set ones |
685 |
if (this != DEAD_END) |
1162 |
this.potentialInits |= otherInits.potentialInits; |
686 |
markAsDefinitelyNotAssigned(local.id + maxFieldCount); |
1163 |
|
687 |
} |
1164 |
// null combinations |
688 |
|
1165 |
boolean otherHasNulls = (otherInits.tagBits & NULL_FLAG_MASK) != 0, |
689 |
/** |
1166 |
thisHasNulls = false; |
690 |
* Returns the receiver updated in the following way: <ul> |
1167 |
long a1, a2, na2, a3, na3, a4, na4, b1, nb1, b2, nb2, b3, nb3, b4, nb4; |
691 |
* <li> intersection of definitely assigned variables, |
1168 |
if (otherHasNulls) { |
692 |
* <li> union of potentially assigned variables. |
1169 |
this.nullAssignmentStatusBit1 = |
693 |
* </ul> |
1170 |
(a1 = this.nullAssignmentStatusBit1) & |
694 |
*/ |
1171 |
(b1 = otherInits.nullAssignmentStatusBit1) & ( |
695 |
public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) { |
1172 |
(nb4 = ~(b4 = otherInits.nullAssignmentValueBit2)) & |
696 |
|
1173 |
((b2 = otherInits.nullAssignmentStatusBit2) & |
697 |
if (this == DEAD_END) return otherInits; |
1174 |
(nb3 = ~(b3 = otherInits.nullAssignmentValueBit1)) & |
698 |
if (otherInits == DEAD_END) return this; |
1175 |
(na3 = ~(a3 = this.nullAssignmentValueBit1)) & |
699 |
|
1176 |
((a2 = this.nullAssignmentStatusBit2) & |
700 |
if ((this.reachMode & UNREACHABLE) != (otherInits.reachMode & UNREACHABLE)){ |
1177 |
(na4 = ~(a4 = this.nullAssignmentValueBit2)) | a4) | |
701 |
if ((this.reachMode & UNREACHABLE) != 0){ |
1178 |
(na2 = ~a2) & a3 & na4 & (nb2 = ~b2) & b3 ) | |
702 |
return otherInits; |
1179 |
b4 & (na3 & nb3 & (na4 & a2 | a4) | |
703 |
} |
1180 |
na2 & a4 & nb2)); |
704 |
return this; |
1181 |
this.nullAssignmentStatusBit2 = |
705 |
} |
1182 |
a2 & b2 & ~(a1 ^ b1) & (na3 & nb3 | na4 & nb4) | |
706 |
|
1183 |
a1 & b1 & (a2 ^ b2) & na3 & nb3 | |
707 |
// if one branch is not fake reachable, then the merged one is reachable |
1184 |
(a1 & na2 & (nb1 = ~b1) & b2 | ~a1 & a2 & b1 & nb2) & na4 & nb4; |
708 |
this.reachMode &= otherInits.reachMode; |
1185 |
this.nullAssignmentValueBit1 = |
709 |
|
1186 |
b1 & nb2 & nb4 | |
710 |
// intersection of definitely assigned variables, |
1187 |
~a1 & (a3 | |
711 |
this.definiteInits &= otherInits.definiteInits; |
1188 |
a2 & na3 & (b1 | nb2)) | |
712 |
// union of potentially set ones |
1189 |
(a1 | na2) & nb1 & b2 & nb3 | |
713 |
this.potentialInits |= otherInits.potentialInits; |
1190 |
nb1 & b3 | |
714 |
// intersection of definitely null variables, |
1191 |
a1 & na2 & (na4 | |
715 |
this.definiteNulls &= otherInits.definiteNulls; |
1192 |
b1 & nb2 & (a3 | b3)); |
716 |
// intersection of definitely non-null variables, |
1193 |
this.nullAssignmentValueBit2 = |
717 |
this.definiteNonNulls &= otherInits.definiteNonNulls; |
1194 |
a4 | b4; |
718 |
|
1195 |
} |
719 |
// treating extra storage |
1196 |
else { |
720 |
if (this.extraDefiniteInits != null) { |
1197 |
// tune potentials |
721 |
if (otherInits.extraDefiniteInits != null) { |
1198 |
this.nullAssignmentValueBit1 = |
|
|
1199 |
~(~this.nullAssignmentStatusBit1 & |
1200 |
~this.nullAssignmentStatusBit2 & |
1201 |
~this.nullAssignmentValueBit1) & |
1202 |
~(this.nullAssignmentStatusBit1 & |
1203 |
(this.nullAssignmentStatusBit2 | this.nullAssignmentValueBit2)); |
1204 |
// reset assignment and protected |
1205 |
this.nullAssignmentStatusBit1 = |
1206 |
this.nullAssignmentStatusBit2 = 0; |
1207 |
} |
1208 |
thisHasNulls = this.nullAssignmentStatusBit1 != 0 || |
1209 |
this.nullAssignmentStatusBit2 != 0 || |
1210 |
this.nullAssignmentValueBit1 != 0 || |
1211 |
this.nullAssignmentValueBit2 != 0; |
1212 |
|
1213 |
// treating extra storage |
1214 |
if (this.extra != null || otherInits.extra != null) { |
1215 |
int mergeLimit = 0, copyLimit = 0, resetLimit = 0; |
1216 |
if (this.extra != null) { |
1217 |
if (otherInits.extra != null) { |
722 |
// both sides have extra storage |
1218 |
// both sides have extra storage |
723 |
int i = 0, length, otherLength; |
1219 |
int length, otherLength; |
724 |
if ((length = this.extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) { |
1220 |
if ((length = this.extra[0].length) < |
725 |
// current storage is shorter -> grow current (could maybe reuse otherInits extra storage?) |
1221 |
(otherLength = otherInits.extra[0].length)) { |
726 |
System.arraycopy(this.extraDefiniteInits, 0, (this.extraDefiniteInits = new long[otherLength]), 0, length); |
1222 |
// current storage is shorter -> grow current |
727 |
System.arraycopy(this.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, length); |
1223 |
for (int j = 0; j < extraLength; j++) { |
728 |
System.arraycopy(this.extraDefiniteNulls, 0, (this.extraDefiniteNulls = new long[otherLength]), 0, length); |
1224 |
System.arraycopy(this.extra[j], 0, |
729 |
System.arraycopy(this.extraDefiniteNonNulls, 0, (this.extraDefiniteNonNulls = new long[otherLength]), 0, length); |
1225 |
(this.extra[j] = new long[otherLength]), 0, length); |
730 |
while (i < length) { |
|
|
731 |
this.extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i]; |
732 |
this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i]; |
733 |
this.extraDefiniteNulls[i] &= otherInits.extraDefiniteNulls[i]; |
734 |
this.extraDefiniteNonNulls[i] &= otherInits.extraDefiniteNonNulls[i++]; |
735 |
} |
1226 |
} |
736 |
while (i < otherLength) { |
1227 |
mergeLimit = length; |
737 |
this.extraPotentialInits[i] = otherInits.extraPotentialInits[i++]; |
1228 |
copyLimit = otherLength; |
738 |
} |
1229 |
} |
739 |
} else { |
1230 |
else { |
740 |
// current storage is longer |
1231 |
// current storage is longer |
741 |
while (i < otherLength) { |
1232 |
mergeLimit = otherLength; |
742 |
this.extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i]; |
1233 |
resetLimit = length; |
743 |
this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i]; |
|
|
744 |
this.extraDefiniteNulls[i] &= otherInits.extraDefiniteNulls[i]; |
745 |
this.extraDefiniteNonNulls[i] &= otherInits.extraDefiniteNonNulls[i++]; |
746 |
} |
747 |
while (i < length) { |
748 |
this.extraDefiniteInits[i] = 0; |
749 |
this.extraDefiniteNulls[i] = 0; |
750 |
this.extraDefiniteNonNulls[i++] = 0; |
751 |
} |
752 |
} |
1234 |
} |
753 |
} else { |
1235 |
} |
754 |
// no extra storage on otherInits |
1236 |
else { |
755 |
int i = 0, length = this.extraDefiniteInits.length; |
1237 |
resetLimit = this.extra[0].length; |
756 |
while (i < length) { |
|
|
757 |
this.extraDefiniteInits[i] = 0; |
758 |
this.extraDefiniteNulls[i] = 0; |
759 |
this.extraDefiniteNonNulls[i++] = 0; |
760 |
} |
761 |
} |
762 |
} else |
763 |
if (otherInits.extraDefiniteInits != null) { |
764 |
// no storage here, but other has extra storage. |
765 |
int otherLength; |
766 |
this.extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length]; |
767 |
System.arraycopy(otherInits.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, otherLength); |
768 |
this.extraDefiniteNulls = new long[otherLength]; |
769 |
this.extraDefiniteNonNulls = new long[otherLength]; |
770 |
} |
1238 |
} |
771 |
return this; |
1239 |
} |
|
|
1240 |
else if (otherInits.extra != null) { |
1241 |
// no storage here, but other has extra storage. |
1242 |
int otherLength = otherInits.extra[0].length; |
1243 |
this.extra = new long[extraLength][]; |
1244 |
for (int j = 0; j < extraLength; j++) { |
1245 |
this.extra[j] = new long[otherLength]; |
1246 |
} |
1247 |
System.arraycopy(otherInits.extra[1], 0, |
1248 |
this.extra[1], 0, otherLength); |
1249 |
copyLimit = otherLength; |
1250 |
} |
1251 |
int i; |
1252 |
if (otherHasNulls) { |
1253 |
for (i = 0; i < mergeLimit; i++) { |
1254 |
this.extra[2][i] = |
1255 |
(a1 = this.extra[2][i]) & |
1256 |
(b1 = otherInits.extra[2][i]) & ( |
1257 |
(nb4 = ~(b4 = otherInits.extra[5][i])) & |
1258 |
((b2 = otherInits.extra[3][i]) & |
1259 |
(nb3 = ~(b3 = otherInits.extra[4][i])) & |
1260 |
(na3 = ~(a3 = this.extra[4][i])) & |
1261 |
((a2 = this.extra[3][i]) & |
1262 |
(na4 = ~(a4 = this.extra[5][i])) | a4) | |
1263 |
(na2 = ~a2) & a3 & na4 & (nb2 = ~b2) & b3 ) | |
1264 |
b4 & (na3 & nb3 & (na4 & a2 | a4) | |
1265 |
na2 & a4 & nb2)); |
1266 |
this.extra[3][i] = |
1267 |
a2 & b2 & ~(a1 ^ b1) & (na3 & nb3 | na4 & nb4) | |
1268 |
a1 & b1 & (a2 ^ b2) & na3 & nb3 | |
1269 |
(a1 & na2 & (nb1 = ~b1) & b2 | ~a1 & a2 & b1 & nb2) & na4 & nb4; |
1270 |
this.extra[4][i] = |
1271 |
b1 & nb2 & nb4 | |
1272 |
~a1 & (a3 | |
1273 |
a2 & na3 & (b1 | nb2)) | |
1274 |
(a1 | na2) & nb1 & b2 & nb3 | |
1275 |
nb1 & b3 | |
1276 |
a1 & na2 & (na4 | |
1277 |
b1 & nb2 & (a3 | b3)); |
1278 |
this.extra[5][i] = |
1279 |
a4 | b4; |
1280 |
thisHasNulls = thisHasNulls || |
1281 |
this.extra[5][i] != 0 || |
1282 |
this.extra[2][i] != 0 || |
1283 |
this.extra[3][i] != 0 || |
1284 |
this.extra[4][i] != 0; |
1285 |
} |
1286 |
} |
1287 |
else { |
1288 |
for (i = 0; i < mergeLimit; i++) { |
1289 |
this.extra[0][i] &= |
1290 |
otherInits.extra[0][i]; |
1291 |
this.extra[1][i] |= |
1292 |
otherInits.extra[1][i]; |
1293 |
this.extra[4][i] = |
1294 |
~(~this.extra[2][i] & |
1295 |
~this.extra[3][i] & |
1296 |
~this.extra[4][i]) & |
1297 |
~(this.extra[2][i] & |
1298 |
(this.extra[3][i] | |
1299 |
this.extra[5][i])); |
1300 |
this.extra[2][i] = |
1301 |
this.extra[3][i] = 0; |
1302 |
thisHasNulls = thisHasNulls || |
1303 |
this.extra[4][i] != 0 || |
1304 |
this.extra[5][i] != 0; |
1305 |
} |
1306 |
} |
1307 |
for (; i < copyLimit; i++) { |
1308 |
this.extra[1][i] = otherInits.extra[1][i]; |
1309 |
this.extra[4][i] = |
1310 |
~(~otherInits.extra[2][i] & |
1311 |
~otherInits.extra[3][i] & |
1312 |
~otherInits.extra[4][i]) & |
1313 |
~(otherInits.extra[2][i] & |
1314 |
(otherInits.extra[3][i] | |
1315 |
otherInits.extra[5][i])); |
1316 |
this.extra[5][i] = otherInits.extra[5][i]; |
1317 |
thisHasNulls = thisHasNulls || |
1318 |
this.extra[4][i] != 0 || |
1319 |
this.extra[5][i] != 0; |
1320 |
} |
1321 |
for (; i < resetLimit; i++) { |
1322 |
this.extra[4][i] = |
1323 |
~(~this.extra[2][i] & |
1324 |
~this.extra[3][i] & |
1325 |
~this.extra[4][i]) & |
1326 |
~(this.extra[2][i] & |
1327 |
(this.extra[3][i] | |
1328 |
this.extra[5][i])); |
1329 |
this.extra[0][i] = |
1330 |
this.extra[2][i] = |
1331 |
this.extra[3][i] = 0; |
1332 |
thisHasNulls = thisHasNulls || |
1333 |
this.extra[4][i] != 0 || |
1334 |
this.extra[5][i] != 0; |
1335 |
} |
772 |
} |
1336 |
} |
773 |
|
1337 |
if (thisHasNulls) { |
774 |
/* |
1338 |
this.tagBits |= NULL_FLAG_MASK; |
775 |
* Answer the total number of fields in enclosing types of a given type |
1339 |
} |
776 |
*/ |
1340 |
else { |
777 |
static int numberOfEnclosingFields(ReferenceBinding type){ |
1341 |
this.tagBits &= ~NULL_FLAG_MASK; |
778 |
|
1342 |
} |
779 |
int count = 0; |
1343 |
return this; |
|
|
1344 |
} |
1345 |
|
1346 |
/* |
1347 |
* Answer the total number of fields in enclosing types of a given type |
1348 |
*/ |
1349 |
static int numberOfEnclosingFields(ReferenceBinding type){ |
1350 |
int count = 0; |
1351 |
type = type.enclosingType(); |
1352 |
while(type != null) { |
1353 |
count += type.fieldCount(); |
780 |
type = type.enclosingType(); |
1354 |
type = type.enclosingType(); |
781 |
while(type != null) { |
|
|
782 |
count += type.fieldCount(); |
783 |
type = type.enclosingType(); |
784 |
} |
785 |
return count; |
786 |
} |
1355 |
} |
787 |
|
1356 |
return count; |
788 |
public int reachMode(){ |
1357 |
} |
789 |
return this.reachMode; |
1358 |
|
|
|
1359 |
public UnconditionalFlowInfo nullInfoLessUnconditionalCopy() { |
1360 |
if (this == DEAD_END) { |
1361 |
return this; |
790 |
} |
1362 |
} |
791 |
|
1363 |
UnconditionalFlowInfo copy = new UnconditionalFlowInfo(); |
792 |
public FlowInfo setReachMode(int reachMode) { |
1364 |
copy.definiteInits = this.definiteInits; |
793 |
|
1365 |
copy.potentialInits = this.potentialInits; |
794 |
if (this == DEAD_END) return this; // cannot modify DEAD_END |
1366 |
copy.tagBits = this.tagBits & ~NULL_FLAG_MASK; |
795 |
|
1367 |
copy.maxFieldCount = this.maxFieldCount; |
796 |
// reset optional inits when becoming unreachable |
1368 |
if (this.extra != null) { |
797 |
if ((this.reachMode & UNREACHABLE) == 0 && (reachMode & UNREACHABLE) != 0) { |
1369 |
int length; |
|
|
1370 |
copy.extra = new long[extraLength][]; |
1371 |
System.arraycopy(this.extra[0], 0, |
1372 |
(copy.extra[0] = |
1373 |
new long[length = this.extra[0].length]), 0, length); |
1374 |
System.arraycopy(this.extra[1], 0, |
1375 |
(copy.extra[1] = new long[length]), 0, length); |
1376 |
for (int j = 2; j < extraLength; j++) { |
1377 |
copy.extra[j] = new long[length]; |
1378 |
} |
1379 |
} |
1380 |
return copy; |
1381 |
} |
1382 |
|
1383 |
public FlowInfo safeInitsWhenTrue() { |
1384 |
return copy(); |
1385 |
} |
1386 |
|
1387 |
public FlowInfo setReachMode(int reachMode) { |
1388 |
if (reachMode == REACHABLE && this != DEAD_END) { // cannot modify DEAD_END |
1389 |
this.tagBits &= ~UNREACHABLE; |
1390 |
} |
1391 |
else { |
1392 |
if ((this.tagBits & UNREACHABLE) == 0) { |
1393 |
// reset optional inits when becoming unreachable |
1394 |
// see InitializationTest#test090 (and others) |
798 |
this.potentialInits = 0; |
1395 |
this.potentialInits = 0; |
799 |
if (this.extraPotentialInits != null){ |
1396 |
if (this.extra != null) { |
800 |
for (int i = 0, length = this.extraPotentialInits.length; i < length; i++){ |
1397 |
for (int i = 0, length = this.extra[0].length; |
801 |
this.extraPotentialInits[i] = 0; |
1398 |
i < length; i++) { |
|
|
1399 |
this.extra[1][i] = 0; |
802 |
} |
1400 |
} |
803 |
} |
1401 |
} |
804 |
} |
1402 |
} |
805 |
this.reachMode = reachMode; |
1403 |
this.tagBits |= UNREACHABLE; |
806 |
|
|
|
807 |
return this; |
808 |
} |
1404 |
} |
|
|
1405 |
return this; |
1406 |
} |
809 |
|
1407 |
|
810 |
public String toString(){ |
1408 |
public String toString(){ |
811 |
|
1409 |
// PREMATURE consider printing bit fields as 0001 0001 1000 0001... |
812 |
if (this == DEAD_END){ |
1410 |
if (this == DEAD_END){ |
813 |
return "FlowInfo.DEAD_END"; //$NON-NLS-1$ |
1411 |
return "FlowInfo.DEAD_END"; //$NON-NLS-1$ |
814 |
} |
1412 |
} |
815 |
return "FlowInfo<def: "+ this.definiteInits //$NON-NLS-1$ |
1413 |
if ((this.tagBits & NULL_FLAG_MASK) != 0) { |
816 |
+", pot: " + this.potentialInits //$NON-NLS-1$ |
1414 |
if (this.extra == null) { |
817 |
+ ", reachable:" + ((this.reachMode & UNREACHABLE) == 0) //$NON-NLS-1$ |
1415 |
return "FlowInfo<def: " + this.definiteInits //$NON-NLS-1$ |
818 |
+", defNull: " + this.definiteNulls //$NON-NLS-1$ |
1416 |
+", pot: " + this.potentialInits //$NON-NLS-1$ |
819 |
+", defNonNull: " + this.definiteNonNulls //$NON-NLS-1$ |
1417 |
+ ", reachable:" + ((this.tagBits & UNREACHABLE) == 0) //$NON-NLS-1$ |
820 |
+">"; //$NON-NLS-1$ |
1418 |
+", nullS1: " + this.nullAssignmentStatusBit1 //$NON-NLS-1$ |
|
|
1419 |
+", nullS2: " + this.nullAssignmentStatusBit2 //$NON-NLS-1$ |
1420 |
+", nullV1: " + this.nullAssignmentValueBit1 //$NON-NLS-1$ |
1421 |
+", nullV2: " + this.nullAssignmentValueBit2 //$NON-NLS-1$ |
1422 |
+">"; //$NON-NLS-1$ |
1423 |
} |
1424 |
else { |
1425 |
String def = "FlowInfo<def:[" + this.definiteInits, //$NON-NLS-1$ |
1426 |
pot = "], pot:[" + this.potentialInits, //$NON-NLS-1$ |
1427 |
nullS1 = ", nullS1:[" + this.nullAssignmentStatusBit1, //$NON-NLS-1$ |
1428 |
nullS2 = "], nullS2:[" + this.nullAssignmentStatusBit2, //$NON-NLS-1$ |
1429 |
nullV1 = "], nullV1:[" + this.nullAssignmentValueBit1, //$NON-NLS-1$ |
1430 |
nullV2 = "], nullV2:[" + this.nullAssignmentValueBit2; //$NON-NLS-1$ |
1431 |
int i, ceil; |
1432 |
for (i = 0, ceil = this.extra[0].length > 3 ? |
1433 |
3 : |
1434 |
this.extra[0].length; |
1435 |
i < ceil; i++) { |
1436 |
def += "," + this.extra[0][i]; //$NON-NLS-1$ |
1437 |
pot += "," + this.extra[1][i]; //$NON-NLS-1$ |
1438 |
nullS1 += "," + this.extra[2][i]; //$NON-NLS-1$ |
1439 |
nullS2 += "," + this.extra[3][i]; //$NON-NLS-1$ |
1440 |
nullV1 += "," + this.extra[4][i]; //$NON-NLS-1$ |
1441 |
nullV2 += "," + this.extra[5][i]; //$NON-NLS-1$ |
1442 |
} |
1443 |
if (ceil < this.extra[0].length) { |
1444 |
def += ",..."; //$NON-NLS-1$ |
1445 |
pot += ",..."; //$NON-NLS-1$ |
1446 |
nullS1 += ",..."; //$NON-NLS-1$ |
1447 |
nullS2 += ",..."; //$NON-NLS-1$ |
1448 |
nullV1 += ",..."; //$NON-NLS-1$ |
1449 |
nullV2 += ",..."; //$NON-NLS-1$ |
1450 |
} |
1451 |
return def + pot |
1452 |
+ "], reachable:" + ((this.tagBits & UNREACHABLE) == 0) //$NON-NLS-1$ |
1453 |
+ nullS1 + nullS2 + nullV1 + nullV2 |
1454 |
+ "]>"; //$NON-NLS-1$ |
1455 |
} |
1456 |
} |
1457 |
else { |
1458 |
if (this.extra == null) { |
1459 |
return "FlowInfo<def: " + this.definiteInits //$NON-NLS-1$ |
1460 |
+", pot: " + this.potentialInits //$NON-NLS-1$ |
1461 |
+ ", reachable:" + ((this.tagBits & UNREACHABLE) == 0) //$NON-NLS-1$ |
1462 |
+", no null info>"; //$NON-NLS-1$ |
1463 |
} |
1464 |
else { |
1465 |
String def = "FlowInfo<def:[" + this.definiteInits, //$NON-NLS-1$ |
1466 |
pot = "], pot:[" + this.potentialInits; //$NON-NLS-1$ |
1467 |
int i, ceil; |
1468 |
for (i = 0, ceil = this.extra[0].length > 3 ? |
1469 |
3 : |
1470 |
this.extra[0].length; |
1471 |
i < ceil; i++) { |
1472 |
def += "," + this.extra[0][i]; //$NON-NLS-1$ |
1473 |
pot += "," + this.extra[1][i]; //$NON-NLS-1$ |
1474 |
} |
1475 |
if (ceil < this.extra[0].length) { |
1476 |
def += ",..."; //$NON-NLS-1$ |
1477 |
pot += ",..."; //$NON-NLS-1$ |
1478 |
} |
1479 |
return def + pot |
1480 |
+ "], reachable:" + ((this.tagBits & UNREACHABLE) == 0) //$NON-NLS-1$ |
1481 |
+ ", no null info>"; //$NON-NLS-1$ |
1482 |
} |
821 |
} |
1483 |
} |
|
|
1484 |
} |
1485 |
|
1486 |
public UnconditionalFlowInfo unconditionalCopy() { |
1487 |
return (UnconditionalFlowInfo) copy(); |
1488 |
} |
822 |
|
1489 |
|
823 |
public UnconditionalFlowInfo unconditionalInits() { |
1490 |
public UnconditionalFlowInfo unconditionalFieldLessCopy() { |
824 |
|
1491 |
// TODO (maxime) may consider leveraging null contribution verification as it is done in copy |
825 |
// also see conditional inits, where it requests them to merge |
1492 |
UnconditionalFlowInfo copy = new UnconditionalFlowInfo(); |
826 |
return this; |
1493 |
copy.tagBits = this.tagBits; |
|
|
1494 |
copy.maxFieldCount = this.maxFieldCount; |
1495 |
int limit = this.maxFieldCount; |
1496 |
if (limit < BitCacheSize) { |
1497 |
long mask; |
1498 |
copy.definiteInits = this.definiteInits & (mask = ~((1L << limit)-1)); |
1499 |
copy.potentialInits = this.potentialInits & mask; |
1500 |
copy.nullAssignmentStatusBit1 = this.nullAssignmentStatusBit1 & mask; |
1501 |
copy.nullAssignmentStatusBit2 = this.nullAssignmentStatusBit2 & mask; |
1502 |
copy.nullAssignmentValueBit1 = this.nullAssignmentValueBit1 & mask; |
1503 |
copy.nullAssignmentValueBit2 = this.nullAssignmentValueBit2 & mask; |
1504 |
} |
1505 |
// use extra vector |
1506 |
if (this.extra == null) { |
1507 |
return copy; // if vector not yet allocated, then not initialized |
1508 |
} |
1509 |
int vectorIndex, length, copyStart; |
1510 |
if ((vectorIndex = (limit / BitCacheSize) - 1) >= |
1511 |
(length = this.extra[0].length)) { |
1512 |
return copy; // not enough room yet |
1513 |
} |
1514 |
long mask; |
1515 |
copy.extra = new long[extraLength][]; |
1516 |
if ((copyStart = vectorIndex + 1) < length) { |
1517 |
int copyLength = length - copyStart; |
1518 |
for (int j = 0; j < extraLength; j++) { |
1519 |
System.arraycopy(this.extra[j], copyStart, |
1520 |
(copy.extra[j] = new long[length]), copyStart, |
1521 |
copyLength); |
1522 |
} |
1523 |
} |
1524 |
else if (vectorIndex >= 0) { |
1525 |
for (int j = 0; j < extraLength; j++) { |
1526 |
copy.extra[j] = new long[length]; |
1527 |
} |
1528 |
} |
1529 |
if (vectorIndex >= 0) { |
1530 |
mask = ~((1L << (limit % BitCacheSize))-1); |
1531 |
for (int j = 0; j < extraLength; j++) { |
1532 |
copy.extra[j][vectorIndex] = |
1533 |
this.extra[j][vectorIndex] & mask; |
1534 |
} |
827 |
} |
1535 |
} |
|
|
1536 |
return copy; |
1537 |
} |
1538 |
|
1539 |
public UnconditionalFlowInfo unconditionalInits() { |
1540 |
// also see conditional inits, where it requests them to merge |
1541 |
return this; |
1542 |
} |
1543 |
|
1544 |
public UnconditionalFlowInfo unconditionalInitsWithoutSideEffect() { |
1545 |
return this; |
1546 |
} |
828 |
} |
1547 |
} |