public synchronized void attach(String file, int line, final DynamicObject block) {
    assert RubyGuards.isRubyProc(block);

    final Instrument instrument =
        Instrument.create(
            new StandardInstrumentListener() {

              @Override
              public void enter(Probe probe, Node node, VirtualFrame frame) {
                final DynamicObject binding =
                    BindingNodes.createRubyBinding(
                        context.getCoreLibrary().getBindingClass(),
                        RubyArguments.getSelf(frame.getArguments()),
                        frame.materialize());
                ProcNodes.rootCall(block, binding);
              }

              @Override
              public void returnVoid(Probe probe, Node node, VirtualFrame virtualFrame) {}

              @Override
              public void returnValue(
                  Probe probe, Node node, VirtualFrame virtualFrame, Object o) {}

              @Override
              public void returnExceptional(
                  Probe probe, Node node, VirtualFrame virtualFrame, Exception e) {}
            },
            String.format("Truffle::Primitive.attach@%s:%d", file, line));

    final Source source = context.getSourceManager().forFileBestFuzzily(file);

    final LineLocation lineLocation = source.createLineLocation(line);

    List<Instrument> instruments = attachments.get(lineLocation);

    if (instruments == null) {
      instruments = new ArrayList<>();
      attachments.put(lineLocation, instruments);
    }

    instruments.add(instrument);

    for (Probe probe : lineToProbesMap.findProbes(lineLocation)) {
      if (probe.isTaggedAs(StandardSyntaxTag.STATEMENT)) {
        probe.attach(instrument);
        return;
      }
    }

    throw new RuntimeException("couldn't find a statement!");
  }
  @Override
  public PEnumerate executePEnumerate(VirtualFrame frame) throws UnexpectedResultException {
    probe.enter(child, frame);
    PEnumerate result;

    try {
      result = child.executePEnumerate(frame);
    } catch (KillException e) {
      throw (e);
    } catch (Exception e) {
      probe.leaveExceptional(child, frame, e);
      throw (e);
    }

    return result;
  }
  @Override
  public int executeInt(VirtualFrame frame) throws UnexpectedResultException {
    probe.enter(child, frame);
    int result;

    try {
      result = child.executeInt(frame);
      probe.leave(child, frame);
    } catch (KillException e) {
      throw (e);
    } catch (Exception e) {
      probe.leaveExceptional(child, frame, e);
      throw (e);
    }

    return result;
  }
  @Override
  public Object execute(VirtualFrame frame) {
    probe.enter(child, frame);
    Object result;

    try {
      result = child.execute(frame);
      probe.leave(child, frame);
    } catch (KillException e) {
      throw (e);
    } catch (Exception e) {
      probe.leaveExceptional(child, frame, e);
      throw (e);
    }

    return result;
  }
  @Override
  public PSequenceIterator executePSequenceIterator(VirtualFrame frame)
      throws UnexpectedResultException {
    probe.enter(child, frame);
    PSequenceIterator result;

    try {
      result = child.executePSequenceIterator(frame);
      probe.leave(child, frame);
    } catch (KillException e) {
      throw (e);
    } catch (Exception e) {
      probe.leaveExceptional(child, frame, e);
      throw (e);
    }

    return result;
  }
  @Override
  public PythonBuiltinClass executePythonBuiltinClass(VirtualFrame frame)
      throws UnexpectedResultException {
    probe.enter(child, frame);
    PythonBuiltinClass result;

    try {
      result = child.executePythonBuiltinClass(frame);
      probe.leave(child, frame);
    } catch (KillException e) {
      throw (e);
    } catch (Exception e) {
      probe.leaveExceptional(child, frame, e);
      throw (e);
    }

    return result;
  }
 @SlowPath
 public Iterable<SyntaxTag> getSyntaxTags() {
   return probe.getSyntaxTags();
 }
 @SlowPath
 public boolean isTaggedAs(SyntaxTag tag) {
   return probe.isTaggedAs(tag);
 }