SOAR

This chapter describes SOAR capabilities and optimizations from the Application developer’s point of view. To get more details on its internal structure, please refer to SOAR Build Phases section.

Java Symbols Encoding

Java symbols are any of package, type, method, field, or local names. In .class files, they are encoded in UTF-8. However, SOAR only supports Java symbols composed of characters that can be stored on 8 bits (unsigned byte).

This is typically the case of ISO-8859-X encoding family.

If you try to build an Application that includes an unsupported Java symbol you will get the following error:

Unsupported Java symbol XXX in file YYY. A character cannot be stored on an unsigned byte.

Note

Classpath *.list files are standard Java properties files that are encoded in ISO-8859-1 (Latin-1). If you need to refer to a Java Symbol that contains a character out of this charset, you must declare the character using the \uHHHH notation where HHHH is the hexadecimal index of the character in the Unicode character set.

Class Initialization Code

SOAR complies with the deterministic class initialization (<clinit>) order specified in [BON] specification. The application is statically analyzed from its entry points in order to generate a clinit dependency graph. The computed clinit sequence is the result of the topological sort of the dependency graph. An error is thrown if the clinit dependency graph contains cycles.

A clinit map file (ending with extension .clinitmap) is generated beside the SOAR object file. It describes for each clinit dependency:

  • the types involved
  • the kind of dependency
  • the stack calls between the two types

In case of complex clinit dependencies graph, the SOAR may detect static cycles (circular dependencies) and fail with an error. In such case, you have to manually cut-off the cycles, by providing the explicit clinit dependencies.

Explicit clinit dependencies are declared in XML files ending with the .clinitdesc extension, at the root of a library or application classpath.

The file has the following format:

<?xml version='1.0' encoding='UTF-8'?>
<clinit>
    <type name="T1" depends="T2"/>
</clinit>

where T1 and T2 are fully qualified names on the form a.b.C. This explicitly forces the SOAR to create a dependency from T1 to T2, and therefore cuts a potentially detected dependency from T2 to T1.

Method Devirtualization

Method devirtualization consists of transforming a virtual method call to a direct method call when possible. A virtual method call is a call to a non-private instance method declared either in an interface or in a class. The Core Engine determines the proper method to call at runtime depending on the actual class of the object. A call to a constructor or a private method is already optimized as a direct method call by the Java compiler.

SOAR automatically optimizes a virtual method call to a direct method call if there is one and only one embedded implementation method.

Note

SOAR generates the list of the embedded methods in the SOAR Information File.

Method Inlining

Method inlining consists of replacing a direct method call with the content of the method. This avoids the creation of a new stack frame context, which can be slower than executing the code itself. Method inlining is transitively applied from leaf to root methods.

The following method code patterns are inlined:

  • empty code after processing assertions and if code removal.
  • call to a constructor with no parameters.
  • call to a private method with no parameters.
  • call to a static method with no parameters, if and only if the caller is also a static method.

Note

Method inlining is performed after method devirtualization, so a virtual method call will be inlined if there is a unique embedded implementation method that matches one of the inlined method code patterns.

Binary Code Verifier

The Binary Code Verifier is the tool that scrutinizes the bytecode instructions for adherence to strict rules and constraints. This process is crucial for preventing runtime errors, security vulnerabilities, and unexpected behavior. It ensures that code loaded by the SOAR is in a consistent state before being linked. Consequently, this guarantees the safe execution of the code by the Core Engine.

Application Build Flow with Binary Code Verifier

Application Build Flow with Binary Code Verifier

The Binary Code Verifier performs tasks including:

  • Type Checking: Verifying that variables and operands are used in a manner consistent with their declared data types, preventing type-related errors at runtime.
  • Bytecode Structure: Ensuring the bytecode is well-formed and follows the structure required by the JVM, which helps prevent memory corruption and crashes.
  • Stack Management: Checking that the operand stack used for calculations and evaluations is properly managed to prevent stack overflows or underflows.
  • Access Control: Verifying that class accesses and method invocations adhere to Java’s access control rules, ensuring data encapsulation and security.
  • Exception Handling: Validating that exception handlers are correctly defined and that exceptions are caught and handled appropriately.
  • Control Flow: Analyzing the flow of control within bytecode to detect anomalies in loops, branches, and jumps that could lead to program instability.

A default implementation, derived from the Apache BCEL Project, is included in the SOAR. If you wish to integrate an alternative implementation, contact our support team for access to the SOAR interface API and integration instructions.

Note

The Binary Code Verifier is enabled by default when building a Sandboxed Application, and disabled by default when building a Standalone Application. See Option(checkbox): Enable Bytecode Verifier for more details.