Error formatting macro: pagetree: java.lang.NullPointerException
Skip to end of metadata
Go to start of metadata
You are viewing an old version of this page. View the current version. Compare with Current  |   View Page History

Also known as CLJ-322

Why do we AOT compile?

  • Interop
    • To consume a Java API
      • Concrete derivation (gen-class)
      • Naming/packaging conventions
    • To expose an API to Java code
      • deftype/record/protocol/interface
    • Deployment environments
      • Special classloaders, e.g. OSGi, Eclipse
  • Application delivery
    • Main method (gen-class)
      • Mitigated by "-m" option to clojure.main
    • Bytecode post-processing
      • Android/Dalvik
    • Faster startup
      • Only an issue in constrained environments like Android
    • Hide source code from consumers
  • Vet reflection warnings
  • Syntax check
    • Not necessary, but still a common use case

What do we want to AOT-compile?

  • Just some things
    • For the Interop case
    • Not currently supported
  • Everything
    • For the "Application delivery", "Syntax check", and "reflection warnings" cases
    • Currently supported by clojure.core/compile

Current behavior

  • Why is AOT-compilation transitive?
    • Clojure does not support separate compilation
      • All symbols must resolved at compile time
    • compile-files is a boolean
  • The effects of transitive compilation when AOT-comipiling a namespace "A"
    • When namespace A loads namespace B within the same project
      • Namespace B is AOT-compiled and emitted
    • When namespace A loads library C from external JAR
      • Library C's namespaces are AOT-compiled and emitted alongside A's
  • Work-arounds
    • Build tools: filter unwanted .class files from JAR
      • Ant, Maven, scripting
      • Clojure itself does this, e.g. "slim" JAR
      • Tedious
      • Not commonly used
    • Write Java
      • Fairly common

Proposed solutions

Finer-grained control of the compilation process

  • A. Global flag for transitive/non-transitive compilation
    • Chas Emerick's patch
      • New system property "clojure.compiler.transitive"
      • When true (default), preserves current behavior
      • When false, only namespaces give as arguments to `compile` are emitted
    • Doesn't handle classes created by deftype/record/etc.
  • B. Specify exactly which .class files should be emitted
    • Stuart Sierra's patch
      • Specified as a Set of Strings, but could be any function, e.g. regex
  • C. Global flag for compiling "interop" forms
    • Is there a universal definition of what an "interop" form is?
      • gen-class, obviously
      • defprotocol?
      • deftype/defrecord?
    • Does not require maintaining list of .class files to emit
    • Could provide a convenient defaults for the common case
    • Macros like "deftype" can opt in with metadata
  • D. Metadata to control AOT-compilation
    • Permits fine-grained control
    • In-line with source code
    • How to support multiple AOT-compilation strategies in a single build
      • E.g. dev build only AOT-compiles interop forms, production AOT-compiles everything

Separate writing class files from compilation

  • E. Compiler holds references to generated bytecode
    • Not currently implemented in any patch
    • After compilation, call function to emit .class files
    • Will use lots of memory!
      • Or will it? The JVM already has this stuff in memory
      • Must disable in production!
    • Brings us closer to a Smalltalk-like "program image"
Labels: