liveBook · Manning

Direct linking

As explained in Clojure: The Essential Reference

Direct linking is a Clojure compilation mode that inlines var contents into compiled code instead of resolving them through var indirection.

Direct linking is a Clojure compilation mode that removes var indirection by embedding direct calls to compiled function implementations. Enable it through the dynamic *compiler-options* map with :direct-linking true. section 23.8

The option changes the shape of compiled calls:

  • With :direct-linking false, compiled code stores a Var and invokes its raw root through IFn. section 23.8
  • With :direct-linking true, compiled code calls the generated function class’s static invokeStatic method directly. section 23.8
  • Pass the same setting from the command line with -Dclojure.compiler.direct-linking=true. section 23.8

Comparing compiled calls

Compile (defn plus [a b] (+ a b)) followed by (plus 1 2) twice. Disabling direct linking produces a Var lookup and IFn invocation; enabling it produces a direct call to user$plus.invokeStatic with the same arguments. section 23.8

import clojure.lang.RT;
import clojure.lang.IFn;
import clojure.lang.Var;
import clojure.lang.AFunction;

public final class user$eval30 extends AFunction
{
    public static final Var const__0;
    public static final Object const__1;
    public static final Object const__2;

    static {
        const__0 = RT.var("user", "plus"); #1
        const__1 = 1L;
        const__2 = 2L;
    }

    public static Object invokeStatic() {
        return ((IFn)user$eval30.const__0.getRawRoot()) #2
               .invoke(user$eval30.const__1,
                       user$eval30.const__2);
    }

    public Object invoke() {
        return invokeStatic();
    }

}

Inspect the decompiled indirect call, where a Var resolves the function’s raw root before invocation. section 23.8

import clojure.lang.AFunction;

//
// Decompiled by Procyon v0.5.36
//

public final class user$eval35 extends AFunction
{
    public static final Object const__1;
    public static final Object const__2;

    public static Object invokeStatic() {
        return user$plus    #1
          .invokeStatic(user$eval35.const__1,
                        user$eval35.const__2);
    }

    public Object invoke() {
        return invokeStatic();
    }

    static {
        const__1 = 1L;
        const__2 = 2L;
    }
}

Inspect the decompiled directly linked call, which invokes the generated function class without Var dereferencing. section 23.8

How Clojure: The Essential Reference covers it

How deep it goes
Shows the compiler option and decompiled Java differences, but does not discuss performance or operational trade-offs.
Examples
Uses a plus function, two numeric arguments, compiler bindings, and decompiled Java output.
What it assumes
Assumes familiarity with Clojure functions, Vars, compilation, and reading decompiled Java classes.
What you can do after
Evaluate/understand how direct linking changes compiled function invocation and configure it through bindings or a JVM property.
How it connects
Connects compiler options, Vars, var indirection, compilation, and generated Java classes.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Clojure: The Essential Reference. The section links point to the parts of the book it draws on.