@@ -157,7 +157,7 @@ Breakpoint create(int ignoreCount, LineLocation lineLocation, boolean oneShot) t
157
157
if (breakpoint == null ) {
158
158
final SourceSectionFilter query = SourceSectionFilter .newBuilder ().sourceIs (lineLocation .getSource ()).lineStartsIn (IndexRange .byLength (lineLocation .getLineNumber (), 1 )).tagIs (
159
159
StandardTags .StatementTag .class ).build ();
160
- breakpoint = new BreakpointImpl (lineLocation , query , ignoreCount , oneShot );
160
+ breakpoint = createBreakpoint (lineLocation , query , ignoreCount , oneShot );
161
161
if (TRACE ) {
162
162
trace ("NEW " + breakpoint .getShortDescription ());
163
163
}
@@ -192,7 +192,7 @@ Breakpoint create(int ignoreCount, Class<?> tag, boolean oneShot) throws IOExcep
192
192
BreakpointImpl breakpoint = breakpoints .get (tag );
193
193
if (breakpoint == null ) {
194
194
final SourceSectionFilter query = SourceSectionFilter .newBuilder ().tagIs (tag ).build ();
195
- breakpoint = new BreakpointImpl (tag , query , ignoreCount , oneShot );
195
+ breakpoint = createBreakpoint (tag , query , ignoreCount , oneShot );
196
196
if (TRACE ) {
197
197
trace ("NEW " + breakpoint .getShortDescription ());
198
198
}
@@ -253,6 +253,16 @@ private void forget(BreakpointImpl breakpoint) {
253
253
breakpoints .remove (breakpoint .getKey ());
254
254
}
255
255
256
+ BreakpointImpl createBreakpoint (Object key , SourceSectionFilter query , int ignoreCount , boolean isOneShot ) {
257
+ BreakpointImpl breakpoint = new BreakpointImpl (key , query , ignoreCount , isOneShot );
258
+ // Register listener after breakpoint has been constructed and JMM
259
+ // allows for safe publication. Otherwise, we can't be sure that the
260
+ // assumption fields are visible by other threads, which would lead to
261
+ // a race with object initialization.
262
+ breakpoint .binding = instrumenter .attachListener (breakpoint .locationQuery , new BreakpointListener (breakpoint ));
263
+ return breakpoint ;
264
+ }
265
+
256
266
private final class BreakpointImpl extends Breakpoint implements ExecutionEventNodeFactory {
257
267
258
268
private static final String SHOULD_NOT_HAPPEN = "BreakpointImpl: should not happen" ;
@@ -266,24 +276,24 @@ private final class BreakpointImpl extends Breakpoint implements ExecutionEventN
266
276
@ SuppressWarnings ("rawtypes" ) private EventBinding binding ;
267
277
268
278
// Cached assumption that the global status of line breakpoint activity has not changed.
269
- private Assumption breakpointsActiveAssumption ;
279
+ @ CompilationFinal private Assumption breakpointsActiveAssumption ;
270
280
271
281
// Whether this breakpoint is enable/disabled
272
282
@ CompilationFinal private boolean isEnabled ;
273
- private Assumption enabledUnchangedAssumption ;
283
+ @ CompilationFinal private Assumption enabledUnchangedAssumption ;
274
284
275
285
private Source conditionSource ;
276
286
@ SuppressWarnings ("rawtypes" ) private Class <? extends TruffleLanguage > condLangClass ;
277
287
278
- BreakpointImpl (Object key , SourceSectionFilter query , int ignoreCount , boolean isOneShot ) {
288
+ private BreakpointImpl (Object key , SourceSectionFilter query , int ignoreCount , boolean isOneShot ) {
279
289
super ();
280
290
this .ignoreCount = ignoreCount ;
281
291
this .isOneShot = isOneShot ;
282
292
this .locationKey = key ;
283
293
this .locationQuery = query ;
284
- this .binding = instrumenter .attachListener (locationQuery , new BreakpointListener ());
285
- this .breakpointsActiveAssumption = BreakpointFactory .this .breakpointsActiveUnchanged .getAssumption ();
286
294
this .isEnabled = true ;
295
+
296
+ this .breakpointsActiveAssumption = BreakpointFactory .this .breakpointsActiveUnchanged .getAssumption ();
287
297
this .enabledUnchangedAssumption = Truffle .getRuntime ().createAssumption ("Breakpoint enabled state unchanged" );
288
298
}
289
299
@@ -347,7 +357,7 @@ public void setCondition(String expr) throws IOException {
347
357
binding .dispose ();
348
358
if (expr == null ) {
349
359
conditionSource = null ;
350
- binding = instrumenter .attachListener (locationQuery , new BreakpointListener ());
360
+ binding = instrumenter .attachListener (locationQuery , new BreakpointListener (this ));
351
361
} else {
352
362
conditionSource = Source .fromText (expr , "breakpoint condition from text: " + expr );
353
363
binding = instrumenter .attachFactory (locationQuery , this );
@@ -482,31 +492,6 @@ private void addExceptionWarning(Exception ex) {
482
492
warningLog .addWarning (String .format ("Exception in %s: %s" , getShortDescription (), ex .getMessage ()));
483
493
}
484
494
485
- /** Attached to implement an unconditional breakpoint. */
486
- private final class BreakpointListener implements ExecutionEventListener {
487
-
488
- @ Override
489
- public void onEnter (EventContext context , VirtualFrame frame ) {
490
- if (TRACE ) {
491
- trace ("hit breakpoint " + getShortDescription ());
492
- }
493
- BreakpointImpl .this .nodeEnter (context , frame );
494
- }
495
-
496
- @ Override
497
- public void onReturnValue (EventContext context , VirtualFrame frame , Object result ) {
498
- }
499
-
500
- @ Override
501
- public void onReturnExceptional (EventContext context , VirtualFrame frame , Throwable exception ) {
502
- }
503
-
504
- @ Override
505
- public String toString () {
506
- return getShortDescription ();
507
- }
508
- }
509
-
510
495
/** Attached to implement a conditional breakpoint. */
511
496
private class BreakpointConditionEventNode extends ExecutionEventNode {
512
497
@ Child DirectCallNode callNode ;
@@ -551,4 +536,35 @@ public String toString() {
551
536
return sb .toString ();
552
537
}
553
538
}
539
+
540
+ /** Attached to implement an unconditional breakpoint. */
541
+ private static final class BreakpointListener implements ExecutionEventListener {
542
+
543
+ private final BreakpointImpl breakpoint ;
544
+
545
+ BreakpointListener (BreakpointImpl breakpoint ) {
546
+ this .breakpoint = breakpoint ;
547
+ }
548
+
549
+ @ Override
550
+ public void onEnter (EventContext context , VirtualFrame frame ) {
551
+ if (TRACE ) {
552
+ trace ("hit breakpoint " + breakpoint .getShortDescription ());
553
+ }
554
+ breakpoint .nodeEnter (context , frame );
555
+ }
556
+
557
+ @ Override
558
+ public void onReturnValue (EventContext context , VirtualFrame frame , Object result ) {
559
+ }
560
+
561
+ @ Override
562
+ public void onReturnExceptional (EventContext context , VirtualFrame frame , Throwable exception ) {
563
+ }
564
+
565
+ @ Override
566
+ public String toString () {
567
+ return breakpoint .getShortDescription ();
568
+ }
569
+ }
554
570
}
0 commit comments