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	"path/filepath"
20	"strings"
21	"sync"
22
23	"github.com/google/blueprint/proptools"
24
25	"android/soong/android"
26	"android/soong/cc"
27	"android/soong/cc/config"
28)
29
30var supportedArches = []string{"arm", "arm64", "riscv64", "x86", "x86_64"}
31
32func globalFlags(ctx android.LoadHookContext) ([]string, []string) {
33	var cflags []string
34	var asflags []string
35
36	opt := ctx.Config().GetenvWithDefault("ART_NDEBUG_OPT_FLAG", "-O3")
37	cflags = append(cflags, opt)
38
39	tlab := false
40	gcType := ctx.Config().GetenvWithDefault("ART_DEFAULT_GC_TYPE", "CMC")
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
49	if ctx.Config().IsEnvTrue("ART_HEAP_POISONING") {
50		cflags = append(cflags, "-DART_HEAP_POISONING=1")
51		asflags = append(asflags, "-DART_HEAP_POISONING=1")
52	}
53	if ctx.Config().IsEnvTrue("ART_USE_CXX_INTERPRETER") {
54		cflags = append(cflags, "-DART_USE_CXX_INTERPRETER=1")
55	}
56
57	if !ctx.Config().IsEnvFalse("ART_USE_READ_BARRIER") && ctx.Config().ArtUseReadBarrier() {
58		// Used to change the read barrier type. Valid values are BAKER, TABLELOOKUP.
59		// The default is BAKER.
60		barrierType := ctx.Config().GetenvWithDefault("ART_READ_BARRIER_TYPE", "BAKER")
61		cflags = append(cflags,
62			"-DART_USE_READ_BARRIER=1",
63			"-DART_READ_BARRIER_TYPE_IS_"+barrierType+"=1")
64		asflags = append(asflags,
65			"-DART_USE_READ_BARRIER=1",
66			"-DART_READ_BARRIER_TYPE_IS_"+barrierType+"=1")
67
68		if !ctx.Config().IsEnvFalse("ART_USE_GENERATIONAL_CC") {
69			cflags = append(cflags, "-DART_USE_GENERATIONAL_CC=1")
70		}
71		// Force CC only if ART_USE_READ_BARRIER was set to true explicitly during
72		// build time.
73		if ctx.Config().IsEnvTrue("ART_USE_READ_BARRIER") {
74			cflags = append(cflags, "-DART_FORCE_USE_READ_BARRIER=1")
75		}
76		tlab = true
77	} else if gcType == "CMC" {
78		tlab = true
79	}
80
81	if tlab {
82		cflags = append(cflags, "-DART_USE_TLAB=1")
83	}
84
85	if ctx.Config().IsEnvTrue("ART_FORCE_TRY_PREDICATED_SIMD") {
86		cflags = append(cflags, "-DART_FORCE_TRY_PREDICATED_SIMD=1")
87	}
88
89	// We need larger stack overflow guards for ASAN, as the compiled code will have
90	// larger frame sizes. For simplicity, just use global not-target-specific cflags.
91	// Note: We increase this for both debug and non-debug, as the overflow gap will
92	//       be compiled into managed code. We always preopt (and build core images) with
93	//       the debug version. So make the gap consistent (and adjust for the worst).
94	if len(ctx.Config().SanitizeDevice()) > 0 || len(ctx.Config().SanitizeHost()) > 0 {
95		cflags = append(cflags,
96			"-DART_STACK_OVERFLOW_GAP_arm=16384",
97			"-DART_STACK_OVERFLOW_GAP_arm64=16384",
98			"-DART_STACK_OVERFLOW_GAP_riscv64=16384",
99			"-DART_STACK_OVERFLOW_GAP_x86=16384",
100			"-DART_STACK_OVERFLOW_GAP_x86_64=20480")
101	} else {
102		cflags = append(cflags,
103			"-DART_STACK_OVERFLOW_GAP_arm=8192",
104			"-DART_STACK_OVERFLOW_GAP_arm64=8192",
105			"-DART_STACK_OVERFLOW_GAP_riscv64=8192",
106			"-DART_STACK_OVERFLOW_GAP_x86=8192",
107			"-DART_STACK_OVERFLOW_GAP_x86_64=8192")
108	}
109
110	if ctx.Config().NoBionicPageSizeMacro() {
111		cflags = append(cflags, "-DART_PAGE_SIZE_AGNOSTIC=1")
112	}
113
114	if ctx.Config().IsEnvTrue("ART_ENABLE_ADDRESS_SANITIZER") {
115		// Used to enable full sanitization, i.e., user poisoning, under ASAN.
116		cflags = append(cflags, "-DART_ENABLE_ADDRESS_SANITIZER=1")
117		asflags = append(asflags, "-DART_ENABLE_ADDRESS_SANITIZER=1")
118	}
119
120	if !ctx.Config().IsEnvFalse("USE_D8_DESUGAR") {
121		cflags = append(cflags, "-DUSE_D8_DESUGAR=1")
122	}
123
124	return cflags, asflags
125}
126
127func deviceFlags(ctx android.LoadHookContext) []string {
128	var cflags []string
129	deviceFrameSizeLimit := 1736
130	if len(ctx.Config().SanitizeDevice()) > 0 {
131		deviceFrameSizeLimit = 7400
132	}
133	cflags = append(cflags,
134		fmt.Sprintf("-Wframe-larger-than=%d", deviceFrameSizeLimit),
135		fmt.Sprintf("-DART_FRAME_SIZE_LIMIT=%d", deviceFrameSizeLimit),
136	)
137
138	cflags = append(cflags, "-DART_BASE_ADDRESS="+ctx.Config().LibartImgDeviceBaseAddress())
139	minDelta := ctx.Config().GetenvWithDefault("LIBART_IMG_TARGET_MIN_BASE_ADDRESS_DELTA", "(-0x1000000)")
140	maxDelta := ctx.Config().GetenvWithDefault("LIBART_IMG_TARGET_MAX_BASE_ADDRESS_DELTA", "0x1000000")
141	cflags = append(cflags, "-DART_BASE_ADDRESS_MIN_DELTA="+minDelta)
142	cflags = append(cflags, "-DART_BASE_ADDRESS_MAX_DELTA="+maxDelta)
143
144	return cflags
145}
146
147func hostFlags(ctx android.LoadHookContext) []string {
148	var cflags []string
149	hostFrameSizeLimit := 1736
150	if len(ctx.Config().SanitizeHost()) > 0 {
151		// art/test/137-cfi/cfi.cc
152		// error: stack frame size of 1944 bytes in function 'Java_Main_unwindInProcess'
153		// b/249586057, need larger stack frame for newer clang compilers
154		hostFrameSizeLimit = 10000
155		// cannot add "-fsanitize-address-use-after-return=never" everywhere,
156		// or some file like compiler_driver.o can have stack frame of 30072 bytes.
157		// cflags = append(cflags, "-fsanitize-address-use-after-return=never")
158	}
159	cflags = append(cflags,
160		fmt.Sprintf("-Wframe-larger-than=%d", hostFrameSizeLimit),
161		fmt.Sprintf("-DART_FRAME_SIZE_LIMIT=%d", hostFrameSizeLimit),
162	)
163
164	cflags = append(cflags, "-DART_BASE_ADDRESS="+ctx.Config().LibartImgHostBaseAddress())
165	minDelta := ctx.Config().GetenvWithDefault("LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA", "(-0x1000000)")
166	maxDelta := ctx.Config().GetenvWithDefault("LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA", "0x1000000")
167	cflags = append(cflags, "-DART_BASE_ADDRESS_MIN_DELTA="+minDelta)
168	cflags = append(cflags, "-DART_BASE_ADDRESS_MAX_DELTA="+maxDelta)
169
170	if len(ctx.Config().SanitizeHost()) > 0 && !ctx.Config().IsEnvFalse("ART_ENABLE_ADDRESS_SANITIZER") {
171		// We enable full sanitization on the host by default.
172		cflags = append(cflags, "-DART_ENABLE_ADDRESS_SANITIZER=1")
173	}
174
175	clang_path := filepath.Join(config.ClangDefaultBase, ctx.Config().PrebuiltOS(), config.ClangDefaultVersion)
176	cflags = append(cflags, fmt.Sprintf("-DART_CLANG_PATH=\"%s\"", clang_path))
177
178	return cflags
179}
180
181func globalDefaults(ctx android.LoadHookContext) {
182	type props struct {
183		Target struct {
184			Android struct {
185				Cflags []string
186			}
187			Host struct {
188				Cflags []string
189			}
190		}
191		Cflags   []string
192		Asflags  []string
193		Sanitize struct {
194			Recover []string
195		}
196	}
197
198	p := &props{}
199	p.Cflags, p.Asflags = globalFlags(ctx)
200	p.Target.Android.Cflags = deviceFlags(ctx)
201	p.Target.Host.Cflags = hostFlags(ctx)
202
203	if ctx.Config().IsEnvTrue("ART_DEX_FILE_ACCESS_TRACKING") {
204		p.Cflags = append(p.Cflags, "-DART_DEX_FILE_ACCESS_TRACKING")
205		p.Sanitize.Recover = []string{
206			"address",
207		}
208	}
209
210	ctx.AppendProperties(p)
211}
212
213// Hook that adds flags that are implicit for all cc_art_* modules.
214func addImplicitFlags(ctx android.LoadHookContext) {
215	type props struct {
216		Target struct {
217			Android struct {
218				Cflags []string
219			}
220		}
221	}
222
223	p := &props{}
224	if ctx.Config().IsEnvTrue("ART_TARGET_LINUX") {
225		p.Target.Android.Cflags = []string{"-DART_TARGET", "-DART_TARGET_LINUX"}
226	} else {
227		p.Target.Android.Cflags = []string{"-DART_TARGET", "-DART_TARGET_ANDROID"}
228	}
229
230	ctx.AppendProperties(p)
231}
232
233func customLinker(ctx android.LoadHookContext) {
234	linker := ctx.Config().Getenv("CUSTOM_TARGET_LINKER")
235	type props struct {
236		DynamicLinker string
237	}
238
239	p := &props{}
240	if linker != "" {
241		p.DynamicLinker = linker
242	}
243
244	ctx.AppendProperties(p)
245}
246
247func prefer32Bit(ctx android.LoadHookContext) {
248	type props struct {
249		Target struct {
250			Host struct {
251				Compile_multilib *string
252			}
253		}
254	}
255
256	p := &props{}
257	if ctx.Config().IsEnvTrue("HOST_PREFER_32_BIT") {
258		p.Target.Host.Compile_multilib = proptools.StringPtr("prefer32")
259	}
260
261	// Prepend to make it overridable in the blueprints. Note that it doesn't work
262	// to override the property in a cc_defaults module.
263	ctx.PrependProperties(p)
264}
265
266var testMapKey = android.NewOnceKey("artTests")
267
268func testMap(config android.Config) map[string][]string {
269	return config.Once(testMapKey, func() interface{} {
270		return make(map[string][]string)
271	}).(map[string][]string)
272}
273
274func testInstall(ctx android.InstallHookContext) {
275	testMap := testMap(ctx.Config())
276
277	var name string
278	if ctx.Host() {
279		name = "host_"
280	} else {
281		name = "device_"
282	}
283	name += ctx.Arch().ArchType.String() + "_" + ctx.ModuleName()
284
285	artTestMutex.Lock()
286	defer artTestMutex.Unlock()
287
288	tests := testMap[name]
289	tests = append(tests, ctx.Path().String())
290	testMap[name] = tests
291}
292
293var testcasesContentKey = android.NewOnceKey("artTestcasesContent")
294
295func testcasesContent(config android.Config) map[string]string {
296	return config.Once(testcasesContentKey, func() interface{} {
297		return make(map[string]string)
298	}).(map[string]string)
299}
300
301// Binaries and libraries also need to be copied in the testcases directory for
302// running tests on host.  This method adds module to the list of needed files.
303// The 'key' is the file in testcases and 'value' is the path to copy it from.
304// The actual copy will be done in make since soong does not do installations.
305func addTestcasesFile(ctx android.InstallHookContext) {
306	if ctx.Os() != ctx.Config().BuildOS || ctx.Target().HostCross || ctx.Module().IsSkipInstall() {
307		return
308	}
309
310	testcasesContent := testcasesContent(ctx.Config())
311
312	artTestMutex.Lock()
313	defer artTestMutex.Unlock()
314
315	src := ctx.SrcPath().String()
316	path := strings.Split(ctx.Path().String(), "/")
317	// Keep last two parts of the install path (e.g. bin/dex2oat).
318	dst := strings.Join(path[len(path)-2:], "/")
319	if oldSrc, ok := testcasesContent[dst]; ok {
320		ctx.ModuleErrorf("Conflicting sources for %s: %s and %s", dst, oldSrc, src)
321	}
322	testcasesContent[dst] = src
323}
324
325var artTestMutex sync.Mutex
326
327func init() {
328	artModuleTypes := []string{
329		"art_cc_library",
330		"art_cc_library_static",
331		"art_cc_binary",
332		"art_cc_test",
333		"art_cc_test_library",
334		"art_cc_defaults",
335		"art_global_defaults",
336	}
337	android.AddNeverAllowRules(
338		android.NeverAllow().
339			NotIn("art", "external/vixl").
340			ModuleType(artModuleTypes...))
341
342	android.RegisterModuleType("art_cc_library", artLibrary)
343	android.RegisterModuleType("art_cc_library_static", artStaticLibrary)
344	android.RegisterModuleType("art_cc_binary", artBinary)
345	android.RegisterModuleType("art_cc_test", artTest)
346	android.RegisterModuleType("art_cc_test_library", artTestLibrary)
347	android.RegisterModuleType("art_cc_defaults", artDefaultsFactory)
348	android.RegisterModuleType("art_global_defaults", artGlobalDefaultsFactory)
349}
350
351func artGlobalDefaultsFactory() android.Module {
352	module := artDefaultsFactory()
353	android.AddLoadHook(module, addImplicitFlags)
354	android.AddLoadHook(module, globalDefaults)
355
356	return module
357}
358
359func artDefaultsFactory() android.Module {
360	c := &codegenProperties{}
361	module := cc.DefaultsFactory(c)
362	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, staticAndSharedLibrary) })
363
364	return module
365}
366
367func artLibrary() android.Module {
368	module := cc.LibraryFactory()
369
370	installCodegenCustomizer(module, staticAndSharedLibrary)
371
372	android.AddLoadHook(module, addImplicitFlags)
373	android.AddInstallHook(module, addTestcasesFile)
374	return module
375}
376
377func artStaticLibrary() android.Module {
378	module := cc.LibraryStaticFactory()
379
380	installCodegenCustomizer(module, staticLibrary)
381
382	android.AddLoadHook(module, addImplicitFlags)
383	return module
384}
385
386func artBinary() android.Module {
387	module := cc.BinaryFactory()
388
389	android.AddLoadHook(module, addImplicitFlags)
390	android.AddLoadHook(module, customLinker)
391	android.AddLoadHook(module, prefer32Bit)
392	android.AddInstallHook(module, addTestcasesFile)
393	return module
394}
395
396func artTest() android.Module {
397	module := cc.NewTest(android.HostAndDeviceSupported).Init()
398
399	installCodegenCustomizer(module, binary)
400
401	android.AddLoadHook(module, addImplicitFlags)
402	android.AddLoadHook(module, customLinker)
403	android.AddLoadHook(module, prefer32Bit)
404	android.AddInstallHook(module, testInstall)
405	return module
406}
407
408func artTestLibrary() android.Module {
409	module := cc.TestLibraryFactory()
410
411	installCodegenCustomizer(module, staticAndSharedLibrary)
412
413	android.AddLoadHook(module, addImplicitFlags)
414	android.AddLoadHook(module, prefer32Bit)
415	android.AddInstallHook(module, testInstall)
416	return module
417}
418