Mercurial > hg > Members > kono > jpf-core
comparison src/main/gov/nasa/jpf/vm/GenericSharednessPolicy.java @ 0:61d41facf527
initial v8 import (history reset)
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Fri, 23 Jan 2015 10:14:01 -0800 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:61d41facf527 |
---|---|
1 /* | |
2 * Copyright (C) 2014, United States Government, as represented by the | |
3 * Administrator of the National Aeronautics and Space Administration. | |
4 * All rights reserved. | |
5 * | |
6 * The Java Pathfinder core (jpf-core) platform is licensed under the | |
7 * Apache License, Version 2.0 (the "License"); you may not use this file except | |
8 * in compliance with the License. You may obtain a copy of the License at | |
9 * | |
10 * http://www.apache.org/licenses/LICENSE-2.0. | |
11 * | |
12 * Unless required by applicable law or agreed to in writing, software | |
13 * distributed under the License is distributed on an "AS IS" BASIS, | |
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 * See the License for the specific language governing permissions and | |
16 * limitations under the License. | |
17 */ | |
18 | |
19 package gov.nasa.jpf.vm; | |
20 | |
21 import gov.nasa.jpf.Config; | |
22 import gov.nasa.jpf.JPF; | |
23 import gov.nasa.jpf.SystemAttribute; | |
24 import gov.nasa.jpf.util.FieldSpecMatcher; | |
25 import gov.nasa.jpf.util.JPFLogger; | |
26 import gov.nasa.jpf.util.MethodSpecMatcher; | |
27 import gov.nasa.jpf.util.TypeSpecMatcher; | |
28 import gov.nasa.jpf.vm.choice.ThreadChoiceFromSet; | |
29 | |
30 /** | |
31 * an abstract SharednessPolicy implementation that makes use of both | |
32 * shared field access CGs and exposure CGs. | |
33 * | |
34 * This class is highly configurable, both in terms of using exposure CGs and filters. | |
35 * The *never_break filters should be used with care to avoid missing defects, especially | |
36 * the (transitive) method filters. | |
37 * NOTE - the default settings from jpf-core/jpf.properties include several | |
38 * java.util.concurrent* and java.lang.* fields/methods that can in fact contribute to | |
39 * concurrency defects, esp. in SUTs that explicitly use Thread/ThreadGroup objects, in | |
40 * which case they should be removed. | |
41 * | |
42 * The *always_break field filter should only be used for white box SUT analysis if JPF | |
43 * fails to detect sharedness (e.g. because no exposure is used). This should only | |
44 * go into application property files | |
45 */ | |
46 public abstract class GenericSharednessPolicy implements SharednessPolicy, Attributor { | |
47 | |
48 //--- auxiliary types to configure filters | |
49 static class NeverBreakIn implements SystemAttribute { | |
50 static NeverBreakIn singleton = new NeverBreakIn(); | |
51 } | |
52 static class NeverBreakOn implements SystemAttribute { | |
53 static NeverBreakOn singleton = new NeverBreakOn(); | |
54 } | |
55 static class AlwaysBreakOn implements SystemAttribute { | |
56 static AlwaysBreakOn singleton = new AlwaysBreakOn(); | |
57 } | |
58 | |
59 protected static JPFLogger logger = JPF.getLogger("shared"); | |
60 | |
61 | |
62 //--- options used for concurrent field access detection | |
63 | |
64 protected TypeSpecMatcher neverBreakOnTypes; | |
65 | |
66 protected TypeSpecMatcher alwaysBreakOnTypes; | |
67 | |
68 /** | |
69 * never break or expose if a matching method is on the stack | |
70 */ | |
71 protected MethodSpecMatcher neverBreakInMethods; | |
72 | |
73 /** | |
74 * never break on matching fields | |
75 */ | |
76 protected FieldSpecMatcher neverBreakOnFields; | |
77 | |
78 /** | |
79 * always break matching fields, no matter if object is already shared or not | |
80 */ | |
81 protected FieldSpecMatcher alwaysBreakOnFields; | |
82 | |
83 | |
84 /** | |
85 * do we break on final field access | |
86 */ | |
87 protected boolean skipFinals; | |
88 protected boolean skipConstructedFinals; | |
89 protected boolean skipStaticFinals; | |
90 | |
91 /** | |
92 * do we break inside of constructors | |
93 * (note that 'this' references could leak from ctors, but | |
94 * this is rather unusual) | |
95 */ | |
96 protected boolean skipInits; | |
97 | |
98 /** | |
99 * do we add CGs for objects that could become shared, e.g. when storing | |
100 * a reference to a non-shared object in a shared object field. | |
101 * NOTE: this is a conservative measure since we don't know yet at the | |
102 * point of exposure if the object will ever be shared, which means it | |
103 * can cause state explosion. | |
104 */ | |
105 protected boolean breakOnExposure; | |
106 | |
107 /** | |
108 * options to filter out lock protected field access, which is not | |
109 * supposed to cause shared CGs | |
110 * (this has no effect on exposure though) | |
111 */ | |
112 protected boolean useSyncDetection; | |
113 protected int lockThreshold; | |
114 | |
115 protected VM vm; | |
116 | |
117 | |
118 protected GenericSharednessPolicy (Config config){ | |
119 neverBreakInMethods = MethodSpecMatcher.create( config.getStringArray("vm.shared.never_break_methods")); | |
120 | |
121 neverBreakOnTypes = TypeSpecMatcher.create(config.getStringArray("vm.shared.never_break_types")); | |
122 alwaysBreakOnTypes = TypeSpecMatcher.create(config.getStringArray("vm.shared.always_break_types")); | |
123 | |
124 neverBreakOnFields = FieldSpecMatcher.create( config.getStringArray("vm.shared.never_break_fields")); | |
125 alwaysBreakOnFields = FieldSpecMatcher.create( config.getStringArray("vm.shared.always_break_fields")); | |
126 | |
127 skipFinals = config.getBoolean("vm.shared.skip_finals", true); | |
128 skipConstructedFinals = config.getBoolean("vm.shared.skip_constructed_finals", false); | |
129 skipStaticFinals = config.getBoolean("vm.shared.skip_static_finals", true); | |
130 skipInits = config.getBoolean("vm.shared.skip_inits", true); | |
131 | |
132 breakOnExposure = config.getBoolean("vm.shared.break_on_exposure", true); | |
133 | |
134 useSyncDetection = config.getBoolean("vm.shared.sync_detection", true); | |
135 lockThreshold = config.getInt("vm.shared.lockthreshold", 5); | |
136 } | |
137 | |
138 //--- internal methods (potentially overridden by subclass) | |
139 | |
140 | |
141 //--- attribute management | |
142 | |
143 protected void setTypeAttributes (TypeSpecMatcher neverMatcher, TypeSpecMatcher alwaysMatcher, ClassInfo ciLoaded){ | |
144 // we flatten this for performance reasons | |
145 for (ClassInfo ci = ciLoaded; ci!= null; ci = ci.getSuperClass()){ | |
146 if (alwaysMatcher != null && alwaysMatcher.matches(ci)){ | |
147 ciLoaded.addAttr(AlwaysBreakOn.singleton); | |
148 return; | |
149 } | |
150 if (neverMatcher != null && neverMatcher.matches(ci)){ | |
151 ciLoaded.addAttr( NeverBreakOn.singleton); | |
152 return; | |
153 } | |
154 } | |
155 } | |
156 | |
157 protected void setFieldAttributes (FieldSpecMatcher neverMatcher, FieldSpecMatcher alwaysMatcher, ClassInfo ci){ | |
158 for (FieldInfo fi : ci.getDeclaredInstanceFields()) { | |
159 // invisible fields (created by compiler) | |
160 if (fi.getName().startsWith("this$")) { | |
161 fi.addAttr( NeverBreakOn.singleton); | |
162 continue; | |
163 } | |
164 | |
165 // configuration | |
166 if (neverMatcher != null && neverMatcher.matches(fi)) { | |
167 fi.addAttr( NeverBreakOn.singleton); | |
168 } | |
169 if (alwaysMatcher != null && alwaysMatcher.matches(fi)) { | |
170 fi.addAttr( AlwaysBreakOn.singleton); | |
171 } | |
172 | |
173 // annotation | |
174 if (fi.hasAnnotation("gov.nasa.jpf.annotation.NeverBreak")){ | |
175 fi.addAttr( NeverBreakOn.singleton); | |
176 } | |
177 } | |
178 | |
179 for (FieldInfo fi : ci.getDeclaredStaticFields()) { | |
180 // invisible fields (created by compiler) | |
181 if ("$assertionsDisabled".equals(fi.getName())) { | |
182 fi.addAttr( NeverBreakOn.singleton); | |
183 continue; | |
184 } | |
185 | |
186 // configuration | |
187 if (neverMatcher != null && neverMatcher.matches(fi)) { | |
188 fi.addAttr( NeverBreakOn.singleton); | |
189 } | |
190 if (alwaysMatcher != null && alwaysMatcher.matches(fi)) { | |
191 fi.addAttr( AlwaysBreakOn.singleton); | |
192 } | |
193 | |
194 // annotation | |
195 if (fi.hasAnnotation("gov.nasa.jpf.annotation.NeverBreak")){ | |
196 fi.addAttr( NeverBreakOn.singleton); | |
197 } | |
198 } | |
199 } | |
200 | |
201 protected boolean isInNeverBreakMethod (ThreadInfo ti){ | |
202 for (StackFrame frame = ti.getTopFrame(); frame != null; frame=frame.getPrevious()){ | |
203 MethodInfo mi = frame.getMethodInfo(); | |
204 if (mi.hasAttr( NeverBreakIn.class)){ | |
205 return true; | |
206 } | |
207 } | |
208 | |
209 return false; | |
210 } | |
211 | |
212 protected abstract boolean checkOtherRunnables (ThreadInfo ti); | |
213 | |
214 // this needs a three-way return value, hence Boolean | |
215 protected Boolean canHaveSharednessCG (ThreadInfo ti, Instruction insn, ElementInfo eiFieldOwner, FieldInfo fi){ | |
216 //--- thread | |
217 if (ti.isFirstStepInsn()){ // no empty transitions | |
218 return Boolean.FALSE; | |
219 } | |
220 | |
221 if (!checkOtherRunnables(ti)){ // nothing to reschedule | |
222 return Boolean.FALSE; | |
223 } | |
224 | |
225 if (ti.hasAttr( NeverBreakIn.class)){ | |
226 return Boolean.FALSE; | |
227 } | |
228 | |
229 //--- method | |
230 if (isInNeverBreakMethod(ti)){ | |
231 return false; | |
232 } | |
233 | |
234 //--- type | |
235 ClassInfo ciFieldOwner = eiFieldOwner.getClassInfo(); | |
236 if (ciFieldOwner.hasAttr(NeverBreakOn.class)){ | |
237 return Boolean.FALSE; | |
238 } | |
239 if (ciFieldOwner.hasAttr(AlwaysBreakOn.class)){ | |
240 return Boolean.TRUE; | |
241 } | |
242 | |
243 //--- field | |
244 if (fi != null){ | |
245 if (fi.hasAttr(AlwaysBreakOn.class)) { | |
246 return Boolean.TRUE; | |
247 } | |
248 if (fi.hasAttr(NeverBreakOn.class)) { | |
249 return Boolean.FALSE; | |
250 } | |
251 } | |
252 | |
253 return null; | |
254 } | |
255 | |
256 //--- FieldLockInfo management | |
257 | |
258 /** | |
259 * static attribute filters that determine if the check..Access() and check..Exposure() methods should be called. | |
260 * This is only called once per instruction execution since it filters all cases that would set a CG. | |
261 * Filter conditions have to apply to both field access and object exposure. | |
262 */ | |
263 protected abstract FieldLockInfo createFieldLockInfo (ThreadInfo ti, ElementInfo ei, FieldInfo fi); | |
264 | |
265 | |
266 /** | |
267 * generic version of FieldLockInfo update, which relies on FieldLockInfo implementation to determine | |
268 * if ElementInfo needs to be cloned | |
269 */ | |
270 protected ElementInfo updateFieldLockInfo (ThreadInfo ti, ElementInfo ei, FieldInfo fi){ | |
271 FieldLockInfo fli = ei.getFieldLockInfo(fi); | |
272 if (fli == null){ | |
273 fli = createFieldLockInfo(ti, ei, fi); | |
274 ei = ei.getModifiableInstance(); | |
275 ei.setFieldLockInfo(fi, fli); | |
276 | |
277 } else { | |
278 FieldLockInfo newFli = fli.checkProtection(ti, ei, fi); | |
279 if (newFli != fli) { | |
280 ei = ei.getModifiableInstance(); | |
281 ei.setFieldLockInfo(fi,newFli); | |
282 } | |
283 } | |
284 | |
285 return ei; | |
286 } | |
287 | |
288 | |
289 //--- runnable computation & CG creation | |
290 | |
291 // NOTE - we don't schedule threads outside this process since field access if process local | |
292 | |
293 protected ThreadInfo[] getRunnables (ApplicationContext appCtx){ | |
294 return vm.getThreadList().getProcessTimeoutRunnables(appCtx); | |
295 } | |
296 | |
297 protected ChoiceGenerator<ThreadInfo> getRunnableCG (String id, ThreadInfo tiCurrent){ | |
298 if (vm.getSystemState().isAtomic()){ // no CG if we are in a atomic section | |
299 return null; | |
300 } | |
301 | |
302 ThreadInfo[] choices = getRunnables(tiCurrent.getApplicationContext()); | |
303 if (choices.length <= 1){ // field access doesn't block, i.e. the current thread is always runnable | |
304 return null; | |
305 } | |
306 | |
307 return new ThreadChoiceFromSet( id, choices, true); | |
308 } | |
309 | |
310 protected boolean setNextChoiceGenerator (ChoiceGenerator<ThreadInfo> cg){ | |
311 if (cg != null){ | |
312 return vm.getSystemState().setNextChoiceGenerator(cg); // listeners could still remove CGs | |
313 } | |
314 | |
315 return false; | |
316 } | |
317 | |
318 | |
319 //--- internal policy methods that can be overridden by subclasses | |
320 | |
321 protected ElementInfo updateSharedness (ThreadInfo ti, ElementInfo ei, FieldInfo fi){ | |
322 ThreadInfoSet tis = ei.getReferencingThreads(); | |
323 ThreadInfoSet newTis = tis.add(ti); | |
324 | |
325 if (tis != newTis){ | |
326 ei = ei.getModifiableInstance(); | |
327 ei.setReferencingThreads(newTis); | |
328 } | |
329 | |
330 // we only change from non-shared to shared | |
331 if (newTis.isShared(ti, ei) && !ei.isShared() && !ei.isSharednessFrozen()) { | |
332 ei = ei.getModifiableInstance(); | |
333 ei.setShared(ti, true); | |
334 } | |
335 | |
336 if (ei.isShared() && fi != null){ | |
337 ei = updateFieldLockInfo(ti,ei,fi); | |
338 } | |
339 | |
340 return ei; | |
341 } | |
342 | |
343 protected boolean setsExposureCG (ThreadInfo ti, Instruction insn, ElementInfo eiFieldOwner, FieldInfo fi, ElementInfo eiExposed){ | |
344 if (breakOnExposure){ | |
345 ClassInfo ciExposed = eiExposed.getClassInfo(); | |
346 | |
347 //--- exposed type | |
348 if (ciExposed.hasAttr(NeverBreakOn.class)){ | |
349 return false; | |
350 } | |
351 if (ciExposed.hasAttr(AlwaysBreakOn.class)){ | |
352 logger.info("type exposure CG setting field ", fi, " to ", eiExposed); | |
353 return setNextChoiceGenerator(getRunnableCG("EXPOSE", ti)); | |
354 } | |
355 | |
356 // we can't filter on immutability since the race subject could be a reference | |
357 // that is exposed through the exposed object | |
358 | |
359 if (isInNeverBreakMethod(ti)){ | |
360 return false; | |
361 } | |
362 | |
363 if (eiFieldOwner.isExposedOrShared() && isFirstExposure(eiFieldOwner, eiExposed)){ | |
364 // don't check against the 'old' field value because this might get called after the field was already updated | |
365 // we should solely depend on different object sharedness | |
366 eiExposed = eiExposed.getExposedInstance(ti, eiFieldOwner); | |
367 logger.info("exposure CG setting field ", fi, " to ", eiExposed); | |
368 return setNextChoiceGenerator(getRunnableCG("EXPOSE", ti)); | |
369 } | |
370 } | |
371 | |
372 return false; | |
373 } | |
374 | |
375 protected boolean isFirstExposure (ElementInfo eiFieldOwner, ElementInfo eiExposed){ | |
376 if (!eiExposed.isImmutable()){ | |
377 if (!eiExposed.isExposedOrShared()) { | |
378 return (eiFieldOwner.isExposedOrShared()); | |
379 } | |
380 } | |
381 | |
382 return false; | |
383 } | |
384 | |
385 | |
386 //------------------------------------------------ Attributor interface | |
387 | |
388 /** | |
389 * this can be used to initializeSharednessPolicy per-application mechanisms such as ClassInfo attribution | |
390 */ | |
391 @Override | |
392 public void initializeSharednessPolicy (VM vm, ApplicationContext appCtx){ | |
393 this.vm = vm; | |
394 | |
395 SystemClassLoaderInfo sysCl = appCtx.getSystemClassLoader(); | |
396 sysCl.addAttributor(this); | |
397 } | |
398 | |
399 | |
400 @Override | |
401 public void setAttributes (ClassInfo ci){ | |
402 setTypeAttributes( neverBreakOnTypes, alwaysBreakOnTypes, ci); | |
403 | |
404 setFieldAttributes( neverBreakOnFields, alwaysBreakOnFields, ci); | |
405 | |
406 // this one is more expensive to iterate over and should be avoided | |
407 if (neverBreakInMethods != null){ | |
408 for (MethodInfo mi : ci.getDeclaredMethods().values()){ | |
409 if (neverBreakInMethods.matches(mi)){ | |
410 mi.setAttr( NeverBreakIn.singleton); | |
411 } | |
412 } | |
413 } | |
414 | |
415 } | |
416 | |
417 //------------------------------------------------ SharednessPolicy interface | |
418 | |
419 @Override | |
420 public ElementInfo updateObjectSharedness (ThreadInfo ti, ElementInfo ei, FieldInfo fi){ | |
421 return updateSharedness(ti, ei, fi); | |
422 } | |
423 @Override | |
424 public ElementInfo updateClassSharedness (ThreadInfo ti, ElementInfo ei, FieldInfo fi){ | |
425 return updateSharedness(ti, ei, fi); | |
426 } | |
427 @Override | |
428 public ElementInfo updateArraySharedness (ThreadInfo ti, ElementInfo ei, int idx){ | |
429 // NOTE - we don't support per-element FieldLockInfos (yet) | |
430 return updateSharedness(ti, ei, null); | |
431 } | |
432 | |
433 | |
434 /** | |
435 * check to determine if call site, object/class attributes and thread execution state | |
436 * could cause CGs. This is called before sharedness is updated, i.e. can be used to | |
437 * filter objects/classes that should not be sharedness tracked | |
438 */ | |
439 @Override | |
440 public boolean canHaveSharedObjectCG (ThreadInfo ti, Instruction insn, ElementInfo eiFieldOwner, FieldInfo fi){ | |
441 Boolean ret = canHaveSharednessCG( ti, insn, eiFieldOwner, fi); | |
442 if (ret != null){ | |
443 return ret; | |
444 } | |
445 | |
446 if (eiFieldOwner.isImmutable()){ | |
447 return false; | |
448 } | |
449 | |
450 if (skipFinals && fi.isFinal()){ | |
451 return false; | |
452 } | |
453 | |
454 //--- mixed (dynamic) attributes | |
455 if (skipConstructedFinals && fi.isFinal() && eiFieldOwner.isConstructed()){ | |
456 return false; | |
457 } | |
458 | |
459 if (skipInits && insn.getMethodInfo().isInit()){ | |
460 return false; | |
461 } | |
462 | |
463 return true; | |
464 } | |
465 | |
466 @Override | |
467 public boolean canHaveSharedClassCG (ThreadInfo ti, Instruction insn, ElementInfo eiFieldOwner, FieldInfo fi){ | |
468 Boolean ret = canHaveSharednessCG( ti, insn, eiFieldOwner, fi); | |
469 if (ret != null){ | |
470 return ret; | |
471 } | |
472 | |
473 if (eiFieldOwner.isImmutable()){ | |
474 return false; | |
475 } | |
476 | |
477 if (skipStaticFinals && fi.isFinal()){ | |
478 return false; | |
479 } | |
480 | |
481 // call site. This could be transitive, in which case it has to be dynamic and can't be moved to isRelevant..() | |
482 MethodInfo mi = insn.getMethodInfo(); | |
483 if (mi.isClinit() && (fi.getClassInfo() == mi.getClassInfo())) { | |
484 // clinits are all synchronized, so they are lock protected per se | |
485 return false; | |
486 } | |
487 | |
488 return true; | |
489 } | |
490 | |
491 @Override | |
492 public boolean canHaveSharedArrayCG (ThreadInfo ti, Instruction insn, ElementInfo eiArray, int idx){ | |
493 Boolean ret = canHaveSharednessCG( ti, insn, eiArray, null); | |
494 if (ret != null){ | |
495 return ret; | |
496 } | |
497 | |
498 // more array specific checks here | |
499 | |
500 return true; | |
501 } | |
502 | |
503 | |
504 /** | |
505 * <2do> explain why not transitive | |
506 * | |
507 * these are the public interfaces towards FieldInstructions. Callers have to be aware this will | |
508 * change the /referenced/ ElementInfo in case the respective object becomes exposed | |
509 */ | |
510 @Override | |
511 public boolean setsSharedObjectCG (ThreadInfo ti, Instruction insn, ElementInfo eiFieldOwner, FieldInfo fi){ | |
512 if (eiFieldOwner.getClassInfo().hasAttr(AlwaysBreakOn.class) || | |
513 (eiFieldOwner.isShared() && !eiFieldOwner.isLockProtected(fi))) { | |
514 logger.info("CG accessing shared instance field ", fi); | |
515 return setNextChoiceGenerator( getRunnableCG("SHARED_OBJECT", ti)); | |
516 } | |
517 | |
518 return false; | |
519 } | |
520 | |
521 @Override | |
522 public boolean setsSharedClassCG (ThreadInfo ti, Instruction insn, ElementInfo eiFieldOwner, FieldInfo fi){ | |
523 if (eiFieldOwner.getClassInfo().hasAttr(AlwaysBreakOn.class) || | |
524 (eiFieldOwner.isShared() && !eiFieldOwner.isLockProtected(fi))) { | |
525 logger.info("CG accessing shared static field ", fi); | |
526 return setNextChoiceGenerator( getRunnableCG("SHARED_CLASS", ti)); | |
527 } | |
528 | |
529 return false; | |
530 } | |
531 | |
532 @Override | |
533 public boolean setsSharedArrayCG (ThreadInfo ti, Instruction insn, ElementInfo eiArray, int index){ | |
534 if (eiArray.isShared()){ | |
535 // <2do> we should check lock protection for the whole array here | |
536 logger.info("CG accessing shared array ", eiArray); | |
537 return setNextChoiceGenerator( getRunnableCG("SHARED_ARRAY", ti)); | |
538 } | |
539 | |
540 return false; | |
541 } | |
542 | |
543 | |
544 //--- internal policy methods that can be overridden by subclasses | |
545 | |
546 protected boolean isRelevantStaticFieldAccess (ThreadInfo ti, Instruction insn, ElementInfo ei, FieldInfo fi){ | |
547 if (!ei.isShared()){ | |
548 return false; | |
549 } | |
550 | |
551 if (ei.isImmutable()){ | |
552 return false; | |
553 } | |
554 | |
555 if (skipStaticFinals && fi.isFinal()){ | |
556 return false; | |
557 } | |
558 | |
559 if (!ti.hasOtherRunnables()){ // nothing to break for | |
560 return false; | |
561 } | |
562 | |
563 // call site. This could be transitive, in which case it has to be dynamic and can't be moved to isRelevant..() | |
564 MethodInfo mi = insn.getMethodInfo(); | |
565 if (mi.isClinit() && (fi.getClassInfo() == mi.getClassInfo())) { | |
566 // clinits are all synchronized, so they are lock protected per se | |
567 return false; | |
568 } | |
569 | |
570 return true; | |
571 } | |
572 | |
573 | |
574 protected boolean isRelevantArrayAccess (ThreadInfo ti, Instruction insn, ElementInfo ei, int index){ | |
575 // <2do> this is too simplistic, we should support filters for array objects | |
576 | |
577 if (!ti.hasOtherRunnables()){ | |
578 return false; | |
579 } | |
580 | |
581 if (!ei.isShared()){ | |
582 return false; | |
583 } | |
584 | |
585 if (ti.isFirstStepInsn()){ // we already did break | |
586 return false; | |
587 } | |
588 | |
589 return true; | |
590 } | |
591 | |
592 //--- object exposure | |
593 | |
594 // <2do> explain why not transitive | |
595 | |
596 @Override | |
597 public boolean setsSharedObjectExposureCG (ThreadInfo ti, Instruction insn, ElementInfo eiFieldOwner, FieldInfo fi, ElementInfo eiExposed){ | |
598 return setsExposureCG(ti,insn,eiFieldOwner,fi,eiExposed); | |
599 } | |
600 | |
601 @Override | |
602 public boolean setsSharedClassExposureCG (ThreadInfo ti, Instruction insn, ElementInfo eiFieldOwner, FieldInfo fi, ElementInfo eiExposed){ | |
603 return setsExposureCG(ti,insn,eiFieldOwner,fi,eiExposed); | |
604 } | |
605 | |
606 // since exposure is about the object being exposed (the element), there is no separate setsSharedArrayExposureCG | |
607 | |
608 | |
609 @Override | |
610 public void cleanupThreadTermination(ThreadInfo ti) { | |
611 // default action is to do nothing | |
612 } | |
613 | |
614 } |