The field identifier
is the maven-coordinated id for the desugared library configuration file with the group id, the artifact id and the version number joined with colon.
The field configuration_format_version
encodes a versioning number internal to R8/D8 in the form of an unsigned integer. It allows R8/D8 to know if the file given is supported. If the number is between 100 and 200, the file is encoded using the human flags (by opposition to the legacy and machine flags). Human flags are not shipped to external users. Human flags can be converted to machine flags which are shipped to external users. Users internal to Google are allowed to use directly human flags if we can easily update the file without backward compatibility issues.
The field required_compilation_api_level
encodes the minimal Android API level required for the desugared library to be compiled correctly. If the API of library used for compilation of the library or a program using the library is lower than this level, one has to upgrade the SDK version used to be able to use desugared libraries.
The field synthesized_library_classes_package_prefix
is used to prefix type names of synthetic classes created during the L8 compilation. It is also used for minification in the java.
namespace to avoid collisions with platforms.
The field support_all_callbacks_from_library
is set if D8/R8 should generate extra callbacks, i.e., methods that may be called from specific library implementations into the program. Setting it to false may lead to invalid behavior if the library effectively use one of the callbacks, but reduces code size.
The fields common_flags
, library_flags
and program_flags
include the set of rewriting flags required for respectively rewriting both the library and the program, only the library or only the program.
The flags are in a list, where each list entry specifies up to which min API level the set of flags should be applied. During compilation, R8/D8 adds up all the required flags for the min API level specified at compilation.
The following subsections describe each rewriting flag.
prefix: rewrittenPrefix
D8/R8 identifies any class which type matches the prefix, and rewrite such types with the new prefix. Types not present as class types are not rewritten. Implicitly, all synthetic types derived from the matching type are also rewritten (lambdas and backports in the class, etc.). Lastly, types referenced directly or indirectly from other flags (method retargeting, custom conversions, emulated interfaces, api generic type conversion) are identified and rewritten.
The exact list of types is computed when generating the machine specification and the pattern matching never applies to user code, but instead to the desugared library jar and android.jar
.
Example: foo.: f$.
A class present with the type foo.Foo will generate a rewrite rule: foo.Foo -> f$.Foo. A type present foo.Bar, which is not the type of any class, will not generate any rewrite rule.
prefix
D8/R8 identifies any class which type matches the prefix, and maintain such class in desugared library in the java
namespace. Using this flag implicitly means that at runtime, either a class from the bootclasspath with the same name will take precedence and be used, or this class will be used on lower api levels.
Using maintain_prefix
allows desugared library code to work seamlessly with recent apis (no wrappers or conversions required), at the cost of preventing some signature changes (the signature in desugared library, even when shrinking, has to match the library one). This can be done only with classes which behavior is identical between desugared library and platform. Lastly, derived synthetic classes from code in such classes (lambdas, etc.) are still moved to the new namespace to avoid collisions with platform, so one has to be extra careful with package private access being broken in this set-up.
Example: foo.
A class present with the type foo.Foo
will be maintained in the output as foo.Foo
. If synthesized_library_classes_package_prefix
is f$
, then all the derived synthetic classes such as lambdas inside foo.Foo
will be generated as f$.Foo$lambda-hash
.
prefix: { fromPrefix: toPrefix }
D8/R8 identifies any class type matching the prefix, and rewrite the type with the fromPrefix to the type with the toPrefix. This can be useful to generate rewrite rules from types not present in the input.
Example: foo.: { f$.: foo. }
A class present with the type foo.Foo will generate a rewrite rule: f$.Foo -> foo.Foo.
prefix
D8/R8 identifies any class type matching the prefix, does not rewrite it and shrinks it away from the input. This flags takes precedence over rewrite_prefix
and rewrite_derived_prefix
, allowing to disable prefix rewriting on subpatterns.
Example: foo.
No class prefixed with foo. will be rewritten or kept in the output.
method
D8/R8 tries to outline api calls working only on high api levels and requiring conversions as much as possible to share the code and avoid soft verification errors. Methods specified here are never outlined. This is usually worse for the users, unless the api is expected to introspect the stack, in which case the extra frame is confusing.
methodApi: [i0, conversionMethod0, ..., iN, conversionMethodN]
D8/R8 automatically generates conversions surrounding api calls with rewritten types which are specified in custom conversions/wrappers. D8/R8 does not automatically convert types from generic types such as collection items, or conversion requiring to convert multiple values in general
This flag is used to specify a plateform api (methodApi) which parameters or return value require a conversion different from the default one. The value is an array of pair. The pair‘s key (i0, .., iN) is the parameter index if greater or equal to 0, or the return type if -1. The pair’s value (conversionMethod0, .., N) is the conversion method to use to convert the value.
Example: void bar(foo.Foo): [0, foo.Foo FooConverter#convertFoo(f$.Foo)]
When generating conversion for the api bar, the parameter 0 foo.Foo will be converted using FooConverter#convertFoo instead of the default conversion logic.
field: retargetField
D8/R8 rewrites all references from the static field to the static retargetField.
Example: int Foo#bar: int Zorg#foo
D8/R8 rewrites all references to the field named bar in Foo to the field named foo in Zorg.
methodToRetarget: retargetType
D8/R8 identifies all invokes which method resolve to the methodToRetarget, and rewrite it to an invoke to the same method but with the retargetType as holder. If the method is virtual, this converts the invoke to an invoke-static and adds the receiver type as the first parameter.
The retargeting is valid for static methods, private methods and methods effectively final (methods with the final keyword, methods on final classes, which do not override any other method).
When using the flag, the method, if virtual, is considered as effectively final. For retargeting of virtual methods that can be overridden, see retarget_method_with_emulated_dispatch.
Example: Foo Bar#foo(Zorg): DesugarBar
Any invoke which method resolves into the method with return type Foo, name foo, parameter Zorg on the holder Bar, is rewritten to an invoke-static to the same method on DesugarBar. If the method is not static, the rewritten method takes an extra first parameter of type Bar.
methodToRetarget: retargetType
Essentially the same as retarget_method, but for non effectively final virtual method. The flag fails the compilation if the methodToRetarget is static. D8/R8 generates an emulated dispatch scheme so that the method can be retargeted, but the virtual dispatch is still valid and will correctly call the overrides if present.
methodWithCovariantReturnType: alternativeReturnType
Any invoke to methodWithCovariantReturnType will be rewritten to a call to the same method with the alternativeReturnType and a checkcast. This is used to deal with covariant return types which are not present in desugared library.
modifiers method
For the retarget_method and retarget_method_with_emulated_dispatch flags to work, resolution has to find the method to retarget to. In some cases, the method is missing because it's not present on the required compilation level Android SDK, or because the method is private.
This flag amends the library to introduce the method, so resolution can find it and retarget it correctly.
modifiers field
Similar to amend_library_method, adds a field into the library so that field resolution can find it and it can be retargeted.
type
In classes with such type, invokes are not retargeted with the retarget_method and the retarget_method_with_emulated_dispatch flag. In addition, forwarding methods required for retarget_method_with_emulated_dispatch are not introduced in such classes.
libraryInterface: desugaredLibraryInterface
D8/R8 assume the libraryInterface is already in the library, but without the default and static methods present on it. It generates a companion class holding the code for the default and static methods, and a dispatch class which hold the code to support emulated dispatch for the default methods.
methodNotToRewrite
D8/R8 ignroes the methods present here from the emulated interface.
type
Generate wrappers for the given type, including methods from the type and all its super types and interface types. In addition, analyse all invokes resolving into the library. If the invoke includes the type as return or parameter type, automatically surround the library call with conversion code using wrappers. The sequence of instructions with the conversions and the library invoke is outlined and shared if possible.
type: [methods]
Similar to wrapper_conversion, generate wrappers for the given type but ignore the methods listed. This can be used for methods not accessing fields or private methods, either to reduce code size or to work around final methods.
type: conversionType
Similar to wrapper_conversion, but instead of generating wrappers, rely on hand written conversions present on conversionType. The conversions methods must be of the form: Type convert(RewrittenType) RewrittenType convert(Type)
The last field is shrinker_config
, it includes keep rules that are appended by L8 when shrinking the desugared library. It includes keep rules related to reflection inside the desugared library, related to enum to have EnumSet working and to keep the j$ prefix. It also includes various keep rules to suppor common serializers.
Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file for details. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.