blob: c819865256329c866f94e458998fda66f1199377 [file] [log] [blame]
Ian Zernydcb172e2022-02-22 15:36:45 +01001#!/usr/bin/env python3
Ian Zerny5ffa58f2020-02-26 08:37:14 +01002# Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
3# for details. All rights reserved. Use of this source code is governed by a
4# BSD-style license that can be found in the LICENSE file.
5
6import argparse
7import os
Christoffer Quist Adamsen3f21c2b2023-02-28 09:37:22 +01008import shutil
Ian Zerny5ffa58f2020-02-26 08:37:14 +01009import subprocess
10import sys
Christoffer Quist Adamsenb6b1c702024-01-31 10:12:45 +010011import time
Ian Zerny5ffa58f2020-02-26 08:37:14 +010012import zipfile
13
Ian Zerny0e53ff12021-06-15 13:40:14 +020014import archive
Søren Gjesse1c8899c2023-11-23 12:06:17 +010015import gradle
Ian Zerny0e53ff12021-06-15 13:40:14 +020016import jdk
17import retrace
Ian Zerny5ffa58f2020-02-26 08:37:14 +010018import utils
19
20
21def make_parser():
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +020022 parser = argparse.ArgumentParser(description='Compile a dump artifact.')
23 parser.add_argument('--summary',
24 help='List a summary of the contents of the dumps.',
25 default=False,
26 action='store_true')
27 parser.add_argument('-d',
28 '--dump',
29 help='Dump file or directory to compile',
30 default=None)
31 parser.add_argument('-o',
32 '--output',
33 help='File to output (defaults to out.jar in temp)',
34 default=None)
35 parser.add_argument(
36 '--temp',
37 help=
38 'Temp directory to extract the dump to, allows you to rerun the command'
39 ' more easily in the terminal with changes',
40 default=None)
41 parser.add_argument('-c',
42 '--compiler',
43 help='Compiler to use',
44 default=None)
45 parser.add_argument('--minify',
46 help='Force enable/disable minification'
47 ' (defaults to app proguard config)',
48 choices=['default', 'force-enable', 'force-disable'],
49 default='default')
50 parser.add_argument('--optimize',
51 help='Force enable/disable optimizations'
52 ' (defaults to app proguard config)',
53 choices=['default', 'force-enable', 'force-disable'],
54 default='default')
55 parser.add_argument('--shrink',
56 help='Force enable/disable shrinking'
57 ' (defaults to app proguard config)',
58 choices=['default', 'force-enable', 'force-disable'],
59 default='default')
60 parser.add_argument(
61 '-v',
62 '--version',
63 help='Compiler version to use (default read from dump version file).'
64 'Valid arguments are:'
65 ' "main" to run from your own tree,'
66 ' "source" to run from build classes directly,'
67 ' "X.Y.Z" to run a specific version, or'
68 ' <hash> to run that hash from main.',
69 default=None)
70 parser.add_argument('--r8-jar', help='Path to an R8 jar.', default=None)
71 parser.add_argument('--r8-flags',
72 '--r8_flags',
73 help='Additional option(s) for the compiler.')
74 parser.add_argument('--pg-conf',
75 '--pg_conf',
76 help='Keep rule file(s).',
77 action='append')
78 parser.add_argument('--override',
79 help='Do not override any extracted dump in temp-dir',
80 default=False,
81 action='store_true')
82 parser.add_argument(
83 '--nolib',
84 help='Use the non-lib distribution (default uses the lib distribution)',
85 default=False,
86 action='store_true')
87 parser.add_argument('--print-times',
88 help='Print timing information from r8',
89 default=False,
90 action='store_true')
91 parser.add_argument(
92 '--disable-assertions',
93 '--disable_assertions',
94 '-da',
95 help=
96 'Disable Java assertions when running the compiler (default enabled)',
97 default=False,
98 action='store_true')
Søren Gjessef8772cb2023-11-24 09:55:23 +010099 parser.add_argument(
100 '--enable-test-assertions',
101 '--enable_test_assertions',
102 help=
103 'Enable additional test assertions when running the compiler (default disabled)',
104 default=False,
105 action='store_true')
Christoffer Quist Adamsenfa1c2ee2024-01-02 12:30:34 +0100106 parser.add_argument('--java-opts',
107 '--java-opts',
108 '-J',
109 metavar='<JVM argument(s)>',
110 default=[],
111 action='append',
112 help='Additional options to pass to JVM invocation')
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200113 parser.add_argument('--classfile',
114 help='Run with classfile output',
115 default=False,
116 action='store_true')
117 parser.add_argument(
118 '--debug-agent',
119 help=
120 'Enable Java debug agent and suspend compilation (default disabled)',
121 default=False,
122 action='store_true')
123 parser.add_argument('--xmx',
124 help='Set JVM max heap size (-Xmx)',
125 default=None)
126 parser.add_argument('--threads',
127 help='Set the number of threads to use',
128 default=None)
129 parser.add_argument(
130 '--min-api',
131 help='Set min-api (default read from dump properties file)',
132 default=None)
133 parser.add_argument('--desugared-lib',
134 help='Set desugared-library (default set from dump)',
135 default=None)
136 parser.add_argument(
137 '--disable-desugared-lib',
138 help='Disable desugared-libary if it will be set from dump',
139 default=False,
140 action='store_true')
141 parser.add_argument('--loop',
142 help='Run the compilation in a loop',
143 default=False,
144 action='store_true')
145 parser.add_argument('--enable-missing-library-api-modeling',
146 help='Run with api modeling',
147 default=False,
148 action='store_true')
149 parser.add_argument('--android-platform-build',
150 help='Run as a platform build',
151 default=False,
152 action='store_true')
153 parser.add_argument('--compilation-mode',
154 '--compilation_mode',
155 help='Run compilation in specified mode',
156 choices=['debug', 'release'],
157 default=None)
Søren Gjesse1c8899c2023-11-23 12:06:17 +0100158 parser.add_argument(
Søren Gjesse95597812023-11-23 15:00:37 +0100159 '--ignore-features',
160 help="Don't split into features when features are present."
Christoffer Quist Adamsenfa1c2ee2024-01-02 12:30:34 +0100161 ' Instead include feature code in main app output.'
162 ' This is always the case when compiler is d8.',
Søren Gjesse95597812023-11-23 15:00:37 +0100163 default=False,
164 action='store_true')
Christoffer Quist Adamsenfa1c2ee2024-01-02 12:30:34 +0100165 parser.add_argument('--no-build',
166 help="Don't build when using --version main",
167 default=False,
168 action='store_true')
Christoffer Quist Adamsenb6b1c702024-01-31 10:12:45 +0100169 parser.add_argument('--print-runtimeraw',
170 metavar='BENCHMARKNAME',
171 help='Print the line \'<BENCHMARKNAME>(RunTimeRaw):' +
172 ' <elapsed> ms\' at the end where <elapsed> is' +
173 ' the elapsed time in milliseconds.')
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200174 return parser
175
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100176
177def error(msg):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200178 print(msg)
179 sys.exit(1)
180
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100181
182class Dump(object):
183
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200184 def __init__(self, directory):
185 self.directory = directory
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100186
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200187 def if_exists(self, name):
188 f = os.path.join(self.directory, name)
189 if os.path.exists(f):
190 return f
191 return None
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100192
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200193 def program_jar(self):
194 return self.if_exists('program.jar')
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100195
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200196 def feature_jars(self):
197 feature_jars = []
198 i = 1
199 while True:
200 feature_jar = self.if_exists('feature-%s.jar' % i)
201 if feature_jar:
202 feature_jars.append(feature_jar)
203 i = i + 1
204 else:
205 return feature_jars
Christoffer Quist Adamsenfcfc63a2020-05-15 19:04:24 +0200206
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200207 def library_jar(self):
208 return self.if_exists('library.jar')
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100209
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200210 def classpath_jar(self):
211 return self.if_exists('classpath.jar')
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100212
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200213 def desugared_library_json(self):
214 return self.if_exists('desugared-library.json')
Clément Béradaae4ca2020-10-27 14:26:41 +0000215
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200216 def proguard_input_map(self):
217 if self.if_exists('proguard_input.config'):
218 print("Unimplemented: proguard_input configuration.")
Clément Béra64a3c4c2020-11-10 08:16:17 +0000219
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200220 def main_dex_list_resource(self):
221 return self.if_exists('main-dex-list.txt')
Clément Béra64a3c4c2020-11-10 08:16:17 +0000222
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200223 def main_dex_rules_resource(self):
224 return self.if_exists('main-dex-rules.txt')
Morten Krogh-Jespersen1e774252021-03-01 16:56:07 +0100225
Rico Wind6a9a0862024-10-02 07:27:20 +0200226 def resource_ap_file(self):
227 return self.if_exists('app-res.ap_')
228
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200229 def art_profile_resources(self):
230 art_profile_resources = []
231 while True:
232 current_art_profile_index = len(art_profile_resources) + 1
233 art_profile_resource = self.if_exists('art-profile-%s.txt' %
234 current_art_profile_index)
235 if art_profile_resource is None:
236 return art_profile_resources
237 art_profile_resources.append(art_profile_resource)
Christoffer Quist Adamsen819273a2023-03-02 15:20:45 +0100238
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200239 def startup_profile_resources(self):
240 startup_profile_resources = []
241 while True:
242 current_startup_profile_index = len(startup_profile_resources) + 1
243 startup_profile_resource = self.if_exists(
244 'startup-profile-%s.txt' % current_startup_profile_index)
245 if startup_profile_resource is None:
246 return startup_profile_resources
247 startup_profile_resources.append(startup_profile_resource)
Christoffer Quist Adamsencd7f7ec2022-08-26 13:39:11 +0200248
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200249 def build_properties_file(self):
250 return self.if_exists('build.properties')
Christoffer Quist Adamsenfcfc63a2020-05-15 19:04:24 +0200251
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200252 def config_file(self):
253 return self.if_exists('proguard.config')
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100254
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200255 def version_file(self):
256 return self.if_exists('r8-version')
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100257
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200258 def version(self):
259 f = self.version_file()
260 if f:
261 return open(f).read().split(' ')[0]
262 return None
263
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100264
Ian Zerny0e53ff12021-06-15 13:40:14 +0200265def read_dump_from_args(args, temp):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200266 if args.dump is None:
267 error("A dump file or directory must be specified")
268 return read_dump(args.dump, temp, args.override)
269
Ian Zerny0e53ff12021-06-15 13:40:14 +0200270
271def read_dump(dump, temp, override=False):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200272 if os.path.isdir(dump):
273 return Dump(dump)
274 dump_file = zipfile.ZipFile(os.path.abspath(dump), 'r')
275 r8_version_file = os.path.join(temp, 'r8-version')
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200276
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200277 if override or not os.path.isfile(r8_version_file):
278 dump_file.extractall(temp)
279 if not os.path.isfile(r8_version_file):
280 error(
281 "Did not extract into %s. Either the zip file is invalid or the "
282 "dump is missing files" % temp)
283 return Dump(temp)
284
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100285
Christoffer Quist Adamsenfcfc63a2020-05-15 19:04:24 +0200286def determine_build_properties(args, dump):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200287 build_properties = {}
288 build_properties_file = dump.build_properties_file()
289 if build_properties_file:
290 with open(build_properties_file) as f:
291 build_properties_contents = f.readlines()
292 for line in build_properties_contents:
293 stripped = line.strip()
294 if stripped:
295 pair = stripped.split('=')
296 build_properties[pair[0]] = pair[1]
297 if 'mode' not in build_properties:
298 build_properties['mode'] = 'release'
299 return build_properties
300
Christoffer Quist Adamsenfcfc63a2020-05-15 19:04:24 +0200301
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100302def determine_version(args, dump):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200303 if args.version is None:
304 return dump.version()
305 return args.version
306
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100307
Søren Gjesse0f8d88b2021-09-28 15:15:54 +0200308def determine_compiler(args, build_properties):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200309 compilers = ['d8', 'r8', 'r8full', 'l8', 'l8d8', 'tracereferences']
310 compiler = args.compiler
311 if not compiler and 'tool' in build_properties:
312 compiler = build_properties.get('tool').lower()
313 if compiler == 'r8':
314 if not 'force-proguard-compatibility' in build_properties:
315 error(
316 "Unable to determine R8 compiler variant from build.properties."
317 " No value for 'force-proguard-compatibility'.")
318 if build_properties.get(
319 'force-proguard-compatibility').lower() == 'false':
320 compiler = compiler + 'full'
321 if compiler == 'TraceReferences':
322 compiler = build_properties.get('tool').lower()
323 if compiler not in compilers:
324 error("Unable to determine a compiler to use. Specified %s,"
325 " Valid options: %s" % (args.compiler, ', '.join(compilers)))
326 return compiler
327
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100328
Christoffer Quist Adamsenfa1c2ee2024-01-02 12:30:34 +0100329def determine_isolated_splits(build_properties, feature_jars):
330 if feature_jars and 'isolated-splits' in build_properties:
331 isolated_splits = build_properties.get('isolated-splits')
332 assert isolated_splits == 'true' or isolated_splits == 'false'
333 return isolated_splits == 'true'
334 return None
335
336
Morten Krogh-Jespersendd12e782023-03-01 16:34:51 +0100337def determine_trace_references_commands(build_properties, output):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200338 trace_ref_consumer = build_properties.get('trace_references_consumer')
339 if trace_ref_consumer == 'com.android.tools.r8.tracereferences.TraceReferencesCheckConsumer':
340 return ["--check"]
341 else:
342 assert trace_ref_consumer == 'com.android.tools.r8.tracereferences.TraceReferencesKeepRules'
343 args = ['--allowobfuscation'
344 ] if build_properties.get('minification') == 'true' else []
345 args.extend(['--keep-rules', '--output', output])
346 return args
347
Morten Krogh-Jespersendd12e782023-03-01 16:34:51 +0100348
Christoffer Quist Adamsen7953d0a2023-02-27 12:08:33 +0100349def is_l8_compiler(compiler):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200350 return compiler.startswith('l8')
351
Christoffer Quist Adamsen7953d0a2023-02-27 12:08:33 +0100352
Christoffer Quist Adamsen3f21c2b2023-02-28 09:37:22 +0100353def is_r8_compiler(compiler):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200354 return compiler.startswith('r8')
355
Christoffer Quist Adamsen3f21c2b2023-02-28 09:37:22 +0100356
357def determine_config_files(args, dump, temp):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200358 if args.pg_conf:
359 config_files = []
360 for config_file in args.pg_conf:
361 dst = os.path.join(temp, 'proguard-%s.config' % len(config_files))
362 shutil.copyfile(config_file, dst)
363 config_files.append(dst)
364 return config_files
365 dump_config_file = dump.config_file()
366 if dump_config_file:
367 return [dump_config_file]
368 return []
369
Christoffer Quist Adamsen3f21c2b2023-02-28 09:37:22 +0100370
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100371def determine_output(args, temp):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200372 if (args.output):
373 return args.output
374 return os.path.join(temp, 'out.jar')
375
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100376
Ian Zerny77bdf5f2020-07-08 11:46:24 +0200377def determine_min_api(args, build_properties):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200378 if args.min_api:
379 return args.min_api
380 if 'min-api' in build_properties:
381 return build_properties.get('min-api')
Ian Zerny9ff31b72021-04-22 11:36:26 +0200382 return None
383
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200384
385def determine_residual_art_profile_output(art_profile, temp):
386 return os.path.join(temp, os.path.basename(art_profile)[:-4] + ".out.txt")
387
388
389def determine_desugared_lib_pg_conf_output(temp):
390 return os.path.join(temp, 'desugared-library-keep-rules.config')
391
392
393def determine_feature_output(feature_jar, temp):
Søren Gjesse95597812023-11-23 15:00:37 +0100394 return os.path.join(
395 args.output if args.output and os.path.isdir(args.output) else temp,
396 os.path.basename(feature_jar)[:-4] + ".out.jar")
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200397
398
399def determine_program_jar(args, dump):
400 if hasattr(args, 'program_jar') and args.program_jar:
401 return args.program_jar
402 return dump.program_jar()
403
404
405def determine_class_file(args, build_properties):
406 return args.classfile \
407 or build_properties.get('backend', 'dex').lower() == 'cf'
408
409
410def determine_android_platform_build(args, build_properties):
411 if args.android_platform_build:
412 return True
413 return build_properties.get('android-platform-build') == 'true'
414
415
416def determine_enable_missing_library_api_modeling(args, build_properties):
417 if args.enable_missing_library_api_modeling:
418 return True
419 return build_properties.get('enable-missing-library-api-modeling') == 'true'
420
421
422def determine_compilation_mode(args, build_properties):
423 if args.compilation_mode:
424 return args.compilation_mode
425 return build_properties.get('mode')
426
427
428def determine_properties(build_properties):
429 args = []
430 for key, value in build_properties.items():
431 # When writing dumps all system properties starting with com.android.tools.r8
432 # are written to the build.properties file in the format
433 # system-property-com.android.tools.r8.XXX=<value>
434 if key.startswith('system-property-'):
435 name = key[len('system-property-'):]
436 if name.endswith('dumpinputtofile') or name.endswith(
437 'dumpinputtodirectory'):
438 continue
439 if len(value) == 0:
440 args.append('-D' + name)
441 else:
442 args.append('-D' + name + '=' + value)
443 return args
444
445
446def download_distribution(version, args, temp):
447 nolib = args.nolib
448 if version == 'main':
Søren Gjesse1c8899c2023-11-23 12:06:17 +0100449 if not args.no_build:
Christoffer Quist Adamsenfa1c2ee2024-01-02 12:30:34 +0100450 gradle.RunGradle(
451 [utils.GRADLE_TASK_R8] if nolib else [utils.GRADLE_TASK_R8LIB])
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200452 return utils.R8_JAR if nolib else utils.R8LIB_JAR
453 if version == 'source':
454 return '%s:%s' % (utils.BUILD_JAVA_MAIN_DIR, utils.ALL_DEPS_JAR)
455 name = 'r8.jar' if nolib else 'r8lib.jar'
456 source = archive.GetUploadDestination(version, name, is_hash(version))
457 dest = os.path.join(temp, 'r8.jar')
458 utils.download_file_from_cloud_storage(source, dest)
459 return dest
460
461
462def clean_configs(files, args):
463 for file in files:
464 clean_config(file, args)
465
466
467def clean_config(file, args):
468 with open(file) as f:
469 lines = f.readlines()
470 minify = args.minify
471 optimize = args.optimize
472 shrink = args.shrink
473 with open(file, 'w') as f:
474 if minify == 'force-disable':
475 print('Adding config line: -dontobfuscate')
476 f.write('-dontobfuscate\n')
477 if optimize == 'force-disable':
478 print('Adding config line: -dontoptimize')
479 f.write('-dontoptimize\n')
480 if shrink == 'force-disable':
481 print('Adding config line: -dontshrink')
482 f.write('-dontshrink\n')
483 for line in lines:
484 if clean_config_line(line, minify, optimize, shrink):
485 print('Removing from config line: \n%s' % line)
486 else:
487 f.write(line)
488
489
490def clean_config_line(line, minify, optimize, shrink):
491 if line.lstrip().startswith('#'):
492 return False
493 if ('-injars' in line or '-libraryjars' in line or '-print' in line or
Rico Windfdc40192023-12-19 11:22:03 +0100494 '-applymapping' in line or '-tracing' in line):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200495 return True
496 if minify == 'force-enable' and '-dontobfuscate' in line:
497 return True
498 if optimize == 'force-enable' and '-dontoptimize' in line:
499 return True
500 if shrink == 'force-enable' and '-dontshrink' in line:
501 return True
502 return False
503
504
505def prepare_r8_wrapper(dist, temp, jdkhome):
506 compile_wrapper_with_javac(
507 dist, temp, jdkhome,
508 os.path.join(
509 utils.REPO_ROOT,
510 'src/main/java/com/android/tools/r8/utils/CompileDumpCompatR8.java')
511 )
512
513
514def prepare_d8_wrapper(dist, temp, jdkhome):
515 compile_wrapper_with_javac(
516 dist, temp, jdkhome,
517 os.path.join(
518 utils.REPO_ROOT,
519 'src/main/java/com/android/tools/r8/utils/CompileDumpD8.java'))
520
521
522def compile_wrapper_with_javac(dist, temp, jdkhome, path):
523 base_path = os.path.join(
524 utils.REPO_ROOT,
525 'src/main/java/com/android/tools/r8/utils/CompileDumpBase.java')
526 cmd = [
527 jdk.GetJavacExecutable(jdkhome),
528 path,
529 base_path,
530 '-d',
531 temp,
532 '-cp',
533 dist,
534 ]
535 utils.PrintCmd(cmd)
536 subprocess.check_output(cmd)
537
538
539def is_hash(version):
540 return len(version) == 40
541
542
543def run1(out, args, otherargs, jdkhome=None, worker_id=None):
544 jvmargs = []
545 compilerargs = []
546 for arg in otherargs:
547 if arg.startswith('-D'):
548 jvmargs.append(arg)
549 else:
550 compilerargs.append(arg)
551 with utils.TempDir() as temp:
552 if out:
553 temp = out
554 if not os.path.exists(temp):
555 os.makedirs(temp)
556 dump = read_dump_from_args(args, temp)
557 if not dump.program_jar():
558 error("Cannot compile dump with no program classes")
559 if not dump.library_jar():
560 print("WARNING: Unexpected lack of library classes in dump")
561 build_properties = determine_build_properties(args, dump)
562 version = determine_version(args, dump)
563 compiler = determine_compiler(args, build_properties)
564 config_files = determine_config_files(args, dump, temp)
565 out = determine_output(args, temp)
566 min_api = determine_min_api(args, build_properties)
567 classfile = determine_class_file(args, build_properties)
568 android_platform_build = determine_android_platform_build(
569 args, build_properties)
570 enable_missing_library_api_modeling = determine_enable_missing_library_api_modeling(
571 args, build_properties)
572 mode = determine_compilation_mode(args, build_properties)
573 jar = args.r8_jar if args.r8_jar else download_distribution(
574 version, args, temp)
575 if ':' not in jar and not os.path.exists(jar):
576 error("Distribution does not exist: " + jar)
577 cmd = [jdk.GetJavaExecutable(jdkhome)]
578 cmd.extend(jvmargs)
579 if args.debug_agent:
580 if not args.nolib:
581 print(
582 "WARNING: Running debugging agent on r8lib is questionable..."
583 )
584 cmd.append(
585 '-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005'
586 )
587 if args.xmx:
588 cmd.append('-Xmx' + args.xmx)
589 if not args.disable_assertions:
590 cmd.append('-ea')
Søren Gjessef8772cb2023-11-24 09:55:23 +0100591 if args.enable_test_assertions:
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200592 cmd.append('-Dcom.android.tools.r8.enableTestAssertions=1')
Christoffer Quist Adamsenfa1c2ee2024-01-02 12:30:34 +0100593 feature_jars = dump.feature_jars()
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200594 if args.print_times:
595 cmd.append('-Dcom.android.tools.r8.printtimes=1')
596 if args.r8_flags:
597 cmd.extend(args.r8_flags.split(' '))
598 if hasattr(args, 'properties'):
599 cmd.extend(args.properties)
600 cmd.extend(determine_properties(build_properties))
Søren Gjessef8772cb2023-11-24 09:55:23 +0100601 cmd.extend(args.java_opts)
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200602 cmd.extend(['-cp', '%s:%s' % (temp, jar)])
603 if compiler == 'd8':
604 prepare_d8_wrapper(jar, temp, jdkhome)
605 cmd.append('com.android.tools.r8.utils.CompileDumpD8')
606 if is_l8_compiler(compiler):
607 cmd.append('com.android.tools.r8.L8')
608 if compiler == 'tracereferences':
609 cmd.append('com.android.tools.r8.tracereferences.TraceReferences')
610 cmd.extend(
611 determine_trace_references_commands(build_properties, out))
612 if compiler.startswith('r8'):
613 prepare_r8_wrapper(jar, temp, jdkhome)
614 cmd.append('com.android.tools.r8.utils.CompileDumpCompatR8')
615 if compiler == 'r8':
616 cmd.append('--compat')
617 if compiler != 'tracereferences':
618 assert mode == 'debug' or mode == 'release'
619 cmd.append('--' + mode)
620 # For recompilation of dumps run_on_app_dumps pass in a program jar.
621 program_jar = determine_program_jar(args, dump)
622 if compiler != 'tracereferences':
623 cmd.append(program_jar)
624 cmd.extend(['--output', out])
625 else:
626 cmd.extend(['--source', program_jar])
Christoffer Quist Adamsenfa1c2ee2024-01-02 12:30:34 +0100627 for feature_jar in feature_jars:
Søren Gjesse95597812023-11-23 15:00:37 +0100628 if not args.ignore_features and compiler != 'd8':
629 cmd.extend([
630 '--feature-jar', feature_jar,
631 determine_feature_output(feature_jar, temp)
632 ])
633 else:
634 cmd.append(feature_jar)
Christoffer Quist Adamsen5c956c72024-01-31 13:31:50 +0100635 if determine_isolated_splits(build_properties, feature_jars):
636 cmd.append('--isolated-splits')
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200637 if dump.library_jar():
638 cmd.extend(['--lib', dump.library_jar()])
Rico Wind6a9a0862024-10-02 07:27:20 +0200639 if dump.resource_ap_file():
640 res_output = os.path.join(temp, 'ap-res-out.ap_')
641 cmd.extend(['--android-resources', dump.resource_ap_file(),
642 res_output])
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200643 if dump.classpath_jar() and not is_l8_compiler(compiler):
644 cmd.extend([
645 '--target' if compiler == 'tracereferences' else '--classpath',
646 dump.classpath_jar()
647 ])
648 if dump.desugared_library_json() and not args.disable_desugared_lib:
649 cmd.extend(['--desugared-lib', dump.desugared_library_json()])
650 if not is_l8_compiler(compiler):
651 cmd.extend([
652 '--desugared-lib-pg-conf-output',
653 determine_desugared_lib_pg_conf_output(temp)
654 ])
655 if (is_r8_compiler(compiler) or compiler == 'l8') and config_files:
656 if hasattr(args,
657 'config_files_consumer') and args.config_files_consumer:
658 args.config_files_consumer(config_files)
659 else:
660 # If we get a dump from the wild we can't use -injars, -libraryjars or
661 # -print{mapping,usage}
662 clean_configs(config_files, args)
663 for config_file in config_files:
664 cmd.extend(['--pg-conf', config_file])
665 cmd.extend(['--pg-map-output', '%s.map' % out])
666 if dump.main_dex_list_resource():
667 cmd.extend(['--main-dex-list', dump.main_dex_list_resource()])
668 if dump.main_dex_rules_resource():
669 cmd.extend(['--main-dex-rules', dump.main_dex_rules_resource()])
670 for art_profile_resource in dump.art_profile_resources():
671 residual_art_profile_output = \
672 determine_residual_art_profile_output(art_profile_resource, temp)
673 cmd.extend([
674 '--art-profile', art_profile_resource,
675 residual_art_profile_output
676 ])
677 for startup_profile_resource in dump.startup_profile_resources():
678 cmd.extend(['--startup-profile', startup_profile_resource])
679 if min_api:
680 cmd.extend(['--min-api', min_api])
681 if classfile:
682 cmd.extend(['--classfile'])
683 if android_platform_build:
684 cmd.extend(['--android-platform-build'])
685 if enable_missing_library_api_modeling:
686 cmd.extend(['--enable-missing-library-api-modeling'])
687 if args.threads:
688 cmd.extend(['--threads', args.threads])
689 cmd.extend(compilerargs)
690 utils.PrintCmd(cmd, worker_id=worker_id)
691 try:
Christoffer Quist Adamsenb6b1c702024-01-31 10:12:45 +0100692 start = time.time()
693 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
694 end = time.time()
695 print(output.decode('utf-8'))
696 if args.print_runtimeraw:
697 benchmark_name = args.print_runtimeraw
698 duration = int((end - start) * 1000)
699 print('')
700 print('%s(RunTimeRaw): %s ms' % (benchmark_name, duration))
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200701 return 0
702 except subprocess.CalledProcessError as e:
703 if args.nolib \
704 or version == 'source' \
705 or not try_retrace_output(e, version, temp):
706 print(e.output.decode('UTF-8'))
707 return 1
708
709
710def try_retrace_output(e, version, temp):
Ian Zerny0e53ff12021-06-15 13:40:14 +0200711 try:
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200712 stacktrace = os.path.join(temp, 'stacktrace')
713 open(stacktrace, 'w+').write(e.output.decode('UTF-8'))
714 print("=" * 80)
715 print(" RETRACED OUTPUT")
716 print("=" * 80)
717 retrace.run(get_map_file(version, temp),
718 stacktrace,
719 None,
720 no_r8lib=False)
721 return True
722 except Exception as e2:
723 print("Failed to retrace for version: %s" % version)
724 print(e2)
725 return False
726
727
728def get_map_file(version, temp):
729 if version == 'main':
730 return utils.R8LIB_MAP
731 download_path = archive.GetUploadDestination(version, 'r8lib.jar.map',
732 is_hash(version))
733 if utils.file_exists_on_cloud_storage(download_path):
734 map_path = os.path.join(temp, 'mapping.map')
735 utils.download_file_from_cloud_storage(download_path, map_path)
736 return map_path
737 else:
738 print('Could not find map file from argument: %s.' % version)
739 return None
740
741
742def summarize_dump_files(dumpfiles):
743 if len(dumpfiles) == 0:
744 error('Summary command expects a list of dumps to summarize')
745 for f in dumpfiles:
746 print(f + ':')
747 try:
748 with utils.TempDir() as temp:
749 dump = read_dump(f, temp)
750 summarize_dump(dump)
751 except IOError as e:
752 print("Error: " + str(e))
753 except zipfile.BadZipfile as e:
754 print("Error: " + str(e))
755
Ian Zerny0e53ff12021-06-15 13:40:14 +0200756
757def summarize_dump(dump):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200758 version = dump.version()
759 if not version:
760 print('No dump version info')
761 return
762 print('version=' + version)
763 props = dump.build_properties_file()
764 if props:
765 with open(props) as props_file:
766 print(props_file.read())
767 if dump.library_jar():
768 print('library.jar present')
769 if dump.classpath_jar():
770 print('classpath.jar present')
771 prog = dump.program_jar()
772 if prog:
773 print('program.jar content:')
774 summarize_jar(prog)
775
Ian Zerny0e53ff12021-06-15 13:40:14 +0200776
777def summarize_jar(jar):
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200778 with zipfile.ZipFile(jar) as zip:
779 pkgs = {}
780 for info in zip.infolist():
781 if info.filename.endswith('.class'):
782 pkg, clazz = os.path.split(info.filename)
783 count = pkgs.get(pkg, 0)
784 pkgs[pkg] = count + 1
785 sorted = list(pkgs.keys())
786 sorted.sort()
787 for p in sorted:
788 print(' ' + p + ': ' + str(pkgs[p]))
789
Ian Zerny0e53ff12021-06-15 13:40:14 +0200790
Søren Gjesse7360f2b2020-08-10 09:13:35 +0200791def run(args, otherargs):
Rico Wind34dcf0d2024-09-30 15:31:30 +0200792 gradle.EnsureJdk()
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200793 if args.summary:
794 summarize_dump_files(otherargs)
795 elif args.loop:
796 count = 1
797 while True:
798 print('Iteration {:03d}'.format(count))
799 out = args.temp
800 if out:
801 out = os.path.join(out, '{:03d}'.format(count))
802 run1(out, args, otherargs)
803 count += 1
804 else:
805 run1(args.temp, args, otherargs)
806
Søren Gjesse7360f2b2020-08-10 09:13:35 +0200807
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100808if __name__ == '__main__':
Christoffer Quist Adamsen2434a4d2023-10-16 11:29:03 +0200809 (args, otherargs) = make_parser().parse_known_args(sys.argv[1:])
810 sys.exit(run(args, otherargs))