1// Copyright (C) 2016 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package art
16
17import (
18	"fmt"
19	"log"
20	"sync"
21
22	"github.com/google/blueprint/proptools"
23
24	"android/soong/android"
25	"android/soong/apex"
26	"android/soong/cc"
27)
28
29var supportedArches = []string{"arm", "arm64", "x86", "x86_64"}
30
31func globalFlags(ctx android.LoadHookContext) ([]string, []string) {
32	var cflags []string
33	var asflags []string
34
35	opt := ctx.Config().GetenvWithDefault("ART_NDEBUG_OPT_FLAG", "-O3")
36	cflags = append(cflags, opt)
37
38	tlab := false
39
40	gcType := ctx.Config().GetenvWithDefault("ART_DEFAULT_GC_TYPE", "CMS")
41
42	if ctx.Config().IsEnvTrue("ART_TEST_DEBUG_GC") {
43		gcType = "SS"
44		tlab = true
45	}
46
47	cflags = append(cflags, "-DART_DEFAULT_GC_TYPE_IS_"+gcType)
48	if tlab {
49		cflags = append(cflags, "-DART_USE_TLAB=1")
50	}
51
52	imtSize := ctx.Config().GetenvWithDefault("ART_IMT_SIZE", "43")
53	cflags = append(cflags, "-DIMT_SIZE="+imtSize)
54
55	if ctx.Config().IsEnvTrue("ART_HEAP_POISONING") {
56		cflags = append(cflags, "-DART_HEAP_POISONING=1")
57		asflags = append(asflags, "-DART_HEAP_POISONING=1")
58	}
59	if ctx.Config().IsEnvTrue("ART_USE_CXX_INTERPRETER") {
60		cflags = append(cflags, "-DART_USE_CXX_INTERPRETER=1")
61	}
62
63	if !ctx.Config().IsEnvFalse("ART_USE_READ_BARRIER") && ctx.Config().ArtUseReadBarrier() {
64		// Used to change the read barrier type. Valid values are BAKER, BROOKS,
65		// TABLELOOKUP. The default is BAKER.
66		barrierType := ctx.Config().GetenvWithDefault("ART_READ_BARRIER_TYPE", "BAKER")
67		cflags = append(cflags,
68			"-DART_USE_READ_BARRIER=1",
69			"-DART_READ_BARRIER_TYPE_IS_"+barrierType+"=1")
70		asflags = append(asflags,
71			"-DART_USE_READ_BARRIER=1",
72			"-DART_READ_BARRIER_TYPE_IS_"+barrierType+"=1")
73	}
74
75	if !ctx.Config().IsEnvFalse("ART_USE_GENERATIONAL_CC") {
76		cflags = append(cflags, "-DART_USE_GENERATIONAL_CC=1")
77	}
78
79	cdexLevel := ctx.Config().GetenvWithDefault("ART_DEFAULT_COMPACT_DEX_LEVEL", "fast")
80	cflags = append(cflags, "-DART_DEFAULT_COMPACT_DEX_LEVEL="+cdexLevel)
81
82	// We need larger stack overflow guards for ASAN, as the compiled code will have
83	// larger frame sizes. For simplicity, just use global not-target-specific cflags.
84	// Note: We increase this for both debug and non-debug, as the overflow gap will
85	//       be compiled into managed code. We always preopt (and build core images) with
86	//       the debug version. So make the gap consistent (and adjust for the worst).
87	if len(ctx.Config().SanitizeDevice()) > 0 || len(ctx.Config().SanitizeHost()) > 0 {
88		cflags = append(cflags,
89			"-DART_STACK_OVERFLOW_GAP_arm=8192",
90			"-DART_STACK_OVERFLOW_GAP_arm64=16384",
91			"-DART_STACK_OVERFLOW_GAP_x86=16384",
92			"-DART_STACK_OVERFLOW_GAP_x86_64=20480")
93	} else {
94		cflags = append(cflags,
95			"-DART_STACK_OVERFLOW_GAP_arm=8192",
96			"-DART_STACK_OVERFLOW_GAP_arm64=8192",
97			"-DART_STACK_OVERFLOW_GAP_x86=8192",
98			"-DART_STACK_OVERFLOW_GAP_x86_64=8192")
99	}
100
101	if ctx.Config().IsEnvTrue("ART_ENABLE_ADDRESS_SANITIZER") {
102		// Used to enable full sanitization, i.e., user poisoning, under ASAN.
103		cflags = append(cflags, "-DART_ENABLE_ADDRESS_SANITIZER=1")
104		asflags = append(asflags, "-DART_ENABLE_ADDRESS_SANITIZER=1")
105	}
106
107	if !ctx.Config().IsEnvFalse("USE_D8_DESUGAR") {
108		cflags = append(cflags, "-DUSE_D8_DESUGAR=1")
109	}
110
111	return cflags, asflags
112}
113
114func debugFlags(ctx android.LoadHookContext) []string {
115	var cflags []string
116
117	opt := ctx.Config().GetenvWithDefault("ART_DEBUG_OPT_FLAG", "-O2")
118	cflags = append(cflags, opt)
119
120	return cflags
121}
122
123func deviceFlags(ctx android.LoadHookContext) []string {
124	var cflags []string
125	deviceFrameSizeLimit := 1736
126	if len(ctx.Config().SanitizeDevice()) > 0 {
127		deviceFrameSizeLimit = 7400
128	}
129	cflags = append(cflags,
130		fmt.Sprintf("-Wframe-larger-than=%d", deviceFrameSizeLimit),
131		fmt.Sprintf("-DART_FRAME_SIZE_LIMIT=%d", deviceFrameSizeLimit),
132	)
133
134	cflags = append(cflags, "-DART_BASE_ADDRESS="+ctx.Config().LibartImgDeviceBaseAddress())
135	if ctx.Config().IsEnvTrue("ART_TARGET_LINUX") {
136		cflags = append(cflags, "-DART_TARGET_LINUX")
137	} else {
138		cflags = append(cflags, "-DART_TARGET_ANDROID")
139	}
140	minDelta := ctx.Config().GetenvWithDefault("LIBART_IMG_TARGET_MIN_BASE_ADDRESS_DELTA", "-0x1000000")
141	maxDelta := ctx.Config().GetenvWithDefault("LIBART_IMG_TARGET_MAX_BASE_ADDRESS_DELTA", "0x1000000")
142	cflags = append(cflags, "-DART_BASE_ADDRESS_MIN_DELTA="+minDelta)
143	cflags = append(cflags, "-DART_BASE_ADDRESS_MAX_DELTA="+maxDelta)
144
145	return cflags
146}
147
148func hostFlags(ctx android.LoadHookContext) []string {
149	var cflags []string
150	hostFrameSizeLimit := 1736
151	if len(ctx.Config().SanitizeHost()) > 0 {
152		// art/test/137-cfi/cfi.cc
153		// error: stack frame size of 1944 bytes in function 'Java_Main_unwindInProcess'
154		hostFrameSizeLimit = 6400
155	}
156	cflags = append(cflags,
157		fmt.Sprintf("-Wframe-larger-than=%d", hostFrameSizeLimit),
158		fmt.Sprintf("-DART_FRAME_SIZE_LIMIT=%d", hostFrameSizeLimit),
159	)
160
161	cflags = append(cflags, "-DART_BASE_ADDRESS="+ctx.Config().LibartImgHostBaseAddress())
162	minDelta := ctx.Config().GetenvWithDefault("LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA", "-0x1000000")
163	maxDelta := ctx.Config().GetenvWithDefault("LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA", "0x1000000")
164	cflags = append(cflags, "-DART_BASE_ADDRESS_MIN_DELTA="+minDelta)
165	cflags = append(cflags, "-DART_BASE_ADDRESS_MAX_DELTA="+maxDelta)
166
167	if len(ctx.Config().SanitizeHost()) > 0 && !ctx.Config().IsEnvFalse("ART_ENABLE_ADDRESS_SANITIZER") {
168		// We enable full sanitization on the host by default.
169		cflags = append(cflags, "-DART_ENABLE_ADDRESS_SANITIZER=1")
170	}
171
172	return cflags
173}
174
175func globalDefaults(ctx android.LoadHookContext) {
176	type props struct {
177		Target struct {
178			Android struct {
179				Cflags []string
180			}
181			Host struct {
182				Cflags []string
183			}
184		}
185		Cflags   []string
186		Asflags  []string
187		Sanitize struct {
188			Recover []string
189		}
190	}
191
192	p := &props{}
193	p.Cflags, p.Asflags = globalFlags(ctx)
194	p.Target.Android.Cflags = deviceFlags(ctx)
195	p.Target.Host.Cflags = hostFlags(ctx)
196
197	if ctx.Config().IsEnvTrue("ART_DEX_FILE_ACCESS_TRACKING") {
198		p.Cflags = append(p.Cflags, "-DART_DEX_FILE_ACCESS_TRACKING")
199		p.Sanitize.Recover = []string{
200			"address",
201		}
202	}
203
204	ctx.AppendProperties(p)
205}
206
207func debugDefaults(ctx android.LoadHookContext) {
208	type props struct {
209		Cflags []string
210	}
211
212	p := &props{}
213	p.Cflags = debugFlags(ctx)
214	ctx.AppendProperties(p)
215}
216
217func customLinker(ctx android.LoadHookContext) {
218	linker := ctx.Config().Getenv("CUSTOM_TARGET_LINKER")
219	type props struct {
220		DynamicLinker string
221	}
222
223	p := &props{}
224	if linker != "" {
225		p.DynamicLinker = linker
226	}
227
228	ctx.AppendProperties(p)
229}
230
231func prefer32Bit(ctx android.LoadHookContext) {
232	type props struct {
233		Target struct {
234			Host struct {
235				Compile_multilib *string
236			}
237		}
238	}
239
240	p := &props{}
241	if ctx.Config().IsEnvTrue("HOST_PREFER_32_BIT") {
242		p.Target.Host.Compile_multilib = proptools.StringPtr("prefer32")
243	}
244
245	// Prepend to make it overridable in the blueprints. Note that it doesn't work
246	// to override the property in a cc_defaults module.
247	ctx.PrependProperties(p)
248}
249
250var testMapKey = android.NewOnceKey("artTests")
251
252func testMap(config android.Config) map[string][]string {
253	return config.Once(testMapKey, func() interface{} {
254		return make(map[string][]string)
255	}).(map[string][]string)
256}
257
258func testInstall(ctx android.InstallHookContext) {
259	testMap := testMap(ctx.Config())
260
261	var name string
262	if ctx.Host() {
263		name = "host_"
264	} else {
265		name = "device_"
266	}
267	name += ctx.Arch().ArchType.String() + "_" + ctx.ModuleName()
268
269	artTestMutex.Lock()
270	defer artTestMutex.Unlock()
271
272	tests := testMap[name]
273	tests = append(tests, ctx.Path().ToMakePath().String())
274	testMap[name] = tests
275}
276
277var artTestMutex sync.Mutex
278
279func init() {
280	artModuleTypes := []string{
281		"art_cc_library",
282		"art_cc_library_static",
283		"art_cc_binary",
284		"art_cc_test",
285		"art_cc_test_library",
286		"art_cc_defaults",
287		"libart_cc_defaults",
288		"libart_static_cc_defaults",
289		"art_global_defaults",
290		"art_debug_defaults",
291		"art_apex_test_host",
292	}
293	android.AddNeverAllowRules(
294		android.NeverAllow().
295			NotIn("art", "external/vixl").
296			ModuleType(artModuleTypes...))
297
298	android.RegisterModuleType("art_cc_library", artLibrary)
299	android.RegisterModuleType("art_cc_library_static", artStaticLibrary)
300	android.RegisterModuleType("art_cc_binary", artBinary)
301	android.RegisterModuleType("art_cc_test", artTest)
302	android.RegisterModuleType("art_cc_test_library", artTestLibrary)
303	android.RegisterModuleType("art_cc_defaults", artDefaultsFactory)
304	android.RegisterModuleType("libart_cc_defaults", libartDefaultsFactory)
305	android.RegisterModuleType("libart_static_cc_defaults", libartStaticDefaultsFactory)
306	android.RegisterModuleType("art_global_defaults", artGlobalDefaultsFactory)
307	android.RegisterModuleType("art_debug_defaults", artDebugDefaultsFactory)
308
309	// ART apex is special because it must include dexpreopt files for bootclasspath jars.
310	android.RegisterModuleType("art_apex", artApexBundleFactory)
311	android.RegisterModuleType("art_apex_test", artTestApexBundleFactory)
312
313	// TODO: This makes the module disable itself for host if HOST_PREFER_32_BIT is
314	// set. We need this because the multilib types of binaries listed in the apex
315	// rule must match the declared type. This is normally not difficult but HOST_PREFER_32_BIT
316	// changes this to 'prefer32' on all host binaries. Since HOST_PREFER_32_BIT is
317	// only used for testing we can just disable the module.
318	// See b/120617876 for more information.
319	android.RegisterModuleType("art_apex_test_host", artHostTestApexBundleFactory)
320}
321
322func artApexBundleFactory() android.Module {
323	return apex.ApexBundleFactory(false /*testApex*/, true /*artApex*/)
324}
325
326func artTestApexBundleFactory() android.Module {
327	return apex.ApexBundleFactory(true /*testApex*/, true /*artApex*/)
328}
329
330func artHostTestApexBundleFactory() android.Module {
331	module := apex.ApexBundleFactory(true /*testApex*/, true /*artApex*/)
332	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
333		if ctx.Config().IsEnvTrue("HOST_PREFER_32_BIT") {
334			type props struct {
335				Target struct {
336					Host struct {
337						Enabled *bool
338					}
339				}
340			}
341
342			p := &props{}
343			p.Target.Host.Enabled = proptools.BoolPtr(false)
344			ctx.AppendProperties(p)
345			log.Print("Disabling host build of " + ctx.ModuleName() + " for HOST_PREFER_32_BIT=true")
346		}
347	})
348
349	return module
350}
351
352func artGlobalDefaultsFactory() android.Module {
353	module := artDefaultsFactory()
354	android.AddLoadHook(module, globalDefaults)
355
356	return module
357}
358
359func artDebugDefaultsFactory() android.Module {
360	module := artDefaultsFactory()
361	android.AddLoadHook(module, debugDefaults)
362
363	return module
364}
365
366func artDefaultsFactory() android.Module {
367	c := &codegenProperties{}
368	module := cc.DefaultsFactory(c)
369	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, staticAndSharedLibrary) })
370
371	return module
372}
373
374func libartDefaultsFactory() android.Module {
375	c := &codegenProperties{}
376	module := cc.DefaultsFactory(c)
377	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, staticAndSharedLibrary) })
378
379	return module
380}
381
382func libartStaticDefaultsFactory() android.Module {
383	c := &codegenProperties{}
384	module := cc.DefaultsFactory(c)
385	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, staticLibrary) })
386
387	return module
388}
389
390func artLibrary() android.Module {
391	module := cc.LibraryFactory()
392
393	installCodegenCustomizer(module, staticAndSharedLibrary)
394
395	return module
396}
397
398func artStaticLibrary() android.Module {
399	module := cc.LibraryStaticFactory()
400
401	installCodegenCustomizer(module, staticLibrary)
402
403	return module
404}
405
406func artBinary() android.Module {
407	module := cc.BinaryFactory()
408
409	android.AddLoadHook(module, customLinker)
410	android.AddLoadHook(module, prefer32Bit)
411	return module
412}
413
414func artTest() android.Module {
415	module := cc.TestFactory()
416
417	installCodegenCustomizer(module, binary)
418
419	android.AddLoadHook(module, customLinker)
420	android.AddLoadHook(module, prefer32Bit)
421	android.AddInstallHook(module, testInstall)
422	return module
423}
424
425func artTestLibrary() android.Module {
426	module := cc.TestLibraryFactory()
427
428	installCodegenCustomizer(module, staticAndSharedLibrary)
429
430	android.AddLoadHook(module, prefer32Bit)
431	android.AddInstallHook(module, testInstall)
432	return module
433}
434