Class Ek9ClassWriter

java.lang.Object
org.objectweb.asm.ClassVisitor
org.objectweb.asm.ClassWriter
org.ek9lang.compiler.backend.jvm.Ek9ClassWriter

final class Ek9ClassWriter extends org.objectweb.asm.ClassWriter
Custom ClassWriter that doesn't require loading classes during frame computation.

Standard ClassWriter.COMPUTE_FRAMES uses ClassLoader to find common superclasses when computing stack map frames. This fails when generating multiple classes in the same compilation unit because referenced classes aren't on classpath yet.

This custom writer uses a type hierarchy map (built from ISymbol data) to find actual common superclasses. This is essential for function delegate polymorphism: when if/else branches assign different concrete functions (e.g., UpperProcessor, LowerProcessor) to a variable of abstract type (Processor), ASM needs to know the actual common superclass (Processor) rather than defaulting to Object.

There is deliberately NO name-based exception test, and no special exception case at all. Asking whether a type name contains "Exception" mis-classifies an ordinary user class - ExceptionReport extends Report is not a Throwable - and produced a clean compile followed by a VerifyError naming java/lang/Throwable, a type absent from the user's source. Identity comes from the hierarchy, never from the spelling of a name.

Exceptions need no special case once the hierarchy map spans the whole program: every EK9 exception descends from org.ek9.lang::Exception, so two of them always meet inside the EK9 hierarchy and the walk never has to climb into JVM-only ancestry. Seeding that JVM spine was tried and could not be falsified - emptying it left the 678 code-generation and 11 end-to-end tests green and all three defect probes passing - so it is deliberately absent.

For types not in the hierarchy map, defaults to java/lang/Object.

  • Field Summary

    Fields inherited from class org.objectweb.asm.ClassWriter

    COMPUTE_FRAMES, COMPUTE_MAXS

    Fields inherited from class org.objectweb.asm.ClassVisitor

    api, cv
  • Constructor Summary

    Constructors
    Constructor
    Description
    Ek9ClassWriter(int flags, Map<String,String> typeHierarchy)
     
  • Method Summary

    Modifier and Type
    Method
    Description
    protected String
    Override getCommonSuperClass to use EK9's type hierarchy from ISymbol data.
    byte[]
    THE chokepoint that makes a zero-length JVM exception-table entry impossible to emit (see SafeExceptionTableMethodVisitor).

    Methods inherited from class org.objectweb.asm.ClassWriter

    getClassLoader, hasFlags, newClass, newConst, newConstantDynamic, newField, newHandle, newHandle, newInvokeDynamic, newMethod, newMethodType, newModule, newNameType, newPackage, newUTF8, setFlags, visit, visitAnnotation, visitAttribute, visitEnd, visitField, visitInnerClass, visitMethod, visitModule, visitNestHost, visitNestMember, visitOuterClass, visitPermittedSubclass, visitRecordComponent, visitSource, visitTypeAnnotation

    Methods inherited from class org.objectweb.asm.ClassVisitor

    getDelegate

    Methods inherited from class Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • Ek9ClassWriter

      Ek9ClassWriter(int flags, Map<String,String> typeHierarchy)
  • Method Details

    • toByteArray

      public byte[] toByteArray()
      THE chokepoint that makes a zero-length JVM exception-table entry impossible to emit (see SafeExceptionTableMethodVisitor). ASM's ClassWriter.visitMethod is final so the wrapper cannot be installed there; instead this filters the finished class on the way out. Every backend ClassWriter is an Ek9ClassWriter, so this one override covers every generated class regardless of which generator produced it or how it registered its exception handlers.

      See SafeExceptionTableMethodVisitor.filterDegenerateExceptionTables(byte[]) for the copy pass that drops any exception-table entry whose start and end labels resolve to the same offset. For valid code (no degenerate range) the copy is faithful and normalisation-equivalent — the filter only ever removes would-be-invalid entries.

      Overrides:
      toByteArray in class org.objectweb.asm.ClassWriter
    • getCommonSuperClass

      protected String getCommonSuperClass(String type1, String type2)
      Override getCommonSuperClass to use EK9's type hierarchy from ISymbol data. Walks up both type hierarchies to find the first common ancestor.
      Overrides:
      getCommonSuperClass in class org.objectweb.asm.ClassWriter
      Parameters:
      type1 - First type (internal name, e.g., "module/UpperProcessor")
      type2 - Second type (internal name, e.g., "module/LowerProcessor")
      Returns:
      Common superclass internal name (e.g., "module/Processor")