Since joining the Parrot development team, I've been forced to forget just about everything I thought I ever knew about stack machines, computer architecture, and especially control flow. In fact, I think a more appropriate slogan for Parrot would be "the antithesis of tradition." This is not necessarily a bad thing though. If it weren't for Parrot, I probably would never have heard of things like continuation passing style or mark and sweep garbage collection systems.
However, Parrot's unconventional design has presented some problems for my GSoC project. It seems that my initial plan for implementing breakpoints won't work out as planned. The process of modifying the opcode stream is a little too cumbersome and unwieldy since opcodes are not fixed length. Furthermore, the fact that I must deal with an actual stream of opcodes instead of an in-memory representation of an executable file (e.g. ELF or COFF) presents some difficulties as well.
My mentor, cotto, suggested that I instead incorporate the debugging behavior into a custom runcore. This concept took some time to digest but after a very helpful email from a Mr. Michael Fair, I'm feeling a lot better about the idea.
Since, as mentioned above, there is continual dynamic flow of execution, I must redirect that flow into an alternate code branch not originally encoding in the opcode stream; kind of like a callback function. This will be the best way to give the illusion that execution has "halted" at a breakpoint.
Now that I have a better understanding of Parrot's execution environment, I think I can finally move past this brick wall I've been stuck at for the past week.