Understanding Directives Better

The following topic examines how directives behave and interact.

What Is the Default Directive?

The default directive is a compiler directive that contains default values for all possible directive options. It is at the bottom of the directives stack and matches every method submitted for compilation.

When you design a new directive, you specify how the new directive differs from the default directive. The default directive becomes a template to guide your design decisions.

Directive Option Values in the Default Directive

Printing an empty directive stack reveals the default directive’s matching criteria and values for all directive options:
Directive: (default)
 matching: *.*
 c1 directives:
  inline: -
  Enable:true Exclude:false BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:80000

 c2 directives:
  inline: -
  Enable:true Exclude:false BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:80000

Note:

Although these printouts provide a thorough account of all directive options and their values, certain options are applicable exclusively to the c2 compiler. For a complete list, see Table 2-2.

Directive Option Values in New Directives

New directives must specify how they differ from the default directive. If a directive option is not mentioned, then that option retains the value from the default directive.

For example:
[
    {
        match: ["*Concurrent.*"],
        c2: {
            MaxNodeLimit: 1000,
        },
        Exclude:true,
    },
]
When you add this directive to the directives stack, the default directive becomes the bottom-most directive of the stack. See How Are Directives Ordered in the Directives Stack? for a description of this process. The printout from the resulting directives stack shows how only the directive options specified in the example differ from the values found in the default directive:
Directive:
 matching: *Concurrent.*
 c1 directives:
  inline: -
  Enable:true Exclude:true BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:80000 

 c2 directives:
  inline: -
  Enable:true Exclude:true BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:1000 


Directive: (default)
 matching: *.*
 c1 directives:
  inline: -
  Enable:true Exclude:false BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:80000 

 c2 directives:
  inline: -
  Enable:true Exclude:false BreakAtExecute:false BreakAtCompile:false Log:false PrintAssembly:false PrintInlining:false PrintNMethods:false BackgroundCompilation:true ReplayInline:false DumpReplay:false DumpInline:false CompilerDirectivesIgnoreCompileCommands:false DisableIntrinsic: BlockLayoutByFrequency:true PrintOptoAssembly:false PrintIntrinsics:false TraceOptoPipelining:false TraceOptoOutput:false TraceSpilling:false Vectorize:false VectorizeDebug:0 CloneMapDebug:false IGVPrintLevel:0 MaxNodeLimit:80000 

How Are Directives Applied to Code?

A directive is applied to code based on a method matching process. Every method submitted for compilation is matched with a directive in the directives stack.

The process of brokering a match between a method and the directives stack is performed by the CompilerBroker.

The Method Matching Process

When a method is submitted for compilation, its fully qualified name is compared to the matching criteria in the directives stack. The first matching directive in the stack is applied to the method. The remaining directives in the stack are ignored. If no other match is found, then the default directive is applied.

This process is repeated for all methods in a compilation. Therefore, more than one directive could be applied in a compilation, while only one directive is applied per method. All directives in the stack are considered active because they are potentially applicable. The key differences between active and applied directives are:

  • A directive is active if it’s present in the directives stack.

  • A directive is applied if it’s affecting code.

Example 2-1 When a Match Is Found

Example of a method submitted for compilation:
public int exampleMethod(int x){
        return x;
}
Based on method-matching criteria, Directive 2 is applied from the following example directive stack:
Directive 2:
 matching: *.*example*
Directive 1:
 matching: *.*exampleMethod*
Directive 0: (default)
 matching: *.*

Example 2-2 When No Match Is Found

The following example method is submitted for compilation:
public int otherMethod(int y){
        return y;
}
Based on method-matching criteria in the following example directive stack, Directive 0 (the default directive) is applied:
Directive 2:
 matching: *.*example*
Directive 1:
 matching: *.*exampleMethod*
Directive 0: (default)
 matching: *.*

Other Guidelines

  • Carefully write the directives’ method-matching criteria. There’s no feedback mechanism to verify which directive is applied to a given method. Instead, a profiler such as JMX is used to measure the cumulative effects of applied directives.

  • The CompilerBroker ignores directive options that create bad code, such as forcing hardware instructions on a platform that doesn't offer support. A warning message is displayed.

  • Directive options have the same limitations as typical command-line flags. For example, instructions to inline code are followed only if the Intermediate Representation (IR) doesn’t become too large.

Compiler Control and Backward Compatibility

CompileCommand and command-line flags can be used alongside Compiler Control directives.

Although Compiler Control can replace CompileCommand for all use cases, backward compatibility is still provided. It’s possible to utilize both at the same time. Compiler Control receives priority. Conflicts are handled based on the following prioritization:
  1. Compiler Control

  2. CompileCommand

  3. Command-line flags

  4. Default values

Example 2-3 Mixing Compiler Control and CompileCommand

The following list shows a small number of compilation options and some ways of assigning values to those options:
  • Compiler Control:

    • Exclude: true

    • BreakAtExecute: false

  • CompileCommand:

    • BreakAtExecute: true

    • BreakAtCompile: true

  • Default values:

    • Exclude: false

    • BreakAtExecute: false

    • BreakAtCompile: false

    • Log: false

For the options and values in this example, the resulting effects on compilation are determined through the rules for handling backward compatibility conflicts:
  • Exclude: true

  • BreakAtExecute: false

  • BreakAtCompile: true

  • Log: false