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!");
  }
 @SlowPath
 public boolean isTaggedAs(SyntaxTag tag) {
   return probe.isTaggedAs(tag);
 }