Writing Directives

This topic examines Compiler Control options and steps for writing directives from those options.

Compiler Control Options

Options are instructions for compilation. Options provide method-context precision. Available options vary by compiler and require specific types of values.

Table 2-1 Common Options

Option Description Value Type Default Value

Enable

Hides a directive and renders it unmatchable if it is set to false. This option is useful for preventing option duplication. See Preventing Duplication with the Enable Option.

bool

true

Exclude

Excludes methods from compilation.

bool

false

BreakAtExecute

Sets a breakpoint to stop execution at the beginning of the specified methods when debugging the JVM.

bool

false

BreakAtCompile

Sets a breakpoint to stop compilation at the beginning of the specified methods when debugging the JVM.

bool

false

Log

Places only the specified methods in a log. You must first set the command-line option -XX:+LogCompilation. The default value false places all compiled methods in a log.

bool

false

PrintAssembly

Prints assembly code for bytecoded and native methods by using the external disassembler.so library.

bool

false

PrintInlining

Prints which methods are inlined, and where.

bool

false

PrintNMethods

Prints nmethods as they are generated.

bool

false

BackgroundCompilation

Compiles methods as a background task. Methods run in interpreter mode until the background compilation finishes. The value false compiles methods as a foreground task.

bool

true

ReplayInline

Enables the same CIReplay functionality as the corresponding global option, but on a per-method basis.

bool

false

DumpReplay

Enables the same CIReplay functionality as the corresponding global option, but on a per-method basis.

bool

false

DumpInline

Enables the same CIReplay functionality as the corresponding global option, but on a per-method basis.

bool

false

CompilerDirectivesIgnoreCompileCommands

Disregards all CompileCommands.

bool

false

DisableIntrinsic

Disables the use of intrinsics based on method-matching criteria.

ccstr

No default value.

inline

Forces or prevents inlining of a method based on method-matching criteria. See Writing an Inline Directive Option.

ccstr[]

No default value.

Table 2-2 C2 Exclusive Options

Option Description Value Type Default Value

BlockLayoutByFrequency

Moves infrequent execution branches from the hot path.

bool

true

PrintOptoAssembly

Prints generated assembly code after compilation by using the external disassembler.so library. This requires a debugging build of the JVM.

bool

false

PrintIntrinsics

Prints which intrinsic methods are used, and where.

bool

false

TraceOptoPipelining

Traces pipelining information, similar to the corresponding global option, but on a per-method basis. This is intended for slow and fast debugging builds.

bool

false

TraceOptoOutput

Traces pipelining information, similar to the corresponding global option, but on a per-method basis. This is intended for slow and fast debugging builds.

bool

false

TraceSpilling

Traces variable spilling.

bool

false

Vectorize

Performs calculations in parallel, across vector registers.

bool

false

VectorizeDebug

Performs calculations in parallel, across vector registers. This requires a debugging build of the JVM.

intx

0

CloneMapDebug

Enables you to examine the CloneMap generated from vectorization. This requires a debugging build of the JVM.

bool

false

IGVPrintLevel

Specifies the points where the compiler graph is printed in Oracle’s Hotspot Ideal Graphic Visualizer (IGV). A higher value means higher granularity.

intx

0

MaxNodeLimit

Sets the maximum number of nodes to use during a single method’s compilation.

intx

80000

A ccstr value type is a method pattern. See Writing a Method Pattern in a Compiler Directive.

The default directive supplies default values for compiler options. See What Is the Default Directive?

Writing a Directive File

Individual compiler directives are written in a directives file. Only directive files, not individual directives, can be added to the stack of active directives.

  1. Create a file with a .json extension. Directive files are written using a subset of JSON syntax with minor additions and deviations.
  2. Add the following syntax as a template you can work from:
    [  //Array of Directives
        {   //Directive Block
            //Directive 1
        },
        {   //Directive Block
            //Directive 2
        },
    ]

    The components of this template are:

    Array of Directives
    • A directives file stores an array of directive blocks, denoted with a pair of brackets ([]).

    • The brackets are optional if the file contains only a single directive block.

    Directive Block
    • A block is denoted with a pair of braces ({}).

    • A block contains one individual directive.

    • A directives file can contain any number of directive blocks.

    • Blocks are separated with a comma (,).

    • A comma is optional following the final block in the array.

    Directive
    • Each directive must be within a directive block.

    • A directives file can contain multiple directives when it contains multiple directive blocks.

    Comments
    • Single-line comments are preceded with two slashes (//).

    • Multiline comments are not allowed.

  3. Add or remove directive blocks from the template to match the number of directives you want in the directives file.
  4. In each directive block, write one compiler directive. See Writing a Compiler Directive.
  5. Reorder the directive blocks if necessary. The ordering of directives in a file is significant. Directives written closer to the beginning of the array receive higher priority. For more information, see How Directives Are Ordered in the Directives Stack? and How Directives are Applied to Code?
The following example shows a completed directives file that contains two compiler directives:
[  //Array of directives
    {   //Directive Block
        //Directive 1
        match: ["java*.*", "oracle*.*"],
        c1: {
            Enable: true,
            Exclude: true,
            BreakAtExecute: true,
        },
        c2: {
            Enable: false,
            MaxNodeLimit: 1000,
        },
        BreakAtCompile: true,
        DumpReplay: true,
    },
    {   //Directive Block
        //Directive 2
        match: ["*Concurrent.*"],
        c2: {
            Exclude:true,
        },
    },
]

Writing a Compiler Directive

You must write a compiler directive within a directives file. You can repeat the following steps for each individual compiler directive that you want to write in a directives file.

An individual compiler directive is written within a directive block in a directives file. See Writing a Directive File.
  1. Insert the following block of code, as a template you can work from, to write an individual compiler directive. This block of code is a directive block.
        {
            match: [],
            c1: {
                //c1 directive options
            },
            c2: {
                //c2 directive options
            },
            //Directive options applicable to all compilers
        },
  2. Provide the match attribute with an array of method patterns. See Writing a Method Pattern in a Compiler Directive.
    For example:
            match: ["java*.*", "oracle*.*"],
  3. Provide the c1 attribute with a block of comma-separated directive options. Ensure that these options are valid for the c1 compiler.
    For example:
            c1: {
                Enable: true,
                Exclude: true,
                BreakAtExecute: true,
            },
  4. Provide the c2 attribute with a block of comma-separated directive options. This block can contain a mix of common and c2-exclusive compiler options.
    For example:
            c2: {
                Enable: false,
                MaxNodeLimit: 1000,
            },
  5. Provide, at the end of the directive, options you want applicable to all compilers. These options are considered written within the scope of the common block. Options are comma-separated.
    For example:
            BreakAtCompile: true,
            DumpReplay: true,
  6. Clean up the file by completing the following steps.
    1. Check for the duplication of directive options. If a conflict occurs, then the last occurrence of an option takes priority. Conflicts typically occur between the common block and the c1 or c2 blocks, not between the c1 and c2 blocks.
    2. Avoid writing c2-exclusive directive options in the common block. Although the common block can accept a mix of common and c2-exclusive options, it’s pointless to structure a directive this way because c2-exclusive options in the common block have no effect on the c1 compiler. Write c2-exclusive options within the c2 block instead.
    3. If the c1 or c2 attribute has no corresponding directive options, then omit the attribute-value syntax for that compiler.
The following example shows the resulting directive, based on earlier examples, is:
    {
        match: ["java*.*", "oracle*.*"],
        c1: {
            Enable: true,
            Exclude: true,
            BreakAtExecute: true,
        },
        c2: {
            Enable: false,
            MaxNodeLimit: 1000,
        },
        BreakAtCompile: true,
        DumpReplay: true,
    },
The JSON format of directive files allows the following deviations in syntax:
  • Extra trailing commas are optional in arrays and objects.

  • Attributes are strings and are optionally placed within quotation marks.

  • If an array contains only one element, then brackets are optional.

Therefore, the following example shows a valid compiler directive:
    {
       "match": "*Concurrent.*",
        c2: {
            "Exclude": true,
        }
    },

Writing a Method Pattern in a Compiler Directive

A ccstr is a method pattern that you can write precisely or you can generalize with wildcard characters. You can specify what best-matching Java code should have accompanying directive options applied, or what Java code should be inlined.

To write a method pattern:
  1. Use the following syntax to write your method pattern: package/class.method(parameter_list). To generalize a method pattern with wildcard characters, see Step 2.
    The following example shows a method pattern that uses this syntax:
    java/lang/String.indexOf()
    Other formatting styles are available. This ensures backward compatibility with earlier ways of method matching such as CompileCommand. Valid formatting alternatives for the previous example include:
    • java/lang/String.indexOf()
    • java/lang/String,indexOf()
    • java/lang/String indexOf()
    • java.lang.String::indexOf()
    The last formatting style matches the HotSpot output.
  2. Insert a wildcard character (*) where you want to generalize part of the method pattern.
    The following examples are valid generalizations of the method pattern example in Step 1:
    • java/lang/String.indexOf*
    • *lang/String.indexOf*
    • *va/lang*.*dex*
    • java/lang/String.*
    • *.*
    Increased generalization leads to decreased precision. More Java code becomes a potential match with the method pattern. Therefore, it’s important to use the wildcard character (*) judiciously.
  3. Modify the signature portion of the method pattern, according to the Java Specifications. A signature match must be exact, otherwise the signature defaults to a wildcard character (*). Omitted signatures also default to a wildcard character. Signatures cannot contain the wildcard character.
  4. Optional: If you write a method pattern to accompany the inline directive option, then you must prefix the method pattern with additional characters. See Writing an Inline Directive Option.

Writing an Inline Directive Option

The attribute for an inline directive option requires an array of method patterns with special commands prefixed. This indicates which method patterns should or shouldn’t inline.

  1. Write inline: in the common block, c1 block , or c2 block of a directive.
  2. Add an array of carefully ordered method patterns. The prefixed command on the first matching method pattern is executed. The remaining method patterns in the array are ignored.
  3. Prefix a + to force inlining of any matching Java code.
  4. Prefix a - to prevent inlining of any matching Java code.
  5. Optional: If you need inlining behavior applied to multiple method patterns, then repeat Steps 1 to 4 to write multiple inline statements. Don’t write a single array that contains multiple method patterns.
The following examples show the inline directive options:
  • inline: ["+java/lang*.*", "-sun*.*"]
  • inline: "+java/lang*.*"

Preventing Duplication with the Enable Option

You can use the Enable option to hide aspects of directives and prevent duplication between directives.

In the following example, the c1attribute of the compiler directives are identical.:
[
    {
        match: ["java*.*"],
        c1: {
            BreakAtExecute: true,
            BreakAtCompile: true,
            DumpReplay: true,
            DumpInline: true,
        },
        c2: {
            MaxNodeLimit: 1000,
        },
    },
    {
        match: ["oracle*.*"],
        c1: {
            BreakAtExecute: true,
            BreakAtCompile: true,
            DumpReplay: true,
            DumpInline: true,
        },
        c2: {
            MaxNodeLimit: 2000,
        },
    },
]
The following example shows how the undesirable code duplication is resolved with the Enable option. Enable hides the block directives and renders them unmatchable.
[
    {
        match: ["java*.*"],
        c1: {
            Enable: false,
        },
        c2: {
            MaxNodeLimit: 1000,
        },
    },
    {
        match: ["oracle*.*"],
        c1: {
            Enable: false,
        },
        c2: {
            MaxNodeLimit: 2000,
        },
    },
    {
        match: ["java*.*", "oracle*.*"],
        c1: {
            BreakAtExecute: true,
            BreakAtCompile: true,
            DumpReplay: true,
            DumpInline: true,
        },
        c2: {
            //Unreachable code
        },
    },
]
Typically, the first matching directive is applied to a method’s compilation. The Enable option provides an exception to this rule. A method that would typically be compiled by c1 in the first or second directive is now compiled with the c1 block of the third directive. The c2 block of the third directive is unreachable because the c2 blocks in the first and second directive take priority.