Adding support for a new language (Dylan)

Hello all,

As I’ve mentioned before, I think, I work on a language called Dylan (http://opendylan.org/). It was originally designed at Apple and some other organizations in the early to mid 1990s.

I’m working on improving our debugging story as described in the blog post that I posted last week (http://dylanfoundry.org/2014/06/25/integrating-with-lldb/).

While some stuff is possible via Python scripts, other things require C++ code and being part of LLDB itself. As an example, I’d like to add support for:

breakpoint set -E dylan …

This requires adding a language runtime plugin and a couple of minor bits of code.

At some point, I’d like to work on support for the dynamic type stuff as I think that’s a better solution than some of what I’ve done in Python. (Although this is made interesting as we don’t use Clang, so I’ve got some eventual questions about how some of this should work.)

What are the policies and guidelines for this sort of contribution?

I’m willing to write and help maintain code and I’m not looking to just dump some code and run away. I suspect others will be in the same position or are already are (like Keno Fischer from the Julia community).

Thanks for your time!

  • Bruce

I remembered that there was a previous thread about this subject and went
and dug it up:

    http://lists.cs.uiuc.edu/pipermail/lldb-dev/2014-January/003046.html

I don't think that it fully resolves some of my questions above, but it is
a start.

- Bruce

If you want to add support for a new language in LLDB, there are two main areas you will want to work on:

  • expression evaluation
  • type inspection

My comments are mostly going to cover the latter (since that’s what I work on)

Your very first step should probably be adding support to ClangASTType for Dylan types. Greg’s reply covered in some detail how you might go ahead and do it: add objects (an AST and a “type pointer” probably) to ClangASTType to represent a DylanType, and then implement individual functions in the form

if (IsDylanType() { // do dylan things } else if (IsClangType()) { // do clang things } else if (IsJuliaType()) { // do julia things } and so on…

A larger refactoring (that I personally favor) would be making ClangASTType into an abstract base class and then having subclasses for ClangType, DylanType, …, and letting dynamic dispatch do its deed instead of having if/switch statements - but I don’t think we ever discussed, much less reached consensus on that.

One of the important things you will want to do is fill out IsPossibleDynamicType() - that API tells LLDB whether it should go looking for “dynamic values” for objects of types in your language. For instance, we know that C int won’t ever resolve to anything except a C int - but ObjectiveC id could be a plethora of things at runtime (an NSString, an NSDictionary, …)

Also, make sure that for Dylan types, ClangASTType::GetMinimumLanguage() correctly reports Dylan back

Those two bits of information (can be dynamic, it’s a Dylan type) are the key for LLDB to know to go look for a Dylan language runtime

A LanguageRuntime is a plugin (you can look at the ObjC ones to see how to make and register one correctly) to which LLDB delegates knowledge of language-specific details

Things it currently knows how to do are, for instance, “give me a printable description of this object”, “set a break-on-exception breakpoint for this language”, and, you guessed it, “figure out the dynamic type of this object”

You will want to fill in those APIs in Dylan-specific ways. For instance, if Dylan objects have an “isa” pointer, you might traverse it to find the actual type of things, construct a type from that information, and vend it back. For an example of how you could vend a type from runtime information, the Objective-C V2 runtime has a type vendor that uses ObjC runtime introspection to generate (partial) types even with no debug information present. Your mileage may vary depending on how much runtime type information you have available.

The “give me a printable description” API is there to support Obj-C “po” behavior, which came from GDB long before data formatters were a thing. If Dylan doesn’t have an equivalent of -(id)description like ObjC does, you might decide not to implement it. If you fail to implement it (return false; is enough), data formatters should kick in for you and print the object automagically. You may want to tweak the output somewhat (ValueObjectPrinter is your guy), and that’s definitely something I’d ask that you talk to us before doing.

Provided you have APIs with reasonable behavior in place, ValueObjectDynamicValue will do the right thing for you automatically, however you might want to pay attention in a couple of places:

  • FixupTypeAndOrName(), make sure that if Dylan has some pointer-like facility, such that the static type of a variable is Foo*, you honor that pointer-ness in the dynamic type
  • in UpdateValue(), you may want to add DylanLanguageRuntime to the list of runtimes that get searched - especially if your Dylan objects have the ability to disguise themselves as plain C objects (think void*)
  • in UpdateValue() also, if you have logic to import types from other languages, or you have flavors of types that are undesirable for users to see, make sure you have proper logic to reject those and fallback to the static type instead

Now that you have all of this support, you can transition your data formatters to C++ - the formatters that ship with LLDB are essentially all written as C++ code in our core. Writing them in Python is nice (sometimes I could fix a bug while sitting at someone’s desk just by typing a few lines of Python), but there is a performance tradeoff involved. Given how you’re writing LLDB support for Dylan, it makes sense for you to also write formatters for Dylan inside LLDB and get those perf numbers back :slight_smile:
You will probably want to set yourself up a category “dylan” and bind it to Dylan objects only. That way, if your dylan integers are called “int”, you don’t have to worry about conflicting with other languages whose integers might be similarly named :slight_smile: The DataFormatters part of the source base has plenty of examples of how to get this to work - feel free to look around!

If Dylan allows types from other languages to be imported under a Dylan cloaking, you may find yourself in the predicament of wanting to write a formatter that displays things one way for Dylan and another way for the origin language of the object. If that is the case, please let me know before making changes, and we can sync up.

I like that :slight_smile:

If you have any further questions, feel free to ask!