Compiler Design

105601
Back to Compiler Design

Module 6: Advanced Topics

  1. Q1i. Dynamic method dispatch is primarily used to implement: (i) Lexical analysis (ii) Constant folding (iii) Runtime polymorphism (iv) Register allocation20262m

    Module 6: Advanced Topics

    Dynamic method dispatch is primarily used to implement:
    (i) Lexical analysis
    (ii) Constant folding
    (iii) Runtime polymorphism
    (iv) Register allocation

    View this question on its own page →
    Worked Solution

    Answer: (iii) Runtime polymorphism

    Explanation

    Dynamic method dispatch selects which overridden method to call based on the actual (run-time) type of the object, not the declared type of the reference.

    Compilers implement it with a virtual method table (vtable): each object carries a hidden pointer to its class's vtable, and a virtual call becomes an indirect call through a fixed slot index.

    Animal a = new Dog();
    a.speak();   // Dog.speak() is chosen at run time
    

    This is exactly runtime (dynamic) polymorphism. It has nothing to do with lexical analysis, constant folding or register allocation.

    (iii) Runtime polymorphism\boxed{\text{(iii) Runtime polymorphism}}

  2. Q8a. Discuss the major challenges involved in compiling object-oriented features such as classes, inheritance, and polymorphism.20267m

    Module 6: Advanced Topics

    Discuss the major challenges involved in compiling object-oriented features such as classes, inheritance, and polymorphism.

    View this question on its own page →
    Worked Solution

    Compiling object-oriented features: main challenges

    Object-oriented languages add classes, objects, inheritance and polymorphism on top of ordinary procedural features. The compiler must map these to plain memory layouts and jumps.

    MermaidDiagram
    Rendering diagram…

    1. Object layout (classes)

    An object is stored as a record of its fields, plus a hidden pointer to its class's method table. The compiler must compute field offsets and the total size.

    SVGVector Architecture Diagram (SVG)
    Dog object in memory vptr age tricks offset 0 offset 8 offset 12 same layout as an Animal object added by Dog

    2. Inheritance

    • A subclass object must be usable wherever a superclass object is expected, so the inherited fields keep the same offsets as in the parent (the subclass fields are appended).
    • Multiple inheritance breaks this: an object has several parent parts, so the compiler needs several vptrs and must adjust the this pointer when converting to a base type; shared (virtual) base classes need extra indirection.
    • Constructors and destructors must run in the right order (base first on construction, derived first on destruction).

    3. Polymorphism and dynamic dispatch

    The method that runs depends on the object's run-time type, not on the declared type. The compiler builds a virtual method table (vtable) for each class and compiles a virtual call as an indirect call through a fixed slot:

    Slot Animal vtable Dog vtable
    0 Animal::speak Dog::speak (overrides)

    A call a.speak() is compiled to an indirect call through the vptr and the fixed slot of speak:

    MermaidDiagram
    Rendering diagram…

    This costs an extra memory load and an indirect jump, and prevents simple inlining; optimizers use devirtualization (when the exact type is known) to recover speed.

    4. Other challenges

    Challenge Why it is hard
    Type checking with subtyping Assignments are legal from subclass to superclass; overriding rules (parameter and return types) must be checked
    Overloading and name mangling Several methods share a name; the compiler selects one by argument types and encodes the signature in the symbol name
    Access control private, protected, public checks at compile time
    this pointer Passed as a hidden first argument to every instance method
    Run-time type information Needed for casts, instanceof, exceptions
    Interfaces and abstract classes Dispatch through interface tables; abstract methods have no body
    Memory management Allocation on heap, garbage collection or destructors
    Separate compilation Changing a base class's layout forces recompilation of all subclasses