Merge "Re-enable the ArraySet fast path with Baker read barriers."
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..835048d
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,6 @@
+subdirs = [
+ "build",
+ "compiler",
+ "runtime",
+ "sigchainlib",
+]
diff --git a/Android.mk b/Android.mk
index 4dc84c4..9d0062b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -76,9 +76,6 @@
########################################################################
# product rules
-include $(art_path)/runtime/Android.mk
-include $(art_path)/runtime/simulator/Android.mk
-include $(art_path)/compiler/Android.mk
include $(art_path)/dexdump/Android.mk
include $(art_path)/dexlist/Android.mk
include $(art_path)/dex2oat/Android.mk
@@ -92,7 +89,6 @@
include $(art_path)/tools/ahat/Android.mk
include $(art_path)/tools/dexfuzz/Android.mk
include $(art_path)/tools/dmtracedump/Android.mk
-include $(art_path)/sigchainlib/Android.mk
include $(art_path)/libart_fake/Android.mk
@@ -555,9 +551,6 @@
art_test_bother :=
TEST_ART_TARGET_SYNC_DEPS :=
-include $(art_path)/runtime/openjdkjvm/Android.mk
-include $(art_path)/runtime/openjdkjvmti/Android.mk
-
# Helper target that depends on boot image creation.
#
# Can be used, for example, to dump initialization failures:
diff --git a/build/Android.bp b/build/Android.bp
new file mode 100644
index 0000000..be7dafd
--- /dev/null
+++ b/build/Android.bp
@@ -0,0 +1,158 @@
+bootstrap_go_package {
+ name: "soong-art",
+ pkgPath: "android/soong/art",
+ deps: [
+ "blueprint",
+ "blueprint-pathtools",
+ "soong",
+ "soong-android",
+ "soong-cc",
+ ],
+ srcs: [
+ "art.go",
+ "codegen.go",
+ "makevars.go",
+ ],
+ pluginFor: ["soong_build"],
+}
+
+art_global_defaults {
+ // Additional flags are computed by art.go
+
+ name: "art_defaults",
+ clang: true,
+ cflags: [
+ "-O3",
+
+ // Base set of cflags used by all things ART.
+ "-fno-rtti",
+ "-ggdb3",
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wstrict-aliasing",
+ "-fstrict-aliasing",
+ "-Wunreachable-code",
+ "-Wredundant-decls",
+ "-Wshadow",
+ "-Wunused",
+ "-fvisibility=protected",
+
+ // Warn about thread safety violations with clang.
+ "-Wthread-safety",
+ "-Wthread-safety-negative",
+
+ // Warn if switch fallthroughs aren't annotated.
+ "-Wimplicit-fallthrough",
+
+ // Enable float equality warnings.
+ "-Wfloat-equal",
+
+ // Enable warning of converting ints to void*.
+ "-Wint-to-void-pointer-cast",
+
+ // Enable warning of wrong unused annotations.
+ "-Wused-but-marked-unused",
+
+ // Enable warning for deprecated language features.
+ "-Wdeprecated",
+
+ // Enable warning for unreachable break & return.
+ "-Wunreachable-code-break",
+ "-Wunreachable-code-return",
+
+ // Bug: http://b/29823425 Disable -Wconstant-conversion and
+ // -Wundefined-var-template for Clang update to r271374
+ "-Wno-constant-conversion",
+ "-Wno-undefined-var-template",
+
+ "-DART_STACK_OVERFLOW_GAP_arm=8192",
+ "-DART_STACK_OVERFLOW_GAP_arm64=8192",
+ "-DART_STACK_OVERFLOW_GAP_mips=16384",
+ "-DART_STACK_OVERFLOW_GAP_mips64=16384",
+ "-DART_STACK_OVERFLOW_GAP_x86=8192",
+ "-DART_STACK_OVERFLOW_GAP_x86_64=8192",
+ ],
+
+ target: {
+ android: {
+ cflags: [
+ "-DART_TARGET",
+
+ // Enable missing-noreturn only on non-Mac. As lots of things are not implemented
+ // for Apple, it's a pain.
+ "-Wmissing-noreturn",
+
+ // To use oprofile_android --callgraph, uncomment this and recompile with
+ // mmma -j art
+ // "-fno-omit-frame-pointer",
+ // "-marm",
+ // "-mapcs",
+ ],
+ include_dirs: [
+ // We optimize Thread::Current() with a direct TLS access. This requires access to a
+ // private Bionic header.
+ "bionic/libc/private",
+ ],
+ },
+ linux: {
+ cflags: [
+ // Enable missing-noreturn only on non-Mac. As lots of things are not implemented for
+ // Apple, it's a pain.
+ "-Wmissing-noreturn",
+ ],
+ },
+ host: {
+ cflags: [
+ // Bug: 15446488. We don't omit the frame pointer to work around
+ // clang/libunwind bugs that cause SEGVs in run-test-004-ThreadStress.
+ "-fno-omit-frame-pointer",
+ ],
+ },
+ },
+
+ codegen: {
+ arm: {
+ cflags: ["-DART_ENABLE_CODEGEN_arm"],
+ },
+ arm64: {
+ cflags: ["-DART_ENABLE_CODEGEN_arm64"],
+ },
+ mips: {
+ cflags: ["-DART_ENABLE_CODEGEN_mips"],
+ },
+ mips64: {
+ cflags: ["-DART_ENABLE_CODEGEN_mips64"],
+ },
+ x86: {
+ cflags: ["-DART_ENABLE_CODEGEN_x86"],
+ },
+ x86_64: {
+ cflags: ["-DART_ENABLE_CODEGEN_x86_64"],
+ },
+ },
+
+ include_dirs: [
+ "external/gtest/include",
+ "external/icu/icu4c/source/common",
+ "external/lz4/lib",
+ "external/valgrind/include",
+ "external/valgrind",
+ "external/vixl/src",
+ "external/zlib",
+ ],
+}
+
+cc_defaults {
+ name: "art_debug_defaults",
+ cflags: [
+ "-O2",
+ "-DDYNAMIC_ANNOTATIONS_ENABLED=1",
+ "-DVIXL_DEBUG",
+ "-UNDEBUG",
+ "-Wno-frame-larger-than=",
+ ],
+ asflags: [
+ "-UNDEBUG",
+ ],
+}
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index c538c4f..fecf0ba 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -373,7 +373,6 @@
COMPILER_GTEST_HOST_SRC_FILES_arm := \
$(COMPILER_GTEST_COMMON_SRC_FILES_arm) \
- compiler/utils/arm/assembler_arm32_test.cc \
compiler/utils/arm/assembler_thumb2_test.cc \
compiler/utils/assembler_thumb_test.cc \
@@ -634,7 +633,7 @@
ifeq ($$(art_target_or_host),target)
$$(eval LOCAL_CLANG := $$(ART_TARGET_CLANG))
$$(eval $$(call set-target-local-cflags-vars,debug))
- LOCAL_SHARED_LIBRARIES += libdl libicuuc libicui18n libnativehelper libz libcutils libvixld-arm64
+ LOCAL_SHARED_LIBRARIES += libdl libicuuc libicui18n libnativehelper libz libcutils libvixld-arm libvixld-arm64
LOCAL_MODULE_PATH_32 := $$(ART_TARGET_NATIVETEST_OUT)/$$(ART_TARGET_ARCH_32)
LOCAL_MODULE_PATH_64 := $$(ART_TARGET_NATIVETEST_OUT)/$$(ART_TARGET_ARCH_64)
LOCAL_MULTILIB := both
@@ -678,7 +677,7 @@
LOCAL_CLANG := $$(ART_HOST_CLANG)
LOCAL_CFLAGS += $$(ART_HOST_CFLAGS) $$(ART_HOST_DEBUG_CFLAGS)
LOCAL_ASFLAGS += $$(ART_HOST_ASFLAGS) $$(ART_HOST_DEBUG_ASFLAGS)
- LOCAL_SHARED_LIBRARIES += libicuuc-host libicui18n-host libnativehelper libziparchive-host libz-host libvixld-arm64
+ LOCAL_SHARED_LIBRARIES += libicuuc-host libicui18n-host libnativehelper libziparchive-host libz-host libvixld-arm libvixld-arm64
LOCAL_LDLIBS := -lpthread -ldl
LOCAL_IS_HOST_MODULE := true
LOCAL_MULTILIB := both
diff --git a/build/art.go b/build/art.go
new file mode 100644
index 0000000..4e64dcf
--- /dev/null
+++ b/build/art.go
@@ -0,0 +1,180 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package art
+
+import (
+ "android/soong"
+ "android/soong/android"
+ "android/soong/cc"
+ "fmt"
+
+ "github.com/google/blueprint"
+)
+
+var supportedArches = []string{"arm", "arm64", "mips", "mips64", "x86", "x86_64"}
+
+func globalFlags(ctx android.BaseContext) ([]string, []string) {
+ var cflags []string
+ var asflags []string
+
+ tlab := false
+
+ gcType := envDefault(ctx, "ART_DEFAULT_GC_TYPE", "CMS")
+
+ if envTrue(ctx, "ART_TEST_DEBUG_GC") {
+ gcType = "SS"
+ tlab = true
+ }
+
+ cflags = append(cflags, "-DART_DEFAULT_GC_TYPE_IS_"+gcType)
+ if tlab {
+ cflags = append(cflags, "-DART_USE_TLAB=1")
+ }
+
+ imtSize := envDefault(ctx, "ART_IMT_SIZE", "43")
+ cflags = append(cflags, "-DIMT_SIZE="+imtSize)
+
+ if envTrue(ctx, "ART_HEAP_POISONING") {
+ cflags = append(cflags, "-DART_HEAP_POISONING=1")
+ asflags = append(asflags, "-DART_HEAP_POISONING=1")
+ }
+
+ if envTrue(ctx, "ART_USE_READ_BARRIER") {
+ // Used to change the read barrier type. Valid values are BAKER, BROOKS, TABLELOOKUP.
+ // The default is BAKER.
+ barrierType := envDefault(ctx, "ART_READ_BARRIER_TYPE", "BAKER")
+ cflags = append(cflags,
+ "-DART_USE_READ_BARRIER=1",
+ "-DART_READ_BARRIER_TYPE_IS_"+barrierType+"=1")
+ asflags = append(asflags,
+ "-DART_USE_READ_BARRIER=1",
+ "-DART_READ_BARRIER_TYPE_IS_"+barrierType+"=1")
+
+ // Temporarily override -fstack-protector-strong with -fstack-protector to avoid a major
+ // slowdown with the read barrier config. b/26744236.
+ cflags = append(cflags, "-fstack-protector")
+ }
+
+ return cflags, asflags
+}
+
+func deviceFlags(ctx android.BaseContext) []string {
+ var cflags []string
+ deviceFrameSizeLimit := 1736
+ if len(ctx.AConfig().SanitizeDevice()) > 0 {
+ deviceFrameSizeLimit = 6400
+ }
+ cflags = append(cflags,
+ fmt.Sprintf("-Wframe-larger-than=%d", deviceFrameSizeLimit),
+ fmt.Sprintf("-DART_FRAME_SIZE_LIMIT=%d", deviceFrameSizeLimit),
+ )
+
+ cflags = append(cflags, "-DART_BASE_ADDRESS="+ctx.AConfig().LibartImgDeviceBaseAddress())
+ if envTrue(ctx, "ART_TARGET_LINUX") {
+ cflags = append(cflags, "-DART_TARGET_LINUX")
+ } else {
+ cflags = append(cflags, "-DART_TARGET_ANDROID")
+ }
+ minDelta := envDefault(ctx, "LIBART_IMG_TARGET_MIN_BASE_ADDRESS_DELTA", "-0x1000000")
+ maxDelta := envDefault(ctx, "LIBART_IMG_TARGET_MAX_BASE_ADDRESS_DELTA", "0x1000000")
+ cflags = append(cflags, "-DART_BASE_ADDRESS_MIN_DELTA="+minDelta)
+ cflags = append(cflags, "-DART_BASE_ADDRESS_MAX_DELTA="+maxDelta)
+
+ return cflags
+}
+
+func hostFlags(ctx android.BaseContext) []string {
+ var cflags []string
+ hostFrameSizeLimit := 1736
+ cflags = append(cflags,
+ fmt.Sprintf("-Wframe-larger-than=%d", hostFrameSizeLimit),
+ fmt.Sprintf("-DART_FRAME_SIZE_LIMIT=%d", hostFrameSizeLimit),
+ )
+
+ cflags = append(cflags, "-DART_BASE_ADDRESS="+ctx.AConfig().LibartImgHostBaseAddress())
+ minDelta := envDefault(ctx, "LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA", "-0x1000000")
+ maxDelta := envDefault(ctx, "LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA", "0x1000000")
+ cflags = append(cflags, "-DART_BASE_ADDRESS_MIN_DELTA="+minDelta)
+ cflags = append(cflags, "-DART_BASE_ADDRESS_MAX_DELTA="+maxDelta)
+
+ return cflags
+}
+
+func (a *artGlobalDefaults) CustomizeProperties(ctx android.CustomizePropertiesContext) {
+ type props struct {
+ Target struct {
+ Android struct {
+ Cflags []string
+ }
+ Host struct {
+ Cflags []string
+ }
+ }
+ Cflags []string
+ Asflags []string
+ }
+
+ p := &props{}
+ p.Cflags, p.Asflags = globalFlags(ctx)
+ p.Target.Android.Cflags = deviceFlags(ctx)
+ p.Target.Host.Cflags = hostFlags(ctx)
+ ctx.AppendProperties(p)
+}
+
+type artGlobalDefaults struct{}
+
+func init() {
+ soong.RegisterModuleType("art_cc_library", artLibrary)
+ soong.RegisterModuleType("art_cc_defaults", artDefaultsFactory)
+ soong.RegisterModuleType("art_global_defaults", artGlobalDefaultsFactory)
+}
+
+func artGlobalDefaultsFactory() (blueprint.Module, []interface{}) {
+ c := &artGlobalDefaults{}
+ module, props := artDefaultsFactory()
+ android.AddCustomizer(module.(android.Module), c)
+
+ return module, props
+}
+
+func artDefaultsFactory() (blueprint.Module, []interface{}) {
+ c := &codegenCustomizer{}
+ module, props := cc.DefaultsFactory(&c.codegenProperties)
+ android.AddCustomizer(module.(android.Module), c)
+
+ return module, props
+}
+
+func artLibrary() (blueprint.Module, []interface{}) {
+ library, _ := cc.NewLibrary(android.HostAndDeviceSupported, true, true)
+ module, props := library.Init()
+
+ c := &codegenCustomizer{}
+ android.AddCustomizer(library, c)
+ props = append(props, &c.codegenProperties)
+ return module, props
+}
+
+func envDefault(ctx android.BaseContext, key string, defaultValue string) string {
+ ret := ctx.AConfig().Getenv(key)
+ if ret == "" {
+ return defaultValue
+ }
+ return ret
+}
+
+func envTrue(ctx android.BaseContext, key string) bool {
+ return ctx.AConfig().Getenv(key) == "true"
+}
diff --git a/build/codegen.go b/build/codegen.go
new file mode 100644
index 0000000..eb2c37d
--- /dev/null
+++ b/build/codegen.go
@@ -0,0 +1,123 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package art
+
+// This file implements the "codegen" property to apply different properties based on the currently
+// selected codegen arches, which defaults to all arches on the host and the primary and secondary
+// arches on the device.
+
+import (
+ "android/soong/android"
+ "sort"
+ "strings"
+)
+
+func (a *codegenCustomizer) CustomizeProperties(ctx android.CustomizePropertiesContext) {
+ c := &a.codegenProperties.Codegen
+
+ var hostArches, deviceArches []string
+
+ e := envDefault(ctx, "ART_HOST_CODEGEN_ARCHS", "")
+ if e == "" {
+ hostArches = supportedArches
+ } else {
+ hostArches = strings.Split(e, " ")
+ }
+
+ e = envDefault(ctx, "ART_TARGET_CODEGEN_ARCHS", "")
+ if e == "" {
+ deviceArches = defaultDeviceCodegenArches(ctx)
+ } else {
+ deviceArches = strings.Split(e, " ")
+ }
+
+ type props struct {
+ Target struct {
+ Android *codegenArchProperties
+ Host *codegenArchProperties
+ }
+ }
+
+ addCodegenArchProperties := func(p *props, hod **codegenArchProperties, arch string) {
+ switch arch {
+ case "arm":
+ *hod = &c.Arm
+ case "arm64":
+ *hod = &c.Arm64
+ case "mips":
+ *hod = &c.Mips
+ case "mips64":
+ *hod = &c.Mips64
+ case "x86":
+ *hod = &c.X86
+ case "x86_64":
+ *hod = &c.X86_64
+ default:
+ ctx.ModuleErrorf("Unknown codegen architecture %q", arch)
+ return
+ }
+ ctx.AppendProperties(p)
+ }
+
+ for _, a := range deviceArches {
+ p := &props{}
+ addCodegenArchProperties(p, &p.Target.Android, a)
+ if ctx.Failed() {
+ return
+ }
+ }
+
+ for _, a := range hostArches {
+ p := &props{}
+ addCodegenArchProperties(p, &p.Target.Host, a)
+ if ctx.Failed() {
+ return
+ }
+ }
+}
+
+type codegenArchProperties struct {
+ Srcs []string
+ Cflags []string
+ Static struct {
+ Whole_static_libs []string
+ }
+ Shared struct {
+ Shared_libs []string
+ }
+}
+
+type codegenProperties struct {
+ Codegen struct {
+ Arm, Arm64, Mips, Mips64, X86, X86_64 codegenArchProperties
+ }
+}
+
+type codegenCustomizer struct {
+ codegenProperties codegenProperties
+}
+
+func defaultDeviceCodegenArches(ctx android.CustomizePropertiesContext) []string {
+ arches := make(map[string]bool)
+ for _, a := range ctx.DeviceConfig().Arches() {
+ arches[a.ArchType.String()] = true
+ }
+ ret := make([]string, 0, len(arches))
+ for a := range arches {
+ ret = append(ret, a)
+ }
+ sort.Strings(ret)
+ return ret
+}
diff --git a/build/makevars.go b/build/makevars.go
new file mode 100644
index 0000000..5655c55
--- /dev/null
+++ b/build/makevars.go
@@ -0,0 +1,30 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package art
+
+import "android/soong/android"
+
+var (
+ pctx = android.NewPackageContext("android/soong/art")
+)
+
+func init() {
+ android.RegisterMakeVarsProvider(pctx, makeVarsProvider)
+}
+
+func makeVarsProvider(ctx android.MakeVarsContext) {
+ ctx.Strict("LIBART_IMG_HOST_BASE_ADDRESS", ctx.Config().LibartImgHostBaseAddress())
+ ctx.Strict("LIBART_IMG_TARGET_BASE_ADDRESS", ctx.Config().LibartImgDeviceBaseAddress())
+}
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index b57383b..b74e588 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -581,7 +581,7 @@
: background_collector_type_(gc::kCollectorTypeNone) {
if (kUseReadBarrier) {
- background_collector_type_ = gc::kCollectorTypeCC; // Disable background compaction for CC.
+ background_collector_type_ = gc::kCollectorTypeCCBackground; // Background compaction for CC.
}
}
diff --git a/compiler/Android.bp b/compiler/Android.bp
new file mode 100644
index 0000000..289adf8
--- /dev/null
+++ b/compiler/Android.bp
@@ -0,0 +1,280 @@
+//
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// TODO We should really separate out those files that are actually needed for both variants of an
+// architecture into its own category. Currently we just include all of the 32bit variant in the
+// 64bit variant. It also might be good to allow one to compile only the 64bit variant without the
+// 32bit one.
+
+art_cc_defaults {
+ name: "libart-compiler-defaults",
+ defaults: ["art_defaults"],
+ host_supported: true,
+ clang: true,
+ srcs: [
+ "compiled_method.cc",
+ "debug/elf_debug_writer.cc",
+ "dex/dex_to_dex_compiler.cc",
+ "dex/verified_method.cc",
+ "dex/verification_results.cc",
+ "dex/quick_compiler_callbacks.cc",
+ "dex/quick/dex_file_method_inliner.cc",
+ "dex/quick/dex_file_to_method_inliner_map.cc",
+ "driver/compiled_method_storage.cc",
+ "driver/compiler_driver.cc",
+ "driver/compiler_options.cc",
+ "driver/dex_compilation_unit.cc",
+ "linker/buffered_output_stream.cc",
+ "linker/file_output_stream.cc",
+ "linker/multi_oat_relative_patcher.cc",
+ "linker/output_stream.cc",
+ "linker/vector_output_stream.cc",
+ "linker/relative_patcher.cc",
+ "jit/jit_compiler.cc",
+ "jni/quick/calling_convention.cc",
+ "jni/quick/jni_compiler.cc",
+ "optimizing/block_builder.cc",
+ "optimizing/bounds_check_elimination.cc",
+ "optimizing/builder.cc",
+ "optimizing/code_generator.cc",
+ "optimizing/code_generator_utils.cc",
+ "optimizing/constant_folding.cc",
+ "optimizing/dead_code_elimination.cc",
+ "optimizing/graph_checker.cc",
+ "optimizing/graph_visualizer.cc",
+ "optimizing/gvn.cc",
+ "optimizing/induction_var_analysis.cc",
+ "optimizing/induction_var_range.cc",
+ "optimizing/inliner.cc",
+ "optimizing/instruction_builder.cc",
+ "optimizing/instruction_simplifier.cc",
+ "optimizing/intrinsics.cc",
+ "optimizing/licm.cc",
+ "optimizing/load_store_elimination.cc",
+ "optimizing/locations.cc",
+ "optimizing/nodes.cc",
+ "optimizing/optimization.cc",
+ "optimizing/optimizing_compiler.cc",
+ "optimizing/parallel_move_resolver.cc",
+ "optimizing/prepare_for_register_allocation.cc",
+ "optimizing/reference_type_propagation.cc",
+ "optimizing/register_allocation_resolver.cc",
+ "optimizing/register_allocator.cc",
+ "optimizing/register_allocator_graph_color.cc",
+ "optimizing/register_allocator_linear_scan.cc",
+ "optimizing/select_generator.cc",
+ "optimizing/sharpening.cc",
+ "optimizing/side_effects_analysis.cc",
+ "optimizing/ssa_builder.cc",
+ "optimizing/ssa_liveness_analysis.cc",
+ "optimizing/ssa_phi_elimination.cc",
+ "optimizing/stack_map_stream.cc",
+ "trampolines/trampoline_compiler.cc",
+ "utils/assembler.cc",
+ "utils/jni_macro_assembler.cc",
+ "utils/swap_space.cc",
+ "compiler.cc",
+ "elf_writer.cc",
+ "elf_writer_quick.cc",
+ "image_writer.cc",
+ "oat_writer.cc",
+ ],
+
+ codegen: {
+ arm: {
+ srcs: [
+ "jni/quick/arm/calling_convention_arm.cc",
+ "linker/arm/relative_patcher_arm_base.cc",
+ "linker/arm/relative_patcher_thumb2.cc",
+ "optimizing/code_generator_arm.cc",
+ "optimizing/dex_cache_array_fixups_arm.cc",
+ "optimizing/instruction_simplifier_arm.cc",
+ "optimizing/instruction_simplifier_shared.cc",
+ "optimizing/intrinsics_arm.cc",
+ "utils/arm/assembler_arm.cc",
+ "utils/arm/assembler_arm_vixl.cc",
+ "utils/arm/assembler_thumb2.cc",
+ "utils/arm/jni_macro_assembler_arm.cc",
+ "utils/arm/jni_macro_assembler_arm_vixl.cc",
+ "utils/arm/managed_register_arm.cc",
+ ],
+ },
+ arm64: {
+ srcs: [
+ "jni/quick/arm64/calling_convention_arm64.cc",
+ "linker/arm64/relative_patcher_arm64.cc",
+ "optimizing/code_generator_arm64.cc",
+ "optimizing/instruction_simplifier_arm64.cc",
+ "optimizing/intrinsics_arm64.cc",
+ "optimizing/nodes_arm64.cc",
+ "utils/arm64/assembler_arm64.cc",
+ "utils/arm64/jni_macro_assembler_arm64.cc",
+ "utils/arm64/managed_register_arm64.cc",
+ ],
+ },
+ mips: {
+ srcs: [
+ "jni/quick/mips/calling_convention_mips.cc",
+ "linker/mips/relative_patcher_mips.cc",
+ "optimizing/code_generator_mips.cc",
+ "optimizing/dex_cache_array_fixups_mips.cc",
+ "optimizing/intrinsics_mips.cc",
+ "optimizing/pc_relative_fixups_mips.cc",
+ "utils/mips/assembler_mips.cc",
+ "utils/mips/managed_register_mips.cc",
+ ],
+ },
+ mips64: {
+ srcs: [
+ "jni/quick/mips64/calling_convention_mips64.cc",
+ "optimizing/code_generator_mips64.cc",
+ "optimizing/intrinsics_mips64.cc",
+ "utils/mips64/assembler_mips64.cc",
+ "utils/mips64/managed_register_mips64.cc",
+ ],
+ },
+ x86: {
+ srcs: [
+ "jni/quick/x86/calling_convention_x86.cc",
+ "linker/x86/relative_patcher_x86.cc",
+ "linker/x86/relative_patcher_x86_base.cc",
+ "optimizing/code_generator_x86.cc",
+ "optimizing/intrinsics_x86.cc",
+ "optimizing/pc_relative_fixups_x86.cc",
+ "optimizing/x86_memory_gen.cc",
+ "utils/x86/assembler_x86.cc",
+ "utils/x86/jni_macro_assembler_x86.cc",
+ "utils/x86/managed_register_x86.cc",
+ ],
+ },
+ x86_64: {
+ srcs: [
+ "jni/quick/x86_64/calling_convention_x86_64.cc",
+ "linker/x86_64/relative_patcher_x86_64.cc",
+ "optimizing/intrinsics_x86_64.cc",
+ "optimizing/code_generator_x86_64.cc",
+ "utils/x86_64/assembler_x86_64.cc",
+ "utils/x86_64/jni_macro_assembler_x86_64.cc",
+ "utils/x86_64/managed_register_x86_64.cc",
+ ],
+ },
+ },
+ target: {
+ host: {
+ // For compiler driver TLS.
+ host_ldlibs: ["-lpthread"],
+ },
+ android: {
+ // For atrace.
+ shared_libs: ["libcutils"],
+ },
+ },
+ generated_sources: ["art_compiler_operator_srcs"],
+ shared_libs: [
+ "liblz4",
+ "liblzma",
+ ],
+ include_dirs: ["art/disassembler"],
+}
+
+gensrcs {
+ name: "art_compiler_operator_srcs",
+ cmd: "art/tools/generate-operator-out.py art/compiler $in > $out",
+ srcs: [
+ "compiled_method.h",
+ "dex/dex_to_dex_compiler.h",
+ "driver/compiler_driver.h",
+ "driver/compiler_options.h",
+ "image_writer.h",
+ "optimizing/locations.h",
+
+ "utils/arm/constants_arm.h",
+ "utils/mips/assembler_mips.h",
+ "utils/mips64/assembler_mips64.h",
+ ],
+ output_extension: "operator_out.cc",
+}
+
+art_cc_library {
+ name: "libart-compiler",
+ defaults: ["libart-compiler-defaults"],
+ codegen: {
+ arm: {
+ // VIXL assembly support for ARM targets.
+ static: {
+ whole_static_libs: [
+ "libvixl-arm",
+ ],
+ },
+ shared: {
+ shared_libs: [
+ "libvixl-arm",
+ ],
+ },
+ },
+ arm64: {
+ // VIXL assembly support for ARM64 targets.
+ static: {
+ whole_static_libs: [
+ "libvixl-arm64",
+ ],
+ },
+ shared: {
+ shared_libs: [
+ "libvixl-arm64",
+ ],
+ },
+ },
+ },
+ shared_libs: ["libart"],
+}
+
+art_cc_library {
+ name: "libartd-compiler",
+ defaults: [
+ "libart-compiler-defaults",
+ "art_debug_defaults",
+ ],
+ codegen: {
+ arm: {
+ // VIXL assembly support for ARM targets.
+ static: {
+ whole_static_libs: [
+ "libvixld-arm",
+ ],
+ },
+ shared: {
+ shared_libs: [
+ "libvixld-arm",
+ ],
+ },
+ },
+ arm64: {
+ // VIXL assembly support for ARM64 targets.
+ static: {
+ whole_static_libs: [
+ "libvixld-arm64",
+ ],
+ },
+ shared: {
+ shared_libs: [
+ "libvixld-arm64",
+ ],
+ },
+ },
+ },
+ shared_libs: ["libartd"],
+}
diff --git a/compiler/Android.mk b/compiler/Android.mk
deleted file mode 100644
index 16c6a7b..0000000
--- a/compiler/Android.mk
+++ /dev/null
@@ -1,343 +0,0 @@
-#
-# Copyright (C) 2012 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include art/build/Android.common_build.mk
-
-LIBART_COMPILER_SRC_FILES := \
- compiled_method.cc \
- debug/elf_debug_writer.cc \
- dex/dex_to_dex_compiler.cc \
- dex/verified_method.cc \
- dex/verification_results.cc \
- dex/quick_compiler_callbacks.cc \
- dex/quick/dex_file_method_inliner.cc \
- dex/quick/dex_file_to_method_inliner_map.cc \
- driver/compiled_method_storage.cc \
- driver/compiler_driver.cc \
- driver/compiler_options.cc \
- driver/dex_compilation_unit.cc \
- linker/buffered_output_stream.cc \
- linker/file_output_stream.cc \
- linker/multi_oat_relative_patcher.cc \
- linker/output_stream.cc \
- linker/vector_output_stream.cc \
- linker/relative_patcher.cc \
- jit/jit_compiler.cc \
- jni/quick/calling_convention.cc \
- jni/quick/jni_compiler.cc \
- optimizing/block_builder.cc \
- optimizing/bounds_check_elimination.cc \
- optimizing/builder.cc \
- optimizing/code_generator.cc \
- optimizing/code_generator_utils.cc \
- optimizing/constant_folding.cc \
- optimizing/dead_code_elimination.cc \
- optimizing/graph_checker.cc \
- optimizing/graph_visualizer.cc \
- optimizing/gvn.cc \
- optimizing/induction_var_analysis.cc \
- optimizing/induction_var_range.cc \
- optimizing/inliner.cc \
- optimizing/instruction_builder.cc \
- optimizing/instruction_simplifier.cc \
- optimizing/intrinsics.cc \
- optimizing/licm.cc \
- optimizing/load_store_elimination.cc \
- optimizing/locations.cc \
- optimizing/nodes.cc \
- optimizing/optimization.cc \
- optimizing/optimizing_compiler.cc \
- optimizing/parallel_move_resolver.cc \
- optimizing/prepare_for_register_allocation.cc \
- optimizing/reference_type_propagation.cc \
- optimizing/register_allocation_resolver.cc \
- optimizing/register_allocator.cc \
- optimizing/register_allocator_graph_color.cc \
- optimizing/register_allocator_linear_scan.cc \
- optimizing/select_generator.cc \
- optimizing/sharpening.cc \
- optimizing/side_effects_analysis.cc \
- optimizing/ssa_builder.cc \
- optimizing/ssa_liveness_analysis.cc \
- optimizing/ssa_phi_elimination.cc \
- optimizing/stack_map_stream.cc \
- trampolines/trampoline_compiler.cc \
- utils/assembler.cc \
- utils/jni_macro_assembler.cc \
- utils/swap_space.cc \
- compiler.cc \
- elf_writer.cc \
- elf_writer_quick.cc \
- image_writer.cc \
- oat_writer.cc
-
-LIBART_COMPILER_SRC_FILES_arm := \
- jni/quick/arm/calling_convention_arm.cc \
- linker/arm/relative_patcher_arm_base.cc \
- linker/arm/relative_patcher_thumb2.cc \
- optimizing/code_generator_arm.cc \
- optimizing/dex_cache_array_fixups_arm.cc \
- optimizing/instruction_simplifier_arm.cc \
- optimizing/instruction_simplifier_shared.cc \
- optimizing/intrinsics_arm.cc \
- utils/arm/assembler_arm.cc \
- utils/arm/assembler_arm32.cc \
- utils/arm/assembler_thumb2.cc \
- utils/arm/jni_macro_assembler_arm.cc \
- utils/arm/managed_register_arm.cc \
-
-# TODO We should really separate out those files that are actually needed for both variants of an
-# architecture into its own category. Currently we just include all of the 32bit variant in the
-# 64bit variant. It also might be good to allow one to compile only the 64bit variant without the
-# 32bit one.
-LIBART_COMPILER_SRC_FILES_arm64 := \
- $(LIBART_COMPILER_SRC_FILES_arm) \
- jni/quick/arm64/calling_convention_arm64.cc \
- linker/arm64/relative_patcher_arm64.cc \
- optimizing/nodes_arm64.cc \
- optimizing/code_generator_arm64.cc \
- optimizing/instruction_simplifier_arm64.cc \
- optimizing/instruction_simplifier_shared.cc \
- optimizing/intrinsics_arm64.cc \
- utils/arm64/assembler_arm64.cc \
- utils/arm64/jni_macro_assembler_arm64.cc \
- utils/arm64/managed_register_arm64.cc \
-
-LIBART_COMPILER_SRC_FILES_mips := \
- jni/quick/mips/calling_convention_mips.cc \
- linker/mips/relative_patcher_mips.cc \
- optimizing/code_generator_mips.cc \
- optimizing/dex_cache_array_fixups_mips.cc \
- optimizing/intrinsics_mips.cc \
- optimizing/pc_relative_fixups_mips.cc \
- utils/mips/assembler_mips.cc \
- utils/mips/managed_register_mips.cc \
-
-LIBART_COMPILER_SRC_FILES_mips64 := \
- $(LIBART_COMPILER_SRC_FILES_mips) \
- jni/quick/mips64/calling_convention_mips64.cc \
- optimizing/code_generator_mips64.cc \
- optimizing/intrinsics_mips64.cc \
- utils/mips64/assembler_mips64.cc \
- utils/mips64/managed_register_mips64.cc \
-
-
-LIBART_COMPILER_SRC_FILES_x86 := \
- jni/quick/x86/calling_convention_x86.cc \
- linker/x86/relative_patcher_x86.cc \
- linker/x86/relative_patcher_x86_base.cc \
- optimizing/code_generator_x86.cc \
- optimizing/intrinsics_x86.cc \
- optimizing/pc_relative_fixups_x86.cc \
- optimizing/x86_memory_gen.cc \
- utils/x86/assembler_x86.cc \
- utils/x86/jni_macro_assembler_x86.cc \
- utils/x86/managed_register_x86.cc \
-
-LIBART_COMPILER_SRC_FILES_x86_64 := \
- $(LIBART_COMPILER_SRC_FILES_x86) \
- jni/quick/x86_64/calling_convention_x86_64.cc \
- linker/x86_64/relative_patcher_x86_64.cc \
- optimizing/intrinsics_x86_64.cc \
- optimizing/code_generator_x86_64.cc \
- utils/x86_64/assembler_x86_64.cc \
- utils/x86_64/jni_macro_assembler_x86_64.cc \
- utils/x86_64/managed_register_x86_64.cc \
-
-
-LIBART_COMPILER_CFLAGS :=
-
-LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES := \
- compiled_method.h \
- dex/dex_to_dex_compiler.h \
- driver/compiler_driver.h \
- driver/compiler_options.h \
- image_writer.h \
- optimizing/locations.h
-
-LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES_arm := \
- utils/arm/constants_arm.h
-
-LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES_arm64 := \
- $(LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES_arm)
-
-LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES_mips := \
- utils/mips/assembler_mips.h
-
-LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES_mips64 := \
- $(LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES_mips) \
- utils/mips64/assembler_mips64.h
-
-LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES_x86 :=
-LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES_x86_64 := \
- $(LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES_x86)
-
-# $(1): target or host
-# $(2): ndebug or debug
-# $(3): static or shared (empty means shared, applies only for host)
-define build-libart-compiler
- ifneq ($(1),target)
- ifneq ($(1),host)
- $$(error expected target or host for argument 1, received $(1))
- endif
- endif
- ifneq ($(2),ndebug)
- ifneq ($(2),debug)
- $$(error expected ndebug or debug for argument 2, received $(2))
- endif
- endif
-
- art_target_or_host := $(1)
- art_ndebug_or_debug := $(2)
- art_static_or_shared := $(3)
-
- include $(CLEAR_VARS)
- ifeq ($$(art_target_or_host),host)
- LOCAL_IS_HOST_MODULE := true
- art_codegen_targets := $(ART_HOST_CODEGEN_ARCHS)
- else
- art_codegen_targets := $(ART_TARGET_CODEGEN_ARCHS)
- endif
- LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
- ifeq ($$(art_ndebug_or_debug),ndebug)
- LOCAL_MODULE := libart-compiler
- ifeq ($$(art_static_or_shared), static)
- LOCAL_STATIC_LIBRARIES += libart liblz4 liblzma
- else
- LOCAL_SHARED_LIBRARIES += libart liblz4 liblzma
- endif
- ifeq ($$(art_target_or_host),target)
- LOCAL_FDO_SUPPORT := true
- endif
- else # debug
- LOCAL_MODULE := libartd-compiler
- ifeq ($$(art_static_or_shared), static)
- LOCAL_STATIC_LIBRARIES += libartd liblz4 liblzma
- else
- LOCAL_SHARED_LIBRARIES += libartd liblz4 liblzma
- endif
- endif
-
- LOCAL_MODULE_TAGS := optional
- ifeq ($$(art_static_or_shared), static)
- LOCAL_MODULE_CLASS := STATIC_LIBRARIES
- else
- LOCAL_MODULE_CLASS := SHARED_LIBRARIES
- endif
-
- # Sort removes duplicates.
- LOCAL_SRC_FILES := $$(LIBART_COMPILER_SRC_FILES) \
- $$(sort $$(foreach arch,$$(art_codegen_targets), $$(LIBART_COMPILER_SRC_FILES_$$(arch))))
-
- GENERATED_SRC_DIR := $$(call local-generated-sources-dir)
- ENUM_OPERATOR_OUT_CC_FILES := $$(patsubst %.h,%_operator_out.cc,\
- $$(LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES) \
- $$(sort $$(foreach arch,$$(art_codegen_targets), $$(LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES_$$(arch)))))
- ENUM_OPERATOR_OUT_GEN := $$(addprefix $$(GENERATED_SRC_DIR)/,$$(ENUM_OPERATOR_OUT_CC_FILES))
-
-$$(ENUM_OPERATOR_OUT_GEN): art/tools/generate-operator-out.py
-$$(ENUM_OPERATOR_OUT_GEN): PRIVATE_CUSTOM_TOOL = art/tools/generate-operator-out.py $(LOCAL_PATH) $$< > $$@
-$$(ENUM_OPERATOR_OUT_GEN): $$(GENERATED_SRC_DIR)/%_operator_out.cc : $(LOCAL_PATH)/%.h
- $$(transform-generated-source)
-
- LOCAL_GENERATED_SOURCES += $$(ENUM_OPERATOR_OUT_GEN)
-
- LOCAL_CFLAGS := $$(LIBART_COMPILER_CFLAGS)
- ifeq ($$(art_target_or_host),target)
- LOCAL_CLANG := $(ART_TARGET_CLANG)
- $(call set-target-local-cflags-vars,$(2))
- else # host
- LOCAL_CLANG := $(ART_HOST_CLANG)
- LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
- LOCAL_ASFLAGS += $(ART_HOST_ASFLAGS)
- ifeq ($$(art_static_or_shared),static)
- LOCAL_LDFLAGS += -static
- endif
- ifeq ($$(art_ndebug_or_debug),debug)
- LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS)
- LOCAL_ASFLAGS += $(ART_HOST_DEBUG_ASFLAGS)
- else
- LOCAL_CFLAGS += $(ART_HOST_NON_DEBUG_CFLAGS)
- LOCAL_ASFLAGS += $(ART_HOST_NON_DEBUG_ASFLAGS)
- endif
- endif
-
- LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime art/disassembler
-
- ifeq ($$(art_target_or_host),host)
- # For compiler driver TLS.
- LOCAL_LDLIBS += -lpthread
- endif
- LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
- LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
- # VIXL assembly support for ARM64 targets.
- ifeq ($$(art_ndebug_or_debug),debug)
- ifeq ($$(art_static_or_shared), static)
- LOCAL_WHOLESTATIC_LIBRARIES += libvixld-arm64
- else
- LOCAL_SHARED_LIBRARIES += libvixld-arm64
- endif
- else
- ifeq ($$(art_static_or_shared), static)
- LOCAL_WHOLE_STATIC_LIBRARIES += libvixl-arm64
- else
- LOCAL_SHARED_LIBRARIES += libvixl-arm64
- endif
- endif
-
- LOCAL_NATIVE_COVERAGE := $(ART_COVERAGE)
-
- ifeq ($$(art_target_or_host),target)
- # For atrace.
- LOCAL_SHARED_LIBRARIES += libcutils
- include $(BUILD_SHARED_LIBRARY)
- else # host
- LOCAL_MULTILIB := both
- ifeq ($$(art_static_or_shared), static)
- include $(BUILD_HOST_STATIC_LIBRARY)
- else
- include $(BUILD_HOST_SHARED_LIBRARY)
- endif
- endif
-
- # Clear locally defined variables.
- art_target_or_host :=
- art_ndebug_or_debug :=
- art_static_or_shared :=
- art_codegen_targets :=
-endef
-
-# We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
-ifeq ($(ART_BUILD_HOST_NDEBUG),true)
- $(eval $(call build-libart-compiler,host,ndebug))
- ifeq ($(ART_BUILD_HOST_STATIC),true)
- $(eval $(call build-libart-compiler,host,ndebug,static))
- endif
-endif
-ifeq ($(ART_BUILD_HOST_DEBUG),true)
- $(eval $(call build-libart-compiler,host,debug))
- ifeq ($(ART_BUILD_HOST_STATIC),true)
- $(eval $(call build-libart-compiler,host,debug,static))
- endif
-endif
-ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
- $(eval $(call build-libart-compiler,target,ndebug))
-endif
-ifeq ($(ART_BUILD_TARGET_DEBUG),true)
- $(eval $(call build-libart-compiler,target,debug))
-endif
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 758cd93..77ec4b7 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -372,7 +372,7 @@
method_inliner_map_(method_inliner_map),
compiler_(Compiler::Create(this, compiler_kind)),
compiler_kind_(compiler_kind),
- instruction_set_(instruction_set),
+ instruction_set_(instruction_set == kArm ? kThumb2: instruction_set),
instruction_set_features_(instruction_set_features),
requires_constructor_barrier_lock_("constructor barrier lock"),
compiled_classes_lock_("compiled classes lock"),
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 9d5aabc..ba2df07 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -4643,12 +4643,10 @@
bool needs_write_barrier =
CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
- bool object_array_set_with_read_barrier =
- kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
instruction,
- (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
+ may_need_runtime_call_for_type_check ?
LocationSummary::kCallOnSlowPath :
LocationSummary::kNoCall);
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 578c7e7..d50b786 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -46,16 +46,20 @@
namespace arm64 {
+using helpers::ARM64EncodableConstantOrRegister;
+using helpers::ArtVixlRegCodeCoherentForRegSet;
using helpers::CPURegisterFrom;
using helpers::DRegisterFrom;
using helpers::FPRegisterFrom;
using helpers::HeapOperand;
using helpers::HeapOperandFrom;
using helpers::InputCPURegisterAt;
+using helpers::InputCPURegisterOrZeroRegAt;
using helpers::InputFPRegisterAt;
-using helpers::InputRegisterAt;
using helpers::InputOperandAt;
+using helpers::InputRegisterAt;
using helpers::Int64ConstantFrom;
+using helpers::IsConstantZeroBitPattern;
using helpers::LocationFrom;
using helpers::OperandFromMemOperand;
using helpers::OutputCPURegister;
@@ -66,8 +70,6 @@
using helpers::VIXLRegCodeFromART;
using helpers::WRegisterFrom;
using helpers::XRegisterFrom;
-using helpers::ARM64EncodableConstantOrRegister;
-using helpers::ArtVixlRegCodeCoherentForRegSet;
static constexpr int kCurrentMethodStackOffset = 0;
// The compare/jump sequence will generate about (1.5 * num_entries + 3) instructions. While jump
@@ -236,10 +238,10 @@
codegen->EmitParallelMoves(
locations->InAt(0), LocationFrom(calling_convention.GetRegisterAt(0)), Primitive::kPrimInt,
locations->InAt(1), LocationFrom(calling_convention.GetRegisterAt(1)), Primitive::kPrimInt);
- uint32_t entry_point_offset = instruction_->AsBoundsCheck()->IsStringCharAt()
- ? QUICK_ENTRY_POINT(pThrowStringBounds)
- : QUICK_ENTRY_POINT(pThrowArrayBounds);
- arm64_codegen->InvokeRuntime(entry_point_offset, instruction_, instruction_->GetDexPc(), this);
+ QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
+ ? kQuickThrowStringBounds
+ : kQuickThrowArrayBounds;
+ arm64_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
}
@@ -263,8 +265,7 @@
// Live registers will be restored in the catch block if caught.
SaveLiveRegisters(codegen, instruction_->GetLocations());
}
- arm64_codegen->InvokeRuntime(
- QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this);
+ arm64_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
}
@@ -295,9 +296,9 @@
InvokeRuntimeCallingConvention calling_convention;
__ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex());
- int32_t entry_point_offset = do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
- : QUICK_ENTRY_POINT(pInitializeType);
- arm64_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this);
+ QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
+ : kQuickInitializeType;
+ arm64_codegen->InvokeRuntime(entrypoint, at_, dex_pc_, this);
if (do_clinit_) {
CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
} else {
@@ -350,8 +351,7 @@
InvokeRuntimeCallingConvention calling_convention;
const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex();
__ Mov(calling_convention.GetRegisterAt(0).W(), string_index);
- arm64_codegen->InvokeRuntime(
- QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this);
+ arm64_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Primitive::Type type = instruction_->GetType();
arm64_codegen->MoveLocation(locations->Out(), calling_convention.GetReturnLocation(type), type);
@@ -377,8 +377,10 @@
// Live registers will be restored in the catch block if caught.
SaveLiveRegisters(codegen, instruction_->GetLocations());
}
- arm64_codegen->InvokeRuntime(
- QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this);
+ arm64_codegen->InvokeRuntime(kQuickThrowNullPointer,
+ instruction_,
+ instruction_->GetDexPc(),
+ this);
CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
}
@@ -398,8 +400,7 @@
void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
__ Bind(GetEntryLabel());
- arm64_codegen->InvokeRuntime(
- QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this);
+ arm64_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
CheckEntrypointTypes<kQuickTestSuspend, void, void>();
if (successor_ == nullptr) {
__ B(GetReturnLabel());
@@ -458,8 +459,7 @@
object_class, LocationFrom(calling_convention.GetRegisterAt(1)), Primitive::kPrimNot);
if (instruction_->IsInstanceOf()) {
- arm64_codegen->InvokeRuntime(
- QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, dex_pc, this);
+ arm64_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this);
CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t,
const mirror::Class*, const mirror::Class*>();
Primitive::Type ret_type = instruction_->GetType();
@@ -467,7 +467,7 @@
arm64_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
} else {
DCHECK(instruction_->IsCheckCast());
- arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), instruction_, dex_pc, this);
+ arm64_codegen->InvokeRuntime(kQuickCheckCast, instruction_, dex_pc, this);
CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>();
}
@@ -495,10 +495,7 @@
CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
__ Bind(GetEntryLabel());
SaveLiveRegisters(codegen, instruction_->GetLocations());
- arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize),
- instruction_,
- instruction_->GetDexPc(),
- this);
+ arm64_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
CheckEntrypointTypes<kQuickDeoptimize, void, void>();
}
@@ -537,10 +534,7 @@
codegen->GetMoveResolver()->EmitNativeCode(¶llel_move);
CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
- arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
- instruction_,
- instruction_->GetDexPc(),
- this);
+ arm64_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
RestoreLiveRegisters(codegen, locations);
__ B(GetExitLabel());
@@ -780,7 +774,7 @@
codegen->GetMoveResolver()->EmitNativeCode(¶llel_move);
arm64_codegen->MoveConstant(LocationFrom(calling_convention.GetRegisterAt(2)), offset_);
}
- arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierSlow),
+ arm64_codegen->InvokeRuntime(kQuickReadBarrierSlow,
instruction_,
instruction_->GetDexPc(),
this);
@@ -859,7 +853,7 @@
// which would emit a 32-bit move, as `type` is a (32-bit wide)
// reference type (`Primitive::kPrimNot`).
__ Mov(calling_convention.GetRegisterAt(0), XRegisterFrom(out_));
- arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierForRootSlow),
+ arm64_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
instruction_,
instruction_->GetDexPc(),
this);
@@ -1466,12 +1460,18 @@
break;
case Primitive::kPrimFloat:
case Primitive::kPrimDouble: {
- DCHECK(src.IsFPRegister());
DCHECK_EQ(src.Is64Bits(), Primitive::Is64BitType(type));
+ Register temp_src;
+ if (src.IsZero()) {
+ // The zero register is used to avoid synthesizing zero constants.
+ temp_src = Register(src);
+ } else {
+ DCHECK(src.IsFPRegister());
+ temp_src = src.Is64Bits() ? temps.AcquireX() : temps.AcquireW();
+ __ Fmov(temp_src, FPRegister(src));
+ }
- Register temp = src.Is64Bits() ? temps.AcquireX() : temps.AcquireW();
- __ Fmov(temp, FPRegister(src));
- __ Stlr(temp, base);
+ __ Stlr(temp_src, base);
break;
}
case Primitive::kPrimVoid:
@@ -1483,20 +1483,8 @@
HInstruction* instruction,
uint32_t dex_pc,
SlowPathCode* slow_path) {
- InvokeRuntime(GetThreadOffset<kArm64PointerSize>(entrypoint).Int32Value(),
- instruction,
- dex_pc,
- slow_path);
-}
-
-void CodeGeneratorARM64::InvokeRuntime(int32_t entry_point_offset,
- HInstruction* instruction,
- uint32_t dex_pc,
- SlowPathCode* slow_path) {
ValidateInvokeRuntime(instruction, slow_path);
- BlockPoolsScope block_pools(GetVIXLAssembler());
- __ Ldr(lr, MemOperand(tr, entry_point_offset));
- __ Blr(lr);
+ GenerateInvokeRuntime(GetThreadOffset<kArm64PointerSize>(entrypoint).Int32Value());
RecordPcInfo(instruction, dex_pc, slow_path);
}
@@ -1504,6 +1492,10 @@
HInstruction* instruction,
SlowPathCode* slow_path) {
ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
+ GenerateInvokeRuntime(entry_point_offset);
+}
+
+void CodeGeneratorARM64::GenerateInvokeRuntime(int32_t entry_point_offset) {
BlockPoolsScope block_pools(GetVIXLAssembler());
__ Ldr(lr, MemOperand(tr, entry_point_offset));
__ Blr(lr);
@@ -1710,7 +1702,9 @@
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
- if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
+ if (IsConstantZeroBitPattern(instruction->InputAt(1))) {
+ locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
+ } else if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
locations->SetInAt(1, Location::RequiresFpuRegister());
} else {
locations->SetInAt(1, Location::RequiresRegister());
@@ -1724,7 +1718,7 @@
BlockPoolsScope block_pools(GetVIXLAssembler());
Register obj = InputRegisterAt(instruction, 0);
- CPURegister value = InputCPURegisterAt(instruction, 1);
+ CPURegister value = InputCPURegisterOrZeroRegAt(instruction, 1);
CPURegister source = value;
Offset offset = field_info.GetFieldOffset();
Primitive::Type field_type = field_info.GetFieldType();
@@ -2163,16 +2157,16 @@
Primitive::Type value_type = instruction->GetComponentType();
bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
- bool object_array_set_with_read_barrier =
- kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
instruction,
- (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
+ may_need_runtime_call_for_type_check ?
LocationSummary::kCallOnSlowPath :
LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
- if (Primitive::IsFloatingPointType(value_type)) {
+ if (IsConstantZeroBitPattern(instruction->InputAt(2))) {
+ locations->SetInAt(2, Location::ConstantLocation(instruction->InputAt(2)->AsConstant()));
+ } else if (Primitive::IsFloatingPointType(value_type)) {
locations->SetInAt(2, Location::RequiresFpuRegister());
} else {
locations->SetInAt(2, Location::RequiresRegister());
@@ -2192,7 +2186,7 @@
CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Register array = InputRegisterAt(instruction, 0);
- CPURegister value = InputCPURegisterAt(instruction, 2);
+ CPURegister value = InputCPURegisterOrZeroRegAt(instruction, 2);
CPURegister source = value;
Location index = locations->InAt(1);
size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
@@ -4092,10 +4086,7 @@
void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
if (cls->NeedsAccessCheck()) {
codegen_->MoveConstant(cls->GetLocations()->GetTemp(0), cls->GetTypeIndex());
- codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
- cls,
- cls->GetDexPc(),
- nullptr);
+ codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
return;
}
@@ -4344,11 +4335,9 @@
}
void InstructionCodeGeneratorARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
- codegen_->InvokeRuntime(instruction->IsEnter()
- ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject),
- instruction,
- instruction->GetDexPc(),
- nullptr);
+ codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject: kQuickUnlockObject,
+ instruction,
+ instruction->GetDexPc());
if (instruction->IsEnter()) {
CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
} else {
@@ -4452,10 +4441,7 @@
__ Mov(type_index, instruction->GetTypeIndex());
// Note: if heap poisoning is enabled, the entry point takes cares
// of poisoning the reference.
- codegen_->InvokeRuntime(instruction->GetEntrypoint(),
- instruction,
- instruction->GetDexPc(),
- nullptr);
+ codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
}
@@ -4484,10 +4470,7 @@
__ Blr(lr);
codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
} else {
- codegen_->InvokeRuntime(instruction->GetEntrypoint(),
- instruction,
- instruction->GetDexPc(),
- nullptr);
+ codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
}
}
@@ -4653,9 +4636,8 @@
case Primitive::kPrimFloat:
case Primitive::kPrimDouble: {
- int32_t entry_offset = (type == Primitive::kPrimFloat) ? QUICK_ENTRY_POINT(pFmodf)
- : QUICK_ENTRY_POINT(pFmod);
- codegen_->InvokeRuntime(entry_offset, rem, rem->GetDexPc(), nullptr);
+ QuickEntrypointEnum entrypoint = (type == Primitive::kPrimFloat) ? kQuickFmodf : kQuickFmod;
+ codegen_->InvokeRuntime(entrypoint, rem, rem->GetDexPc());
if (type == Primitive::kPrimFloat) {
CheckEntrypointTypes<kQuickFmodf, float, float, float>();
} else {
@@ -4838,8 +4820,7 @@
}
void InstructionCodeGeneratorARM64::VisitThrow(HThrow* instruction) {
- codegen_->InvokeRuntime(
- QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr);
+ codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
}
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 921ce10..78db803 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -491,12 +491,7 @@
void InvokeRuntime(QuickEntrypointEnum entrypoint,
HInstruction* instruction,
uint32_t dex_pc,
- SlowPathCode* slow_path) OVERRIDE;
-
- void InvokeRuntime(int32_t offset,
- HInstruction* instruction,
- uint32_t dex_pc,
- SlowPathCode* slow_path);
+ SlowPathCode* slow_path = nullptr) OVERRIDE;
// Generate code to invoke a runtime entry point, but do not record
// PC-related information in a stack map.
@@ -504,6 +499,8 @@
HInstruction* instruction,
SlowPathCode* slow_path);
+ void GenerateInvokeRuntime(int32_t entry_point_offset);
+
ParallelMoveResolverARM64* GetMoveResolver() OVERRIDE { return &move_resolver_; }
bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index a7fbc84..8a2f90d 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -1833,11 +1833,19 @@
}
}
+auto InstructionCodeGeneratorMIPS::GetImplicitNullChecker(HInstruction* instruction) {
+ auto null_checker = [this, instruction]() {
+ this->codegen_->MaybeRecordImplicitNullCheck(instruction);
+ };
+ return null_checker;
+}
+
void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) {
LocationSummary* locations = instruction->GetLocations();
Register obj = locations->InAt(0).AsRegister<Register>();
Location index = locations->InAt(1);
uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
+ auto null_checker = GetImplicitNullChecker(instruction);
Primitive::Type type = instruction->GetType();
switch (type) {
@@ -1846,10 +1854,10 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
- __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
+ __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset, null_checker);
} else {
__ Addu(TMP, obj, index.AsRegister<Register>());
- __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset);
+ __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset, null_checker);
}
break;
}
@@ -1859,10 +1867,10 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
- __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
+ __ LoadFromOffset(kLoadSignedByte, out, obj, offset, null_checker);
} else {
__ Addu(TMP, obj, index.AsRegister<Register>());
- __ LoadFromOffset(kLoadSignedByte, out, TMP, data_offset);
+ __ LoadFromOffset(kLoadSignedByte, out, TMP, data_offset, null_checker);
}
break;
}
@@ -1872,11 +1880,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
- __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
+ __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_2);
__ Addu(TMP, obj, TMP);
- __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset);
+ __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
}
break;
}
@@ -1886,11 +1894,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
- __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
+ __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_2);
__ Addu(TMP, obj, TMP);
- __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset);
+ __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker);
}
break;
}
@@ -1902,11 +1910,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
- __ LoadFromOffset(kLoadWord, out, obj, offset);
+ __ LoadFromOffset(kLoadWord, out, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
__ Addu(TMP, obj, TMP);
- __ LoadFromOffset(kLoadWord, out, TMP, data_offset);
+ __ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
}
break;
}
@@ -1916,11 +1924,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
- __ LoadFromOffset(kLoadDoubleword, out, obj, offset);
+ __ LoadFromOffset(kLoadDoubleword, out, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
__ Addu(TMP, obj, TMP);
- __ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset);
+ __ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
}
break;
}
@@ -1930,11 +1938,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
- __ LoadSFromOffset(out, obj, offset);
+ __ LoadSFromOffset(out, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
__ Addu(TMP, obj, TMP);
- __ LoadSFromOffset(out, TMP, data_offset);
+ __ LoadSFromOffset(out, TMP, data_offset, null_checker);
}
break;
}
@@ -1944,11 +1952,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
- __ LoadDFromOffset(out, obj, offset);
+ __ LoadDFromOffset(out, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
__ Addu(TMP, obj, TMP);
- __ LoadDFromOffset(out, TMP, data_offset);
+ __ LoadDFromOffset(out, TMP, data_offset, null_checker);
}
break;
}
@@ -1957,7 +1965,6 @@
LOG(FATAL) << "Unreachable type " << instruction->GetType();
UNREACHABLE();
}
- codegen_->MaybeRecordImplicitNullCheck(instruction);
}
void LocationsBuilderMIPS::VisitArrayLength(HArrayLength* instruction) {
@@ -2004,6 +2011,7 @@
bool needs_runtime_call = locations->WillCall();
bool needs_write_barrier =
CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
+ auto null_checker = GetImplicitNullChecker(instruction);
switch (value_type) {
case Primitive::kPrimBoolean:
@@ -2013,10 +2021,10 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
- __ StoreToOffset(kStoreByte, value, obj, offset);
+ __ StoreToOffset(kStoreByte, value, obj, offset, null_checker);
} else {
__ Addu(TMP, obj, index.AsRegister<Register>());
- __ StoreToOffset(kStoreByte, value, TMP, data_offset);
+ __ StoreToOffset(kStoreByte, value, TMP, data_offset, null_checker);
}
break;
}
@@ -2028,11 +2036,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
- __ StoreToOffset(kStoreHalfword, value, obj, offset);
+ __ StoreToOffset(kStoreHalfword, value, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_2);
__ Addu(TMP, obj, TMP);
- __ StoreToOffset(kStoreHalfword, value, TMP, data_offset);
+ __ StoreToOffset(kStoreHalfword, value, TMP, data_offset, null_checker);
}
break;
}
@@ -2045,14 +2053,13 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
- __ StoreToOffset(kStoreWord, value, obj, offset);
+ __ StoreToOffset(kStoreWord, value, obj, offset, null_checker);
} else {
DCHECK(index.IsRegister()) << index;
__ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
__ Addu(TMP, obj, TMP);
- __ StoreToOffset(kStoreWord, value, TMP, data_offset);
+ __ StoreToOffset(kStoreWord, value, TMP, data_offset, null_checker);
}
- codegen_->MaybeRecordImplicitNullCheck(instruction);
if (needs_write_barrier) {
DCHECK_EQ(value_type, Primitive::kPrimNot);
codegen_->MarkGCCard(obj, value);
@@ -2075,11 +2082,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
- __ StoreToOffset(kStoreDoubleword, value, obj, offset);
+ __ StoreToOffset(kStoreDoubleword, value, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
__ Addu(TMP, obj, TMP);
- __ StoreToOffset(kStoreDoubleword, value, TMP, data_offset);
+ __ StoreToOffset(kStoreDoubleword, value, TMP, data_offset, null_checker);
}
break;
}
@@ -2091,11 +2098,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
- __ StoreSToOffset(value, obj, offset);
+ __ StoreSToOffset(value, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
__ Addu(TMP, obj, TMP);
- __ StoreSToOffset(value, TMP, data_offset);
+ __ StoreSToOffset(value, TMP, data_offset, null_checker);
}
break;
}
@@ -2107,11 +2114,11 @@
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
- __ StoreDToOffset(value, obj, offset);
+ __ StoreDToOffset(value, obj, offset, null_checker);
} else {
__ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
__ Addu(TMP, obj, TMP);
- __ StoreDToOffset(value, TMP, data_offset);
+ __ StoreDToOffset(value, TMP, data_offset, null_checker);
}
break;
}
@@ -2120,11 +2127,6 @@
LOG(FATAL) << "Unreachable type " << instruction->GetType();
UNREACHABLE();
}
-
- // Ints and objects are handled in the switch.
- if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
- codegen_->MaybeRecordImplicitNullCheck(instruction);
- }
}
void LocationsBuilderMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -3589,6 +3591,7 @@
LoadOperandType load_type = kLoadUnsignedByte;
bool is_volatile = field_info.IsVolatile();
uint32_t offset = field_info.GetFieldOffset().Uint32Value();
+ auto null_checker = GetImplicitNullChecker(instruction);
switch (type) {
case Primitive::kPrimBoolean:
@@ -3654,34 +3657,20 @@
if (type == Primitive::kPrimLong) {
DCHECK(locations->Out().IsRegisterPair());
dst = locations->Out().AsRegisterPairLow<Register>();
- Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
- if (obj == dst) {
- __ LoadFromOffset(kLoadWord, dst_high, obj, offset + kMipsWordSize);
- codegen_->MaybeRecordImplicitNullCheck(instruction);
- __ LoadFromOffset(kLoadWord, dst, obj, offset);
- } else {
- __ LoadFromOffset(kLoadWord, dst, obj, offset);
- codegen_->MaybeRecordImplicitNullCheck(instruction);
- __ LoadFromOffset(kLoadWord, dst_high, obj, offset + kMipsWordSize);
- }
} else {
DCHECK(locations->Out().IsRegister());
dst = locations->Out().AsRegister<Register>();
- __ LoadFromOffset(load_type, dst, obj, offset);
}
+ __ LoadFromOffset(load_type, dst, obj, offset, null_checker);
} else {
DCHECK(locations->Out().IsFpuRegister());
FRegister dst = locations->Out().AsFpuRegister<FRegister>();
if (type == Primitive::kPrimFloat) {
- __ LoadSFromOffset(dst, obj, offset);
+ __ LoadSFromOffset(dst, obj, offset, null_checker);
} else {
- __ LoadDFromOffset(dst, obj, offset);
+ __ LoadDFromOffset(dst, obj, offset, null_checker);
}
}
- // Longs are handled earlier.
- if (type != Primitive::kPrimLong) {
- codegen_->MaybeRecordImplicitNullCheck(instruction);
- }
}
if (is_volatile) {
@@ -3729,6 +3718,7 @@
StoreOperandType store_type = kStoreByte;
bool is_volatile = field_info.IsVolatile();
uint32_t offset = field_info.GetFieldOffset().Uint32Value();
+ auto null_checker = GetImplicitNullChecker(instruction);
switch (type) {
case Primitive::kPrimBoolean:
@@ -3800,28 +3790,20 @@
if (type == Primitive::kPrimLong) {
DCHECK(locations->InAt(1).IsRegisterPair());
src = locations->InAt(1).AsRegisterPairLow<Register>();
- Register src_high = locations->InAt(1).AsRegisterPairHigh<Register>();
- __ StoreToOffset(kStoreWord, src, obj, offset);
- codegen_->MaybeRecordImplicitNullCheck(instruction);
- __ StoreToOffset(kStoreWord, src_high, obj, offset + kMipsWordSize);
} else {
DCHECK(locations->InAt(1).IsRegister());
src = locations->InAt(1).AsRegister<Register>();
- __ StoreToOffset(store_type, src, obj, offset);
}
+ __ StoreToOffset(store_type, src, obj, offset, null_checker);
} else {
DCHECK(locations->InAt(1).IsFpuRegister());
FRegister src = locations->InAt(1).AsFpuRegister<FRegister>();
if (type == Primitive::kPrimFloat) {
- __ StoreSToOffset(src, obj, offset);
+ __ StoreSToOffset(src, obj, offset, null_checker);
} else {
- __ StoreDToOffset(src, obj, offset);
+ __ StoreDToOffset(src, obj, offset, null_checker);
}
}
- // Longs are handled earlier.
- if (type != Primitive::kPrimLong) {
- codegen_->MaybeRecordImplicitNullCheck(instruction);
- }
}
// TODO: memory barriers?
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index 63a0345..46810d6 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -257,6 +257,7 @@
void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
void GenerateDivRemIntegral(HBinaryOperation* instruction);
void HandleGoto(HInstruction* got, HBasicBlock* successor);
+ auto GetImplicitNullChecker(HInstruction* instruction);
MipsAssembler* const assembler_;
CodeGeneratorMIPS* const codegen_;
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index e8740a5..675c5e0 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -5254,12 +5254,10 @@
bool needs_write_barrier =
CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
- bool object_array_set_with_read_barrier =
- kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
instruction,
- (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
+ may_need_runtime_call_for_type_check ?
LocationSummary::kCallOnSlowPath :
LocationSummary::kNoCall);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index bc5ffcc..87b6de3 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -4742,12 +4742,10 @@
bool needs_write_barrier =
CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
- bool object_array_set_with_read_barrier =
- kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot);
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
instruction,
- (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ?
+ may_need_runtime_call_for_type_check ?
LocationSummary::kCallOnSlowPath :
LocationSummary::kNoCall);
diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h
index cc949c5..cea4a7e 100644
--- a/compiler/optimizing/common_arm64.h
+++ b/compiler/optimizing/common_arm64.h
@@ -124,6 +124,18 @@
: static_cast<vixl::aarch64::CPURegister>(InputRegisterAt(instr, index));
}
+static inline vixl::aarch64::CPURegister InputCPURegisterOrZeroRegAt(HInstruction* instr,
+ int index) {
+ HInstruction* input = instr->InputAt(index);
+ Primitive::Type input_type = input->GetType();
+ if (input->IsConstant() && input->AsConstant()->IsZeroBitPattern()) {
+ return (Primitive::ComponentSize(input_type) >= vixl::aarch64::kXRegSizeInBytes)
+ ? vixl::aarch64::xzr
+ : vixl::aarch64::wzr;
+ }
+ return InputCPURegisterAt(instr, index);
+}
+
static inline int64_t Int64ConstantFrom(Location location) {
HConstant* instr = location.GetConstant();
if (instr->IsIntConstant()) {
@@ -339,6 +351,10 @@
return instruction->IsAdd() || instruction->IsSub();
}
+static inline bool IsConstantZeroBitPattern(const HInstruction* instruction) {
+ return instruction->IsConstant() && instruction->AsConstant()->IsZeroBitPattern();
+}
+
} // namespace helpers
} // namespace arm64
} // namespace art
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 91374b3..7482057 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -1466,9 +1466,8 @@
__ Mov(tmp_reg, 0);
}
- __ Ldr(lr, MemOperand(tr, QUICK_ENTRYPOINT_OFFSET(kArm64PointerSize, pIndexOf).Int32Value()));
+ codegen->InvokeRuntime(kQuickIndexOf, invoke, invoke->GetDexPc(), slow_path);
CheckEntrypointTypes<kQuickIndexOf, int32_t, void*, uint32_t, uint32_t>();
- __ Blr(lr);
if (slow_path != nullptr) {
__ Bind(slow_path->GetExitLabel());
@@ -1535,12 +1534,8 @@
codegen_->AddSlowPath(slow_path);
__ B(eq, slow_path->GetEntryLabel());
- __ Ldr(lr,
- MemOperand(tr,
- QUICK_ENTRYPOINT_OFFSET(kArm64PointerSize, pAllocStringFromBytes).Int32Value()));
+ codegen_->InvokeRuntime(kQuickAllocStringFromBytes, invoke, invoke->GetDexPc(), slow_path);
CheckEntrypointTypes<kQuickAllocStringFromBytes, void*, void*, int32_t, int32_t, int32_t>();
- __ Blr(lr);
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
__ Bind(slow_path->GetExitLabel());
}
@@ -1556,20 +1551,14 @@
}
void IntrinsicCodeGeneratorARM64::VisitStringNewStringFromChars(HInvoke* invoke) {
- MacroAssembler* masm = GetVIXLAssembler();
-
// No need to emit code checking whether `locations->InAt(2)` is a null
// pointer, as callers of the native method
//
// java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
//
// all include a null check on `data` before calling that method.
- __ Ldr(lr,
- MemOperand(tr,
- QUICK_ENTRYPOINT_OFFSET(kArm64PointerSize, pAllocStringFromChars).Int32Value()));
+ codegen_->InvokeRuntime(kQuickAllocStringFromChars, invoke, invoke->GetDexPc());
CheckEntrypointTypes<kQuickAllocStringFromChars, void*, int32_t, int32_t, void*>();
- __ Blr(lr);
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
void IntrinsicLocationsBuilderARM64::VisitStringNewStringFromString(HInvoke* invoke) {
@@ -1591,12 +1580,8 @@
codegen_->AddSlowPath(slow_path);
__ B(eq, slow_path->GetEntryLabel());
- __ Ldr(lr,
- MemOperand(tr,
- QUICK_ENTRYPOINT_OFFSET(kArm64PointerSize, pAllocStringFromString).Int32Value()));
+ codegen_->InvokeRuntime(kQuickAllocStringFromString, invoke, invoke->GetDexPc(), slow_path);
CheckEntrypointTypes<kQuickAllocStringFromString, void*, void*>();
- __ Blr(lr);
- codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
__ Bind(slow_path->GetExitLabel());
}
@@ -1631,13 +1616,9 @@
}
static void GenFPToFPCall(HInvoke* invoke,
- MacroAssembler* masm,
CodeGeneratorARM64* codegen,
QuickEntrypointEnum entry) {
- __ Ldr(lr, MemOperand(tr,
- GetThreadOffset<kArm64PointerSize>(entry).Int32Value()));
- __ Blr(lr);
- codegen->RecordPcInfo(invoke, invoke->GetDexPc());
+ codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
}
void IntrinsicLocationsBuilderARM64::VisitMathCos(HInvoke* invoke) {
@@ -1645,7 +1626,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathCos(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickCos);
+ GenFPToFPCall(invoke, codegen_, kQuickCos);
}
void IntrinsicLocationsBuilderARM64::VisitMathSin(HInvoke* invoke) {
@@ -1653,7 +1634,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathSin(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickSin);
+ GenFPToFPCall(invoke, codegen_, kQuickSin);
}
void IntrinsicLocationsBuilderARM64::VisitMathAcos(HInvoke* invoke) {
@@ -1661,7 +1642,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathAcos(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickAcos);
+ GenFPToFPCall(invoke, codegen_, kQuickAcos);
}
void IntrinsicLocationsBuilderARM64::VisitMathAsin(HInvoke* invoke) {
@@ -1669,7 +1650,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathAsin(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickAsin);
+ GenFPToFPCall(invoke, codegen_, kQuickAsin);
}
void IntrinsicLocationsBuilderARM64::VisitMathAtan(HInvoke* invoke) {
@@ -1677,7 +1658,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathAtan(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickAtan);
+ GenFPToFPCall(invoke, codegen_, kQuickAtan);
}
void IntrinsicLocationsBuilderARM64::VisitMathCbrt(HInvoke* invoke) {
@@ -1685,7 +1666,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathCbrt(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickCbrt);
+ GenFPToFPCall(invoke, codegen_, kQuickCbrt);
}
void IntrinsicLocationsBuilderARM64::VisitMathCosh(HInvoke* invoke) {
@@ -1693,7 +1674,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathCosh(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickCosh);
+ GenFPToFPCall(invoke, codegen_, kQuickCosh);
}
void IntrinsicLocationsBuilderARM64::VisitMathExp(HInvoke* invoke) {
@@ -1701,7 +1682,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathExp(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickExp);
+ GenFPToFPCall(invoke, codegen_, kQuickExp);
}
void IntrinsicLocationsBuilderARM64::VisitMathExpm1(HInvoke* invoke) {
@@ -1709,7 +1690,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathExpm1(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickExpm1);
+ GenFPToFPCall(invoke, codegen_, kQuickExpm1);
}
void IntrinsicLocationsBuilderARM64::VisitMathLog(HInvoke* invoke) {
@@ -1717,7 +1698,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathLog(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickLog);
+ GenFPToFPCall(invoke, codegen_, kQuickLog);
}
void IntrinsicLocationsBuilderARM64::VisitMathLog10(HInvoke* invoke) {
@@ -1725,7 +1706,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathLog10(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickLog10);
+ GenFPToFPCall(invoke, codegen_, kQuickLog10);
}
void IntrinsicLocationsBuilderARM64::VisitMathSinh(HInvoke* invoke) {
@@ -1733,7 +1714,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathSinh(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickSinh);
+ GenFPToFPCall(invoke, codegen_, kQuickSinh);
}
void IntrinsicLocationsBuilderARM64::VisitMathTan(HInvoke* invoke) {
@@ -1741,7 +1722,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathTan(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickTan);
+ GenFPToFPCall(invoke, codegen_, kQuickTan);
}
void IntrinsicLocationsBuilderARM64::VisitMathTanh(HInvoke* invoke) {
@@ -1749,7 +1730,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathTanh(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickTanh);
+ GenFPToFPCall(invoke, codegen_, kQuickTanh);
}
void IntrinsicLocationsBuilderARM64::VisitMathAtan2(HInvoke* invoke) {
@@ -1757,7 +1738,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathAtan2(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickAtan2);
+ GenFPToFPCall(invoke, codegen_, kQuickAtan2);
}
void IntrinsicLocationsBuilderARM64::VisitMathHypot(HInvoke* invoke) {
@@ -1765,7 +1746,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathHypot(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickHypot);
+ GenFPToFPCall(invoke, codegen_, kQuickHypot);
}
void IntrinsicLocationsBuilderARM64::VisitMathNextAfter(HInvoke* invoke) {
@@ -1773,7 +1754,7 @@
}
void IntrinsicCodeGeneratorARM64::VisitMathNextAfter(HInvoke* invoke) {
- GenFPToFPCall(invoke, GetVIXLAssembler(), codegen_, kQuickNextAfter);
+ GenFPToFPCall(invoke, codegen_, kQuickNextAfter);
}
void IntrinsicLocationsBuilderARM64::VisitStringGetCharsNoCheck(HInvoke* invoke) {
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index cc9cbda..f7c325e 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -838,9 +838,7 @@
// Always use the Thumb-2 assembler: some runtime functionality
// (like implicit stack overflow checks) assume Thumb-2.
- if (instruction_set == kArm) {
- instruction_set = kThumb2;
- }
+ DCHECK_NE(instruction_set, kArm);
// Do not attempt to compile on architectures we do not support.
if (!IsInstructionSetSupported(instruction_set)) {
diff --git a/compiler/trampolines/trampoline_compiler.cc b/compiler/trampolines/trampoline_compiler.cc
index 304e56b..55835e7 100644
--- a/compiler/trampolines/trampoline_compiler.cc
+++ b/compiler/trampolines/trampoline_compiler.cc
@@ -20,7 +20,7 @@
#include "jni_env_ext.h"
#ifdef ART_ENABLE_CODEGEN_arm
-#include "utils/arm/assembler_thumb2.h"
+#include "utils/arm/assembler_arm_vixl.h"
#endif
#ifdef ART_ENABLE_CODEGEN_arm64
@@ -49,22 +49,37 @@
#ifdef ART_ENABLE_CODEGEN_arm
namespace arm {
+
+#ifdef ___
+#error "ARM Assembler macro already defined."
+#else
+#define ___ assembler.GetVIXLAssembler()->
+#endif
+
static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset32 offset) {
- Thumb2Assembler assembler(arena);
+ using vixl::aarch32::MemOperand;
+ using vixl::aarch32::pc;
+ using vixl::aarch32::r0;
+ ArmVIXLAssembler assembler(arena);
switch (abi) {
case kInterpreterAbi: // Thread* is first argument (R0) in interpreter ABI.
- __ LoadFromOffset(kLoadWord, PC, R0, offset.Int32Value());
+ ___ Ldr(pc, MemOperand(r0, offset.Int32Value()));
break;
- case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (R0).
- __ LoadFromOffset(kLoadWord, IP, R0, JNIEnvExt::SelfOffset(4).Int32Value());
- __ LoadFromOffset(kLoadWord, PC, IP, offset.Int32Value());
+ case kJniAbi: { // Load via Thread* held in JNIEnv* in first argument (R0).
+ vixl::aarch32::UseScratchRegisterScope temps(assembler.GetVIXLAssembler());
+ const vixl::aarch32::Register temp_reg = temps.Acquire();
+
+ // VIXL will use the destination as a scratch register if
+ // the offset is not encodable as an immediate operand.
+ ___ Ldr(temp_reg, MemOperand(r0, JNIEnvExt::SelfOffset(4).Int32Value()));
+ ___ Ldr(pc, MemOperand(temp_reg, offset.Int32Value()));
break;
- case kQuickAbi: // R9 holds Thread*.
- __ LoadFromOffset(kLoadWord, PC, R9, offset.Int32Value());
+ }
+ case kQuickAbi: // TR holds Thread*.
+ ___ Ldr(pc, MemOperand(tr, offset.Int32Value()));
}
- __ bkpt(0);
__ FinalizeCode();
size_t cs = __ CodeSize();
@@ -74,6 +89,9 @@
return std::move(entry_stub);
}
+
+#undef ___
+
} // namespace arm
#endif // ART_ENABLE_CODEGEN_arm
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index c52a5a9..3084e6e 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -28,6 +28,7 @@
#include "base/stl_util.h"
#include "base/value_object.h"
#include "constants_arm.h"
+#include "utils/arm/assembler_arm_shared.h"
#include "utils/arm/managed_register_arm.h"
#include "utils/assembler.h"
#include "utils/jni_macro_assembler.h"
@@ -36,7 +37,6 @@
namespace art {
namespace arm {
-class Arm32Assembler;
class Thumb2Assembler;
// Assembler literal is a value embedded in code, retrieved using a PC-relative load.
@@ -208,7 +208,6 @@
uint32_t rotate_;
uint32_t immed_;
- friend class Arm32Assembler;
friend class Thumb2Assembler;
#ifdef SOURCE_ASSEMBLER_SUPPORT
@@ -216,29 +215,6 @@
#endif
};
-
-enum LoadOperandType {
- kLoadSignedByte,
- kLoadUnsignedByte,
- kLoadSignedHalfword,
- kLoadUnsignedHalfword,
- kLoadWord,
- kLoadWordPair,
- kLoadSWord,
- kLoadDWord
-};
-
-
-enum StoreOperandType {
- kStoreByte,
- kStoreHalfword,
- kStoreWord,
- kStoreWordPair,
- kStoreSWord,
- kStoreDWord
-};
-
-
// Load/store multiple addressing mode.
enum BlockAddressMode {
// bit encoding P U W
@@ -419,13 +395,6 @@
kItE = kItElse
};
-// Set condition codes request.
-enum SetCc {
- kCcDontCare, // Allows prioritizing 16-bit instructions on Thumb2 whether they set CCs or not.
- kCcSet,
- kCcKeep,
-};
-
constexpr uint32_t kNoItCondition = 3;
constexpr uint32_t kInvalidModifiedImmediate = -1;
diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc
deleted file mode 100644
index b8eb60c..0000000
--- a/compiler/utils/arm/assembler_arm32.cc
+++ /dev/null
@@ -1,1725 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "assembler_arm32.h"
-
-#include "base/bit_utils.h"
-#include "base/logging.h"
-#include "entrypoints/quick/quick_entrypoints.h"
-#include "offsets.h"
-#include "thread.h"
-
-namespace art {
-namespace arm {
-
-bool Arm32Assembler::ShifterOperandCanHoldArm32(uint32_t immediate, ShifterOperand* shifter_op) {
- // Avoid the more expensive test for frequent small immediate values.
- if (immediate < (1 << kImmed8Bits)) {
- shifter_op->type_ = ShifterOperand::kImmediate;
- shifter_op->is_rotate_ = true;
- shifter_op->rotate_ = 0;
- shifter_op->immed_ = immediate;
- return true;
- }
- // Note that immediate must be unsigned for the test to work correctly.
- for (int rot = 0; rot < 16; rot++) {
- uint32_t imm8 = (immediate << 2*rot) | (immediate >> (32 - 2*rot));
- if (imm8 < (1 << kImmed8Bits)) {
- shifter_op->type_ = ShifterOperand::kImmediate;
- shifter_op->is_rotate_ = true;
- shifter_op->rotate_ = rot;
- shifter_op->immed_ = imm8;
- return true;
- }
- }
- return false;
-}
-
-bool Arm32Assembler::ShifterOperandCanAlwaysHold(uint32_t immediate) {
- ShifterOperand shifter_op;
- return ShifterOperandCanHoldArm32(immediate, &shifter_op);
-}
-
-bool Arm32Assembler::ShifterOperandCanHold(Register rd ATTRIBUTE_UNUSED,
- Register rn ATTRIBUTE_UNUSED,
- Opcode opcode ATTRIBUTE_UNUSED,
- uint32_t immediate,
- SetCc set_cc ATTRIBUTE_UNUSED,
- ShifterOperand* shifter_op) {
- return ShifterOperandCanHoldArm32(immediate, shifter_op);
-}
-
-void Arm32Assembler::and_(Register rd, Register rn, const ShifterOperand& so,
- Condition cond, SetCc set_cc) {
- EmitType01(cond, so.type(), AND, set_cc, rn, rd, so);
-}
-
-
-void Arm32Assembler::eor(Register rd, Register rn, const ShifterOperand& so,
- Condition cond, SetCc set_cc) {
- EmitType01(cond, so.type(), EOR, set_cc, rn, rd, so);
-}
-
-
-void Arm32Assembler::sub(Register rd, Register rn, const ShifterOperand& so,
- Condition cond, SetCc set_cc) {
- EmitType01(cond, so.type(), SUB, set_cc, rn, rd, so);
-}
-
-void Arm32Assembler::rsb(Register rd, Register rn, const ShifterOperand& so,
- Condition cond, SetCc set_cc) {
- EmitType01(cond, so.type(), RSB, set_cc, rn, rd, so);
-}
-
-void Arm32Assembler::add(Register rd, Register rn, const ShifterOperand& so,
- Condition cond, SetCc set_cc) {
- EmitType01(cond, so.type(), ADD, set_cc, rn, rd, so);
-}
-
-
-void Arm32Assembler::adc(Register rd, Register rn, const ShifterOperand& so,
- Condition cond, SetCc set_cc) {
- EmitType01(cond, so.type(), ADC, set_cc, rn, rd, so);
-}
-
-
-void Arm32Assembler::sbc(Register rd, Register rn, const ShifterOperand& so,
- Condition cond, SetCc set_cc) {
- EmitType01(cond, so.type(), SBC, set_cc, rn, rd, so);
-}
-
-
-void Arm32Assembler::rsc(Register rd, Register rn, const ShifterOperand& so,
- Condition cond, SetCc set_cc) {
- EmitType01(cond, so.type(), RSC, set_cc, rn, rd, so);
-}
-
-
-void Arm32Assembler::tst(Register rn, const ShifterOperand& so, Condition cond) {
- CHECK_NE(rn, PC); // Reserve tst pc instruction for exception handler marker.
- EmitType01(cond, so.type(), TST, kCcSet, rn, R0, so);
-}
-
-
-void Arm32Assembler::teq(Register rn, const ShifterOperand& so, Condition cond) {
- CHECK_NE(rn, PC); // Reserve teq pc instruction for exception handler marker.
- EmitType01(cond, so.type(), TEQ, kCcSet, rn, R0, so);
-}
-
-
-void Arm32Assembler::cmp(Register rn, const ShifterOperand& so, Condition cond) {
- EmitType01(cond, so.type(), CMP, kCcSet, rn, R0, so);
-}
-
-
-void Arm32Assembler::cmn(Register rn, const ShifterOperand& so, Condition cond) {
- EmitType01(cond, so.type(), CMN, kCcSet, rn, R0, so);
-}
-
-
-void Arm32Assembler::orr(Register rd, Register rn, const ShifterOperand& so,
- Condition cond, SetCc set_cc) {
- EmitType01(cond, so.type(), ORR, set_cc, rn, rd, so);
-}
-
-
-void Arm32Assembler::orn(Register rd ATTRIBUTE_UNUSED,
- Register rn ATTRIBUTE_UNUSED,
- const ShifterOperand& so ATTRIBUTE_UNUSED,
- Condition cond ATTRIBUTE_UNUSED,
- SetCc set_cc ATTRIBUTE_UNUSED) {
- LOG(FATAL) << "orn is not supported on ARM32";
-}
-
-
-void Arm32Assembler::mov(Register rd, const ShifterOperand& so,
- Condition cond, SetCc set_cc) {
- EmitType01(cond, so.type(), MOV, set_cc, R0, rd, so);
-}
-
-
-void Arm32Assembler::bic(Register rd, Register rn, const ShifterOperand& so,
- Condition cond, SetCc set_cc) {
- EmitType01(cond, so.type(), BIC, set_cc, rn, rd, so);
-}
-
-
-void Arm32Assembler::mvn(Register rd, const ShifterOperand& so,
- Condition cond, SetCc set_cc) {
- EmitType01(cond, so.type(), MVN, set_cc, R0, rd, so);
-}
-
-
-void Arm32Assembler::mul(Register rd, Register rn, Register rm, Condition cond) {
- // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
- EmitMulOp(cond, 0, R0, rd, rn, rm);
-}
-
-
-void Arm32Assembler::mla(Register rd, Register rn, Register rm, Register ra,
- Condition cond) {
- // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
- EmitMulOp(cond, B21, ra, rd, rn, rm);
-}
-
-
-void Arm32Assembler::mls(Register rd, Register rn, Register rm, Register ra,
- Condition cond) {
- // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
- EmitMulOp(cond, B22 | B21, ra, rd, rn, rm);
-}
-
-
-void Arm32Assembler::smull(Register rd_lo, Register rd_hi, Register rn,
- Register rm, Condition cond) {
- // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
- EmitMulOp(cond, B23 | B22, rd_lo, rd_hi, rn, rm);
-}
-
-
-void Arm32Assembler::umull(Register rd_lo, Register rd_hi, Register rn,
- Register rm, Condition cond) {
- // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
- EmitMulOp(cond, B23, rd_lo, rd_hi, rn, rm);
-}
-
-
-void Arm32Assembler::sdiv(Register rd, Register rn, Register rm, Condition cond) {
- CHECK_NE(rd, kNoRegister);
- CHECK_NE(rn, kNoRegister);
- CHECK_NE(rm, kNoRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = B26 | B25 | B24 | B20 |
- B15 | B14 | B13 | B12 |
- (static_cast<int32_t>(cond) << kConditionShift) |
- (static_cast<int32_t>(rn) << 0) |
- (static_cast<int32_t>(rd) << 16) |
- (static_cast<int32_t>(rm) << 8) |
- B4;
- Emit(encoding);
-}
-
-
-void Arm32Assembler::udiv(Register rd, Register rn, Register rm, Condition cond) {
- CHECK_NE(rd, kNoRegister);
- CHECK_NE(rn, kNoRegister);
- CHECK_NE(rm, kNoRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = B26 | B25 | B24 | B21 | B20 |
- B15 | B14 | B13 | B12 |
- (static_cast<int32_t>(cond) << kConditionShift) |
- (static_cast<int32_t>(rn) << 0) |
- (static_cast<int32_t>(rd) << 16) |
- (static_cast<int32_t>(rm) << 8) |
- B4;
- Emit(encoding);
-}
-
-
-void Arm32Assembler::sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond) {
- CHECK_NE(rd, kNoRegister);
- CHECK_NE(rn, kNoRegister);
- CHECK_NE(cond, kNoCondition);
- CHECK_LE(lsb, 31U);
- CHECK(1U <= width && width <= 32U) << width;
- uint32_t widthminus1 = width - 1;
-
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B26 | B25 | B24 | B23 | B21 |
- (widthminus1 << 16) |
- (static_cast<uint32_t>(rd) << 12) |
- (lsb << 7) |
- B6 | B4 |
- static_cast<uint32_t>(rn);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond) {
- CHECK_NE(rd, kNoRegister);
- CHECK_NE(rn, kNoRegister);
- CHECK_NE(cond, kNoCondition);
- CHECK_LE(lsb, 31U);
- CHECK(1U <= width && width <= 32U) << width;
- uint32_t widthminus1 = width - 1;
-
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B26 | B25 | B24 | B23 | B22 | B21 |
- (widthminus1 << 16) |
- (static_cast<uint32_t>(rd) << 12) |
- (lsb << 7) |
- B6 | B4 |
- static_cast<uint32_t>(rn);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::ldr(Register rd, const Address& ad, Condition cond) {
- EmitMemOp(cond, true, false, rd, ad);
-}
-
-
-void Arm32Assembler::str(Register rd, const Address& ad, Condition cond) {
- EmitMemOp(cond, false, false, rd, ad);
-}
-
-
-void Arm32Assembler::ldrb(Register rd, const Address& ad, Condition cond) {
- EmitMemOp(cond, true, true, rd, ad);
-}
-
-
-void Arm32Assembler::strb(Register rd, const Address& ad, Condition cond) {
- EmitMemOp(cond, false, true, rd, ad);
-}
-
-
-void Arm32Assembler::ldrh(Register rd, const Address& ad, Condition cond) {
- EmitMemOpAddressMode3(cond, L | B7 | H | B4, rd, ad);
-}
-
-
-void Arm32Assembler::strh(Register rd, const Address& ad, Condition cond) {
- EmitMemOpAddressMode3(cond, B7 | H | B4, rd, ad);
-}
-
-
-void Arm32Assembler::ldrsb(Register rd, const Address& ad, Condition cond) {
- EmitMemOpAddressMode3(cond, L | B7 | B6 | B4, rd, ad);
-}
-
-
-void Arm32Assembler::ldrsh(Register rd, const Address& ad, Condition cond) {
- EmitMemOpAddressMode3(cond, L | B7 | B6 | H | B4, rd, ad);
-}
-
-
-void Arm32Assembler::ldrd(Register rd, const Address& ad, Condition cond) {
- CHECK_EQ(rd % 2, 0);
- EmitMemOpAddressMode3(cond, B7 | B6 | B4, rd, ad);
-}
-
-
-void Arm32Assembler::strd(Register rd, const Address& ad, Condition cond) {
- CHECK_EQ(rd % 2, 0);
- EmitMemOpAddressMode3(cond, B7 | B6 | B5 | B4, rd, ad);
-}
-
-
-void Arm32Assembler::ldm(BlockAddressMode am,
- Register base,
- RegList regs,
- Condition cond) {
- EmitMultiMemOp(cond, am, true, base, regs);
-}
-
-
-void Arm32Assembler::stm(BlockAddressMode am,
- Register base,
- RegList regs,
- Condition cond) {
- EmitMultiMemOp(cond, am, false, base, regs);
-}
-
-
-void Arm32Assembler::vmovs(SRegister sd, SRegister sm, Condition cond) {
- EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm);
-}
-
-
-void Arm32Assembler::vmovd(DRegister dd, DRegister dm, Condition cond) {
- EmitVFPddd(cond, B23 | B21 | B20 | B6, dd, D0, dm);
-}
-
-
-bool Arm32Assembler::vmovs(SRegister sd, float s_imm, Condition cond) {
- uint32_t imm32 = bit_cast<uint32_t, float>(s_imm);
- if (((imm32 & ((1 << 19) - 1)) == 0) &&
- ((((imm32 >> 25) & ((1 << 6) - 1)) == (1 << 5)) ||
- (((imm32 >> 25) & ((1 << 6) - 1)) == ((1 << 5) -1)))) {
- uint8_t imm8 = ((imm32 >> 31) << 7) | (((imm32 >> 29) & 1) << 6) |
- ((imm32 >> 19) & ((1 << 6) -1));
- EmitVFPsss(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | (imm8 & 0xf),
- sd, S0, S0);
- return true;
- }
- return false;
-}
-
-
-bool Arm32Assembler::vmovd(DRegister dd, double d_imm, Condition cond) {
- uint64_t imm64 = bit_cast<uint64_t, double>(d_imm);
- if (((imm64 & ((1LL << 48) - 1)) == 0) &&
- ((((imm64 >> 54) & ((1 << 9) - 1)) == (1 << 8)) ||
- (((imm64 >> 54) & ((1 << 9) - 1)) == ((1 << 8) -1)))) {
- uint8_t imm8 = ((imm64 >> 63) << 7) | (((imm64 >> 61) & 1) << 6) |
- ((imm64 >> 48) & ((1 << 6) -1));
- EmitVFPddd(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | B8 | (imm8 & 0xf),
- dd, D0, D0);
- return true;
- }
- return false;
-}
-
-
-void Arm32Assembler::vadds(SRegister sd, SRegister sn, SRegister sm,
- Condition cond) {
- EmitVFPsss(cond, B21 | B20, sd, sn, sm);
-}
-
-
-void Arm32Assembler::vaddd(DRegister dd, DRegister dn, DRegister dm,
- Condition cond) {
- EmitVFPddd(cond, B21 | B20, dd, dn, dm);
-}
-
-
-void Arm32Assembler::vsubs(SRegister sd, SRegister sn, SRegister sm,
- Condition cond) {
- EmitVFPsss(cond, B21 | B20 | B6, sd, sn, sm);
-}
-
-
-void Arm32Assembler::vsubd(DRegister dd, DRegister dn, DRegister dm,
- Condition cond) {
- EmitVFPddd(cond, B21 | B20 | B6, dd, dn, dm);
-}
-
-
-void Arm32Assembler::vmuls(SRegister sd, SRegister sn, SRegister sm,
- Condition cond) {
- EmitVFPsss(cond, B21, sd, sn, sm);
-}
-
-
-void Arm32Assembler::vmuld(DRegister dd, DRegister dn, DRegister dm,
- Condition cond) {
- EmitVFPddd(cond, B21, dd, dn, dm);
-}
-
-
-void Arm32Assembler::vmlas(SRegister sd, SRegister sn, SRegister sm,
- Condition cond) {
- EmitVFPsss(cond, 0, sd, sn, sm);
-}
-
-
-void Arm32Assembler::vmlad(DRegister dd, DRegister dn, DRegister dm,
- Condition cond) {
- EmitVFPddd(cond, 0, dd, dn, dm);
-}
-
-
-void Arm32Assembler::vmlss(SRegister sd, SRegister sn, SRegister sm,
- Condition cond) {
- EmitVFPsss(cond, B6, sd, sn, sm);
-}
-
-
-void Arm32Assembler::vmlsd(DRegister dd, DRegister dn, DRegister dm,
- Condition cond) {
- EmitVFPddd(cond, B6, dd, dn, dm);
-}
-
-
-void Arm32Assembler::vdivs(SRegister sd, SRegister sn, SRegister sm,
- Condition cond) {
- EmitVFPsss(cond, B23, sd, sn, sm);
-}
-
-
-void Arm32Assembler::vdivd(DRegister dd, DRegister dn, DRegister dm,
- Condition cond) {
- EmitVFPddd(cond, B23, dd, dn, dm);
-}
-
-
-void Arm32Assembler::vabss(SRegister sd, SRegister sm, Condition cond) {
- EmitVFPsss(cond, B23 | B21 | B20 | B7 | B6, sd, S0, sm);
-}
-
-
-void Arm32Assembler::vabsd(DRegister dd, DRegister dm, Condition cond) {
- EmitVFPddd(cond, B23 | B21 | B20 | B7 | B6, dd, D0, dm);
-}
-
-
-void Arm32Assembler::vnegs(SRegister sd, SRegister sm, Condition cond) {
- EmitVFPsss(cond, B23 | B21 | B20 | B16 | B6, sd, S0, sm);
-}
-
-
-void Arm32Assembler::vnegd(DRegister dd, DRegister dm, Condition cond) {
- EmitVFPddd(cond, B23 | B21 | B20 | B16 | B6, dd, D0, dm);
-}
-
-
-void Arm32Assembler::vsqrts(SRegister sd, SRegister sm, Condition cond) {
- EmitVFPsss(cond, B23 | B21 | B20 | B16 | B7 | B6, sd, S0, sm);
-}
-
-void Arm32Assembler::vsqrtd(DRegister dd, DRegister dm, Condition cond) {
- EmitVFPddd(cond, B23 | B21 | B20 | B16 | B7 | B6, dd, D0, dm);
-}
-
-
-void Arm32Assembler::vcvtsd(SRegister sd, DRegister dm, Condition cond) {
- EmitVFPsd(cond, B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6, sd, dm);
-}
-
-
-void Arm32Assembler::vcvtds(DRegister dd, SRegister sm, Condition cond) {
- EmitVFPds(cond, B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6, dd, sm);
-}
-
-
-void Arm32Assembler::vcvtis(SRegister sd, SRegister sm, Condition cond) {
- EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B16 | B7 | B6, sd, S0, sm);
-}
-
-
-void Arm32Assembler::vcvtid(SRegister sd, DRegister dm, Condition cond) {
- EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B16 | B8 | B7 | B6, sd, dm);
-}
-
-
-void Arm32Assembler::vcvtsi(SRegister sd, SRegister sm, Condition cond) {
- EmitVFPsss(cond, B23 | B21 | B20 | B19 | B7 | B6, sd, S0, sm);
-}
-
-
-void Arm32Assembler::vcvtdi(DRegister dd, SRegister sm, Condition cond) {
- EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B7 | B6, dd, sm);
-}
-
-
-void Arm32Assembler::vcvtus(SRegister sd, SRegister sm, Condition cond) {
- EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B7 | B6, sd, S0, sm);
-}
-
-
-void Arm32Assembler::vcvtud(SRegister sd, DRegister dm, Condition cond) {
- EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B8 | B7 | B6, sd, dm);
-}
-
-
-void Arm32Assembler::vcvtsu(SRegister sd, SRegister sm, Condition cond) {
- EmitVFPsss(cond, B23 | B21 | B20 | B19 | B6, sd, S0, sm);
-}
-
-
-void Arm32Assembler::vcvtdu(DRegister dd, SRegister sm, Condition cond) {
- EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B6, dd, sm);
-}
-
-
-void Arm32Assembler::vcmps(SRegister sd, SRegister sm, Condition cond) {
- EmitVFPsss(cond, B23 | B21 | B20 | B18 | B6, sd, S0, sm);
-}
-
-
-void Arm32Assembler::vcmpd(DRegister dd, DRegister dm, Condition cond) {
- EmitVFPddd(cond, B23 | B21 | B20 | B18 | B6, dd, D0, dm);
-}
-
-
-void Arm32Assembler::vcmpsz(SRegister sd, Condition cond) {
- EmitVFPsss(cond, B23 | B21 | B20 | B18 | B16 | B6, sd, S0, S0);
-}
-
-
-void Arm32Assembler::vcmpdz(DRegister dd, Condition cond) {
- EmitVFPddd(cond, B23 | B21 | B20 | B18 | B16 | B6, dd, D0, D0);
-}
-
-void Arm32Assembler::b(Label* label, Condition cond) {
- EmitBranch(cond, label, false);
-}
-
-
-void Arm32Assembler::bl(Label* label, Condition cond) {
- EmitBranch(cond, label, true);
-}
-
-
-void Arm32Assembler::MarkExceptionHandler(Label* label) {
- EmitType01(AL, 1, TST, kCcSet, PC, R0, ShifterOperand(0));
- Label l;
- b(&l);
- EmitBranch(AL, label, false);
- Bind(&l);
-}
-
-
-void Arm32Assembler::Emit(int32_t value) {
- AssemblerBuffer::EnsureCapacity ensured(&buffer_);
- buffer_.Emit<int32_t>(value);
-}
-
-
-void Arm32Assembler::EmitType01(Condition cond,
- int type,
- Opcode opcode,
- SetCc set_cc,
- Register rn,
- Register rd,
- const ShifterOperand& so) {
- CHECK_NE(rd, kNoRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
- type << kTypeShift |
- static_cast<int32_t>(opcode) << kOpcodeShift |
- (set_cc == kCcSet ? 1 : 0) << kSShift |
- static_cast<int32_t>(rn) << kRnShift |
- static_cast<int32_t>(rd) << kRdShift |
- so.encodingArm();
- Emit(encoding);
-}
-
-
-void Arm32Assembler::EmitType5(Condition cond, int offset, bool link) {
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
- 5 << kTypeShift |
- (link ? 1 : 0) << kLinkShift;
- Emit(Arm32Assembler::EncodeBranchOffset(offset, encoding));
-}
-
-
-void Arm32Assembler::EmitMemOp(Condition cond,
- bool load,
- bool byte,
- Register rd,
- const Address& ad) {
- CHECK_NE(rd, kNoRegister);
- CHECK_NE(cond, kNoCondition);
- const Address& addr = static_cast<const Address&>(ad);
-
- int32_t encoding = 0;
- if (!ad.IsImmediate() && ad.GetRegisterOffset() == PC) {
- // PC relative LDR(literal)
- int32_t offset = ad.GetOffset();
- int32_t u = B23;
- if (offset < 0) {
- offset = -offset;
- u = 0;
- }
- CHECK_LT(offset, (1 << 12));
- encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B26 | B24 | u | B20 |
- (load ? L : 0) |
- (byte ? B : 0) |
- (static_cast<int32_t>(rd) << kRdShift) |
- 0xf << 16 |
- (offset & 0xfff);
-
- } else {
- encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B26 |
- (load ? L : 0) |
- (byte ? B : 0) |
- (static_cast<int32_t>(rd) << kRdShift) |
- addr.encodingArm();
- }
- Emit(encoding);
-}
-
-
-void Arm32Assembler::EmitMemOpAddressMode3(Condition cond,
- int32_t mode,
- Register rd,
- const Address& ad) {
- CHECK_NE(rd, kNoRegister);
- CHECK_NE(cond, kNoCondition);
- const Address& addr = static_cast<const Address&>(ad);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B22 |
- mode |
- (static_cast<int32_t>(rd) << kRdShift) |
- addr.encoding3();
- Emit(encoding);
-}
-
-
-void Arm32Assembler::EmitMultiMemOp(Condition cond,
- BlockAddressMode am,
- bool load,
- Register base,
- RegList regs) {
- CHECK_NE(base, kNoRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 |
- am |
- (load ? L : 0) |
- (static_cast<int32_t>(base) << kRnShift) |
- regs;
- Emit(encoding);
-}
-
-
-void Arm32Assembler::EmitShiftImmediate(Condition cond,
- Shift opcode,
- Register rd,
- Register rm,
- const ShifterOperand& so) {
- CHECK_NE(cond, kNoCondition);
- CHECK(so.IsImmediate());
- int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
- static_cast<int32_t>(MOV) << kOpcodeShift |
- static_cast<int32_t>(rd) << kRdShift |
- so.encodingArm() << kShiftImmShift |
- static_cast<int32_t>(opcode) << kShiftShift |
- static_cast<int32_t>(rm);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::EmitShiftRegister(Condition cond,
- Shift opcode,
- Register rd,
- Register rm,
- const ShifterOperand& so) {
- CHECK_NE(cond, kNoCondition);
- CHECK(so.IsRegister());
- int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
- static_cast<int32_t>(MOV) << kOpcodeShift |
- static_cast<int32_t>(rd) << kRdShift |
- so.encodingArm() << kShiftRegisterShift |
- static_cast<int32_t>(opcode) << kShiftShift |
- B4 |
- static_cast<int32_t>(rm);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::EmitBranch(Condition cond, Label* label, bool link) {
- if (label->IsBound()) {
- EmitType5(cond, label->Position() - buffer_.Size(), link);
- } else {
- int position = buffer_.Size();
- // Use the offset field of the branch instruction for linking the sites.
- EmitType5(cond, label->position_, link);
- label->LinkTo(position);
- }
-}
-
-
-void Arm32Assembler::clz(Register rd, Register rm, Condition cond) {
- CHECK_NE(rd, kNoRegister);
- CHECK_NE(rm, kNoRegister);
- CHECK_NE(cond, kNoCondition);
- CHECK_NE(rd, PC);
- CHECK_NE(rm, PC);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B24 | B22 | B21 | (0xf << 16) |
- (static_cast<int32_t>(rd) << kRdShift) |
- (0xf << 8) | B4 | static_cast<int32_t>(rm);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
- B25 | B24 | ((imm16 >> 12) << 16) |
- static_cast<int32_t>(rd) << kRdShift | (imm16 & 0xfff);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
- B25 | B24 | B22 | ((imm16 >> 12) << 16) |
- static_cast<int32_t>(rd) << kRdShift | (imm16 & 0xfff);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::EmitMiscellaneous(Condition cond, uint8_t op1,
- uint8_t op2, uint32_t a_part,
- uint32_t rest) {
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B26 | B25 | B23 |
- (op1 << 20) |
- (a_part << 16) |
- (op2 << 5) |
- B4 |
- rest;
- Emit(encoding);
-}
-
-
-void Arm32Assembler::EmitReverseBytes(Register rd, Register rm, Condition cond,
- uint8_t op1, uint8_t op2) {
- CHECK_NE(rd, kNoRegister);
- CHECK_NE(rm, kNoRegister);
- CHECK_NE(cond, kNoCondition);
- CHECK_NE(rd, PC);
- CHECK_NE(rm, PC);
-
- int32_t encoding = (static_cast<int32_t>(rd) << kRdShift) |
- (0b1111 << 8) |
- static_cast<int32_t>(rm);
- EmitMiscellaneous(cond, op1, op2, 0b1111, encoding);
-}
-
-
-void Arm32Assembler::rbit(Register rd, Register rm, Condition cond) {
- CHECK_NE(rd, kNoRegister);
- CHECK_NE(rm, kNoRegister);
- CHECK_NE(cond, kNoCondition);
- CHECK_NE(rd, PC);
- CHECK_NE(rm, PC);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B26 | B25 | B23 | B22 | B21 | B20 | (0xf << 16) |
- (static_cast<int32_t>(rd) << kRdShift) |
- (0xf << 8) | B5 | B4 | static_cast<int32_t>(rm);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::rev(Register rd, Register rm, Condition cond) {
- EmitReverseBytes(rd, rm, cond, 0b011, 0b001);
-}
-
-
-void Arm32Assembler::rev16(Register rd, Register rm, Condition cond) {
- EmitReverseBytes(rd, rm, cond, 0b011, 0b101);
-}
-
-
-void Arm32Assembler::revsh(Register rd, Register rm, Condition cond) {
- EmitReverseBytes(rd, rm, cond, 0b111, 0b101);
-}
-
-
-void Arm32Assembler::EmitMulOp(Condition cond, int32_t opcode,
- Register rd, Register rn,
- Register rm, Register rs) {
- CHECK_NE(rd, kNoRegister);
- CHECK_NE(rn, kNoRegister);
- CHECK_NE(rm, kNoRegister);
- CHECK_NE(rs, kNoRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = opcode |
- (static_cast<int32_t>(cond) << kConditionShift) |
- (static_cast<int32_t>(rn) << kRnShift) |
- (static_cast<int32_t>(rd) << kRdShift) |
- (static_cast<int32_t>(rs) << kRsShift) |
- B7 | B4 |
- (static_cast<int32_t>(rm) << kRmShift);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::ldrex(Register rt, Register rn, Condition cond) {
- CHECK_NE(rn, kNoRegister);
- CHECK_NE(rt, kNoRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B24 |
- B23 |
- L |
- (static_cast<int32_t>(rn) << kLdExRnShift) |
- (static_cast<int32_t>(rt) << kLdExRtShift) |
- B11 | B10 | B9 | B8 | B7 | B4 | B3 | B2 | B1 | B0;
- Emit(encoding);
-}
-
-
-void Arm32Assembler::ldrexd(Register rt, Register rt2, Register rn, Condition cond) {
- CHECK_NE(rn, kNoRegister);
- CHECK_NE(rt, kNoRegister);
- CHECK_NE(rt2, kNoRegister);
- CHECK_NE(rt, R14);
- CHECK_EQ(0u, static_cast<uint32_t>(rt) % 2);
- CHECK_EQ(static_cast<uint32_t>(rt) + 1, static_cast<uint32_t>(rt2));
- CHECK_NE(cond, kNoCondition);
-
- int32_t encoding =
- (static_cast<uint32_t>(cond) << kConditionShift) |
- B24 | B23 | B21 | B20 |
- static_cast<uint32_t>(rn) << 16 |
- static_cast<uint32_t>(rt) << 12 |
- B11 | B10 | B9 | B8 | B7 | B4 | B3 | B2 | B1 | B0;
- Emit(encoding);
-}
-
-
-void Arm32Assembler::strex(Register rd,
- Register rt,
- Register rn,
- Condition cond) {
- CHECK_NE(rn, kNoRegister);
- CHECK_NE(rd, kNoRegister);
- CHECK_NE(rt, kNoRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B24 |
- B23 |
- (static_cast<int32_t>(rn) << kStrExRnShift) |
- (static_cast<int32_t>(rd) << kStrExRdShift) |
- B11 | B10 | B9 | B8 | B7 | B4 |
- (static_cast<int32_t>(rt) << kStrExRtShift);
- Emit(encoding);
-}
-
-void Arm32Assembler::strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond) {
- CHECK_NE(rd, kNoRegister);
- CHECK_NE(rn, kNoRegister);
- CHECK_NE(rt, kNoRegister);
- CHECK_NE(rt2, kNoRegister);
- CHECK_NE(rt, R14);
- CHECK_NE(rd, rt);
- CHECK_NE(rd, rt2);
- CHECK_EQ(0u, static_cast<uint32_t>(rt) % 2);
- CHECK_EQ(static_cast<uint32_t>(rt) + 1, static_cast<uint32_t>(rt2));
- CHECK_NE(cond, kNoCondition);
-
- int32_t encoding =
- (static_cast<uint32_t>(cond) << kConditionShift) |
- B24 | B23 | B21 |
- static_cast<uint32_t>(rn) << 16 |
- static_cast<uint32_t>(rd) << 12 |
- B11 | B10 | B9 | B8 | B7 | B4 |
- static_cast<uint32_t>(rt);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::clrex(Condition cond) {
- CHECK_EQ(cond, AL); // This cannot be conditional on ARM.
- int32_t encoding = (kSpecialCondition << kConditionShift) |
- B26 | B24 | B22 | B21 | B20 | (0xff << 12) | B4 | 0xf;
- Emit(encoding);
-}
-
-
-void Arm32Assembler::nop(Condition cond) {
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B25 | B24 | B21 | (0xf << 12);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::vmovsr(SRegister sn, Register rt, Condition cond) {
- CHECK_NE(sn, kNoSRegister);
- CHECK_NE(rt, kNoRegister);
- CHECK_NE(rt, SP);
- CHECK_NE(rt, PC);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 | B26 | B25 |
- ((static_cast<int32_t>(sn) >> 1)*B16) |
- (static_cast<int32_t>(rt)*B12) | B11 | B9 |
- ((static_cast<int32_t>(sn) & 1)*B7) | B4;
- Emit(encoding);
-}
-
-
-void Arm32Assembler::vmovrs(Register rt, SRegister sn, Condition cond) {
- CHECK_NE(sn, kNoSRegister);
- CHECK_NE(rt, kNoRegister);
- CHECK_NE(rt, SP);
- CHECK_NE(rt, PC);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 | B26 | B25 | B20 |
- ((static_cast<int32_t>(sn) >> 1)*B16) |
- (static_cast<int32_t>(rt)*B12) | B11 | B9 |
- ((static_cast<int32_t>(sn) & 1)*B7) | B4;
- Emit(encoding);
-}
-
-
-void Arm32Assembler::vmovsrr(SRegister sm, Register rt, Register rt2,
- Condition cond) {
- CHECK_NE(sm, kNoSRegister);
- CHECK_NE(sm, S31);
- CHECK_NE(rt, kNoRegister);
- CHECK_NE(rt, SP);
- CHECK_NE(rt, PC);
- CHECK_NE(rt2, kNoRegister);
- CHECK_NE(rt2, SP);
- CHECK_NE(rt2, PC);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 | B26 | B22 |
- (static_cast<int32_t>(rt2)*B16) |
- (static_cast<int32_t>(rt)*B12) | B11 | B9 |
- ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
- (static_cast<int32_t>(sm) >> 1);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::vmovrrs(Register rt, Register rt2, SRegister sm,
- Condition cond) {
- CHECK_NE(sm, kNoSRegister);
- CHECK_NE(sm, S31);
- CHECK_NE(rt, kNoRegister);
- CHECK_NE(rt, SP);
- CHECK_NE(rt, PC);
- CHECK_NE(rt2, kNoRegister);
- CHECK_NE(rt2, SP);
- CHECK_NE(rt2, PC);
- CHECK_NE(rt, rt2);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 | B26 | B22 | B20 |
- (static_cast<int32_t>(rt2)*B16) |
- (static_cast<int32_t>(rt)*B12) | B11 | B9 |
- ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
- (static_cast<int32_t>(sm) >> 1);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
- Condition cond) {
- CHECK_NE(dm, kNoDRegister);
- CHECK_NE(rt, kNoRegister);
- CHECK_NE(rt, SP);
- CHECK_NE(rt, PC);
- CHECK_NE(rt2, kNoRegister);
- CHECK_NE(rt2, SP);
- CHECK_NE(rt2, PC);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 | B26 | B22 |
- (static_cast<int32_t>(rt2)*B16) |
- (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
- ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
- (static_cast<int32_t>(dm) & 0xf);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
- Condition cond) {
- CHECK_NE(dm, kNoDRegister);
- CHECK_NE(rt, kNoRegister);
- CHECK_NE(rt, SP);
- CHECK_NE(rt, PC);
- CHECK_NE(rt2, kNoRegister);
- CHECK_NE(rt2, SP);
- CHECK_NE(rt2, PC);
- CHECK_NE(rt, rt2);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 | B26 | B22 | B20 |
- (static_cast<int32_t>(rt2)*B16) |
- (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
- ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
- (static_cast<int32_t>(dm) & 0xf);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::vldrs(SRegister sd, const Address& ad, Condition cond) {
- const Address& addr = static_cast<const Address&>(ad);
- CHECK_NE(sd, kNoSRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 | B26 | B24 | B20 |
- ((static_cast<int32_t>(sd) & 1)*B22) |
- ((static_cast<int32_t>(sd) >> 1)*B12) |
- B11 | B9 | addr.vencoding();
- Emit(encoding);
-}
-
-
-void Arm32Assembler::vstrs(SRegister sd, const Address& ad, Condition cond) {
- const Address& addr = static_cast<const Address&>(ad);
- CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
- CHECK_NE(sd, kNoSRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 | B26 | B24 |
- ((static_cast<int32_t>(sd) & 1)*B22) |
- ((static_cast<int32_t>(sd) >> 1)*B12) |
- B11 | B9 | addr.vencoding();
- Emit(encoding);
-}
-
-
-void Arm32Assembler::vldrd(DRegister dd, const Address& ad, Condition cond) {
- const Address& addr = static_cast<const Address&>(ad);
- CHECK_NE(dd, kNoDRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 | B26 | B24 | B20 |
- ((static_cast<int32_t>(dd) >> 4)*B22) |
- ((static_cast<int32_t>(dd) & 0xf)*B12) |
- B11 | B9 | B8 | addr.vencoding();
- Emit(encoding);
-}
-
-
-void Arm32Assembler::vstrd(DRegister dd, const Address& ad, Condition cond) {
- const Address& addr = static_cast<const Address&>(ad);
- CHECK_NE(static_cast<Register>(addr.encodingArm() & (0xf << kRnShift)), PC);
- CHECK_NE(dd, kNoDRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 | B26 | B24 |
- ((static_cast<int32_t>(dd) >> 4)*B22) |
- ((static_cast<int32_t>(dd) & 0xf)*B12) |
- B11 | B9 | B8 | addr.vencoding();
- Emit(encoding);
-}
-
-
-void Arm32Assembler::vpushs(SRegister reg, int nregs, Condition cond) {
- EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, false, cond);
-}
-
-
-void Arm32Assembler::vpushd(DRegister reg, int nregs, Condition cond) {
- EmitVPushPop(static_cast<uint32_t>(reg), nregs, true, true, cond);
-}
-
-
-void Arm32Assembler::vpops(SRegister reg, int nregs, Condition cond) {
- EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, false, cond);
-}
-
-
-void Arm32Assembler::vpopd(DRegister reg, int nregs, Condition cond) {
- EmitVPushPop(static_cast<uint32_t>(reg), nregs, false, true, cond);
-}
-
-
-void Arm32Assembler::vldmiad(Register, DRegister, int, Condition) {
- LOG(FATAL) << "Unimplemented.";
- UNREACHABLE();
-}
-
-
-void Arm32Assembler::vstmiad(Register, DRegister, int, Condition) {
- LOG(FATAL) << "Unimplemented.";
- UNREACHABLE();
-}
-
-
-void Arm32Assembler::EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond) {
- CHECK_NE(cond, kNoCondition);
- CHECK_GT(nregs, 0);
- uint32_t D;
- uint32_t Vd;
- if (dbl) {
- // Encoded as D:Vd.
- D = (reg >> 4) & 1;
- Vd = reg & 15U /* 0b1111 */;
- } else {
- // Encoded as Vd:D.
- D = reg & 1;
- Vd = (reg >> 1) & 15U /* 0b1111 */;
- }
- int32_t encoding = B27 | B26 | B21 | B19 | B18 | B16 |
- B11 | B9 |
- (dbl ? B8 : 0) |
- (push ? B24 : (B23 | B20)) |
- static_cast<int32_t>(cond) << kConditionShift |
- nregs << (dbl ? 1 : 0) |
- D << 22 |
- Vd << 12;
- Emit(encoding);
-}
-
-
-void Arm32Assembler::EmitVFPsss(Condition cond, int32_t opcode,
- SRegister sd, SRegister sn, SRegister sm) {
- CHECK_NE(sd, kNoSRegister);
- CHECK_NE(sn, kNoSRegister);
- CHECK_NE(sm, kNoSRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 | B26 | B25 | B11 | B9 | opcode |
- ((static_cast<int32_t>(sd) & 1)*B22) |
- ((static_cast<int32_t>(sn) >> 1)*B16) |
- ((static_cast<int32_t>(sd) >> 1)*B12) |
- ((static_cast<int32_t>(sn) & 1)*B7) |
- ((static_cast<int32_t>(sm) & 1)*B5) |
- (static_cast<int32_t>(sm) >> 1);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::EmitVFPddd(Condition cond, int32_t opcode,
- DRegister dd, DRegister dn, DRegister dm) {
- CHECK_NE(dd, kNoDRegister);
- CHECK_NE(dn, kNoDRegister);
- CHECK_NE(dm, kNoDRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 | B26 | B25 | B11 | B9 | B8 | opcode |
- ((static_cast<int32_t>(dd) >> 4)*B22) |
- ((static_cast<int32_t>(dn) & 0xf)*B16) |
- ((static_cast<int32_t>(dd) & 0xf)*B12) |
- ((static_cast<int32_t>(dn) >> 4)*B7) |
- ((static_cast<int32_t>(dm) >> 4)*B5) |
- (static_cast<int32_t>(dm) & 0xf);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::EmitVFPsd(Condition cond, int32_t opcode,
- SRegister sd, DRegister dm) {
- CHECK_NE(sd, kNoSRegister);
- CHECK_NE(dm, kNoDRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 | B26 | B25 | B11 | B9 | opcode |
- ((static_cast<int32_t>(sd) & 1)*B22) |
- ((static_cast<int32_t>(sd) >> 1)*B12) |
- ((static_cast<int32_t>(dm) >> 4)*B5) |
- (static_cast<int32_t>(dm) & 0xf);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::EmitVFPds(Condition cond, int32_t opcode,
- DRegister dd, SRegister sm) {
- CHECK_NE(dd, kNoDRegister);
- CHECK_NE(sm, kNoSRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 | B26 | B25 | B11 | B9 | opcode |
- ((static_cast<int32_t>(dd) >> 4)*B22) |
- ((static_cast<int32_t>(dd) & 0xf)*B12) |
- ((static_cast<int32_t>(sm) & 1)*B5) |
- (static_cast<int32_t>(sm) >> 1);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm,
- Condition cond, SetCc set_cc) {
- CHECK_LE(shift_imm, 31u);
- mov(rd, ShifterOperand(rm, LSL, shift_imm), cond, set_cc);
-}
-
-
-void Arm32Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
- Condition cond, SetCc set_cc) {
- CHECK(1u <= shift_imm && shift_imm <= 32u);
- if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
- mov(rd, ShifterOperand(rm, LSR, shift_imm), cond, set_cc);
-}
-
-
-void Arm32Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
- Condition cond, SetCc set_cc) {
- CHECK(1u <= shift_imm && shift_imm <= 32u);
- if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax.
- mov(rd, ShifterOperand(rm, ASR, shift_imm), cond, set_cc);
-}
-
-
-void Arm32Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
- Condition cond, SetCc set_cc) {
- CHECK(1u <= shift_imm && shift_imm <= 31u);
- mov(rd, ShifterOperand(rm, ROR, shift_imm), cond, set_cc);
-}
-
-void Arm32Assembler::Rrx(Register rd, Register rm, Condition cond, SetCc set_cc) {
- mov(rd, ShifterOperand(rm, ROR, 0), cond, set_cc);
-}
-
-
-void Arm32Assembler::Lsl(Register rd, Register rm, Register rn,
- Condition cond, SetCc set_cc) {
- mov(rd, ShifterOperand(rm, LSL, rn), cond, set_cc);
-}
-
-
-void Arm32Assembler::Lsr(Register rd, Register rm, Register rn,
- Condition cond, SetCc set_cc) {
- mov(rd, ShifterOperand(rm, LSR, rn), cond, set_cc);
-}
-
-
-void Arm32Assembler::Asr(Register rd, Register rm, Register rn,
- Condition cond, SetCc set_cc) {
- mov(rd, ShifterOperand(rm, ASR, rn), cond, set_cc);
-}
-
-
-void Arm32Assembler::Ror(Register rd, Register rm, Register rn,
- Condition cond, SetCc set_cc) {
- mov(rd, ShifterOperand(rm, ROR, rn), cond, set_cc);
-}
-
-void Arm32Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 | B26 | B25 | B23 | B22 | B21 | B20 | B16 |
- (static_cast<int32_t>(PC)*B12) |
- B11 | B9 | B4;
- Emit(encoding);
-}
-
-void Arm32Assembler::vcntd(DRegister dd, DRegister dm) {
- uint32_t encoding = (B31 | B30 | B29 | B28 | B25 | B24 | B23 | B21 | B20) |
- ((static_cast<int32_t>(dd) >> 4) * B22) |
- ((static_cast<uint32_t>(dd) & 0xf) * B12) |
- (B10 | B8) |
- ((static_cast<int32_t>(dm) >> 4) * B5) |
- (static_cast<uint32_t>(dm) & 0xf);
-
- Emit(encoding);
-}
-
-void Arm32Assembler::vpaddld(DRegister dd, DRegister dm, int32_t size, bool is_unsigned) {
- CHECK(size == 8 || size == 16 || size == 32) << size;
- uint32_t encoding = (B31 | B30 | B29 | B28 | B25 | B24 | B23 | B21 | B20) |
- ((static_cast<uint32_t>(size >> 4) & 0x3) * B18) |
- ((static_cast<int32_t>(dd) >> 4) * B22) |
- ((static_cast<uint32_t>(dd) & 0xf) * B12) |
- (B9) |
- (is_unsigned ? B7 : 0) |
- ((static_cast<int32_t>(dm) >> 4) * B5) |
- (static_cast<uint32_t>(dm) & 0xf);
-
- Emit(encoding);
-}
-
-
-void Arm32Assembler::svc(uint32_t imm24) {
- CHECK(IsUint<24>(imm24)) << imm24;
- int32_t encoding = (AL << kConditionShift) | B27 | B26 | B25 | B24 | imm24;
- Emit(encoding);
-}
-
-
-void Arm32Assembler::bkpt(uint16_t imm16) {
- int32_t encoding = (AL << kConditionShift) | B24 | B21 |
- ((imm16 >> 4) << 8) | B6 | B5 | B4 | (imm16 & 0xf);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::blx(Register rm, Condition cond) {
- CHECK_NE(rm, kNoRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B24 | B21 | (0xfff << 8) | B5 | B4 |
- (static_cast<int32_t>(rm) << kRmShift);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::bx(Register rm, Condition cond) {
- CHECK_NE(rm, kNoRegister);
- CHECK_NE(cond, kNoCondition);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B24 | B21 | (0xfff << 8) | B4 |
- (static_cast<int32_t>(rm) << kRmShift);
- Emit(encoding);
-}
-
-
-void Arm32Assembler::Push(Register rd, Condition cond) {
- str(rd, Address(SP, -kRegisterSize, Address::PreIndex), cond);
-}
-
-
-void Arm32Assembler::Pop(Register rd, Condition cond) {
- ldr(rd, Address(SP, kRegisterSize, Address::PostIndex), cond);
-}
-
-
-void Arm32Assembler::PushList(RegList regs, Condition cond) {
- stm(DB_W, SP, regs, cond);
-}
-
-
-void Arm32Assembler::PopList(RegList regs, Condition cond) {
- ldm(IA_W, SP, regs, cond);
-}
-
-
-void Arm32Assembler::Mov(Register rd, Register rm, Condition cond) {
- if (rd != rm) {
- mov(rd, ShifterOperand(rm), cond);
- }
-}
-
-
-void Arm32Assembler::Bind(Label* label) {
- CHECK(!label->IsBound());
- int bound_pc = buffer_.Size();
- while (label->IsLinked()) {
- int32_t position = label->Position();
- int32_t next = buffer_.Load<int32_t>(position);
- int32_t encoded = Arm32Assembler::EncodeBranchOffset(bound_pc - position, next);
- buffer_.Store<int32_t>(position, encoded);
- label->position_ = Arm32Assembler::DecodeBranchOffset(next);
- }
- label->BindTo(bound_pc);
-}
-
-
-int32_t Arm32Assembler::EncodeBranchOffset(int offset, int32_t inst) {
- // The offset is off by 8 due to the way the ARM CPUs read PC.
- offset -= 8;
- CHECK_ALIGNED(offset, 4);
- CHECK(IsInt(POPCOUNT(kBranchOffsetMask), offset)) << offset;
-
- // Properly preserve only the bits supported in the instruction.
- offset >>= 2;
- offset &= kBranchOffsetMask;
- return (inst & ~kBranchOffsetMask) | offset;
-}
-
-
-int Arm32Assembler::DecodeBranchOffset(int32_t inst) {
- // Sign-extend, left-shift by 2, then add 8.
- return ((((inst & kBranchOffsetMask) << 8) >> 6) + 8);
-}
-
-
-uint32_t Arm32Assembler::GetAdjustedPosition(uint32_t old_position ATTRIBUTE_UNUSED) {
- LOG(FATAL) << "Unimplemented.";
- UNREACHABLE();
-}
-
-Literal* Arm32Assembler::NewLiteral(size_t size ATTRIBUTE_UNUSED,
- const uint8_t* data ATTRIBUTE_UNUSED) {
- LOG(FATAL) << "Unimplemented.";
- UNREACHABLE();
-}
-
-void Arm32Assembler::LoadLiteral(Register rt ATTRIBUTE_UNUSED,
- Literal* literal ATTRIBUTE_UNUSED) {
- LOG(FATAL) << "Unimplemented.";
- UNREACHABLE();
-}
-
-void Arm32Assembler::LoadLiteral(Register rt ATTRIBUTE_UNUSED, Register rt2 ATTRIBUTE_UNUSED,
- Literal* literal ATTRIBUTE_UNUSED) {
- LOG(FATAL) << "Unimplemented.";
- UNREACHABLE();
-}
-
-void Arm32Assembler::LoadLiteral(SRegister sd ATTRIBUTE_UNUSED,
- Literal* literal ATTRIBUTE_UNUSED) {
- LOG(FATAL) << "Unimplemented.";
- UNREACHABLE();
-}
-
-void Arm32Assembler::LoadLiteral(DRegister dd ATTRIBUTE_UNUSED,
- Literal* literal ATTRIBUTE_UNUSED) {
- LOG(FATAL) << "Unimplemented.";
- UNREACHABLE();
-}
-
-
-void Arm32Assembler::AddConstant(Register rd, Register rn, int32_t value,
- Condition cond, SetCc set_cc) {
- if (value == 0 && set_cc != kCcSet) {
- if (rd != rn) {
- mov(rd, ShifterOperand(rn), cond, set_cc);
- }
- return;
- }
- // We prefer to select the shorter code sequence rather than selecting add for
- // positive values and sub for negatives ones, which would slightly improve
- // the readability of generated code for some constants.
- ShifterOperand shifter_op;
- if (ShifterOperandCanHoldArm32(value, &shifter_op)) {
- add(rd, rn, shifter_op, cond, set_cc);
- } else if (ShifterOperandCanHoldArm32(-value, &shifter_op)) {
- sub(rd, rn, shifter_op, cond, set_cc);
- } else {
- CHECK(rn != IP);
- if (ShifterOperandCanHoldArm32(~value, &shifter_op)) {
- mvn(IP, shifter_op, cond, kCcKeep);
- add(rd, rn, ShifterOperand(IP), cond, set_cc);
- } else if (ShifterOperandCanHoldArm32(~(-value), &shifter_op)) {
- mvn(IP, shifter_op, cond, kCcKeep);
- sub(rd, rn, ShifterOperand(IP), cond, set_cc);
- } else {
- movw(IP, Low16Bits(value), cond);
- uint16_t value_high = High16Bits(value);
- if (value_high != 0) {
- movt(IP, value_high, cond);
- }
- add(rd, rn, ShifterOperand(IP), cond, set_cc);
- }
- }
-}
-
-void Arm32Assembler::CmpConstant(Register rn, int32_t value, Condition cond) {
- ShifterOperand shifter_op;
- if (ShifterOperandCanHoldArm32(value, &shifter_op)) {
- cmp(rn, shifter_op, cond);
- } else if (ShifterOperandCanHoldArm32(~value, &shifter_op)) {
- cmn(rn, shifter_op, cond);
- } else {
- movw(IP, Low16Bits(value), cond);
- uint16_t value_high = High16Bits(value);
- if (value_high != 0) {
- movt(IP, value_high, cond);
- }
- cmp(rn, ShifterOperand(IP), cond);
- }
-}
-
-void Arm32Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
- ShifterOperand shifter_op;
- if (ShifterOperandCanHoldArm32(value, &shifter_op)) {
- mov(rd, shifter_op, cond);
- } else if (ShifterOperandCanHoldArm32(~value, &shifter_op)) {
- mvn(rd, shifter_op, cond);
- } else {
- movw(rd, Low16Bits(value), cond);
- uint16_t value_high = High16Bits(value);
- if (value_high != 0) {
- movt(rd, value_high, cond);
- }
- }
-}
-
-void Arm32Assembler::LoadDImmediate(DRegister dd, double value, Condition cond) {
- if (!vmovd(dd, value, cond)) {
- uint64_t int_value = bit_cast<uint64_t, double>(value);
- if (int_value == bit_cast<uint64_t, double>(0.0)) {
- // 0.0 is quite common, so we special case it by loading
- // 2.0 in `dd` and then subtracting it.
- bool success = vmovd(dd, 2.0, cond);
- CHECK(success);
- vsubd(dd, dd, dd, cond);
- } else {
- if (dd < 16) {
- // Note: Depending on the particular CPU, this may cause register
- // forwarding hazard, negatively impacting the performance.
- SRegister low = static_cast<SRegister>(dd << 1);
- SRegister high = static_cast<SRegister>(low + 1);
- LoadSImmediate(low, bit_cast<float, uint32_t>(Low32Bits(int_value)), cond);
- if (High32Bits(int_value) == Low32Bits(int_value)) {
- vmovs(high, low);
- } else {
- LoadSImmediate(high, bit_cast<float, uint32_t>(High32Bits(int_value)), cond);
- }
- } else {
- LOG(FATAL) << "Unimplemented loading of double into a D register "
- << "that cannot be split into two S registers";
- }
- }
- }
-}
-
-// Implementation note: this method must emit at most one instruction when
-// Address::CanHoldLoadOffsetArm.
-void Arm32Assembler::LoadFromOffset(LoadOperandType type,
- Register reg,
- Register base,
- int32_t offset,
- Condition cond) {
- if (!Address::CanHoldLoadOffsetArm(type, offset)) {
- CHECK(base != IP);
- LoadImmediate(IP, offset, cond);
- add(IP, IP, ShifterOperand(base), cond);
- base = IP;
- offset = 0;
- }
- CHECK(Address::CanHoldLoadOffsetArm(type, offset));
- switch (type) {
- case kLoadSignedByte:
- ldrsb(reg, Address(base, offset), cond);
- break;
- case kLoadUnsignedByte:
- ldrb(reg, Address(base, offset), cond);
- break;
- case kLoadSignedHalfword:
- ldrsh(reg, Address(base, offset), cond);
- break;
- case kLoadUnsignedHalfword:
- ldrh(reg, Address(base, offset), cond);
- break;
- case kLoadWord:
- ldr(reg, Address(base, offset), cond);
- break;
- case kLoadWordPair:
- ldrd(reg, Address(base, offset), cond);
- break;
- default:
- LOG(FATAL) << "UNREACHABLE";
- UNREACHABLE();
- }
-}
-
-
-// Implementation note: this method must emit at most one instruction when
-// Address::CanHoldLoadOffsetArm, as expected by JIT::GuardedLoadFromOffset.
-void Arm32Assembler::LoadSFromOffset(SRegister reg,
- Register base,
- int32_t offset,
- Condition cond) {
- if (!Address::CanHoldLoadOffsetArm(kLoadSWord, offset)) {
- CHECK_NE(base, IP);
- LoadImmediate(IP, offset, cond);
- add(IP, IP, ShifterOperand(base), cond);
- base = IP;
- offset = 0;
- }
- CHECK(Address::CanHoldLoadOffsetArm(kLoadSWord, offset));
- vldrs(reg, Address(base, offset), cond);
-}
-
-
-// Implementation note: this method must emit at most one instruction when
-// Address::CanHoldLoadOffsetArm, as expected by JIT::GuardedLoadFromOffset.
-void Arm32Assembler::LoadDFromOffset(DRegister reg,
- Register base,
- int32_t offset,
- Condition cond) {
- if (!Address::CanHoldLoadOffsetArm(kLoadDWord, offset)) {
- CHECK_NE(base, IP);
- LoadImmediate(IP, offset, cond);
- add(IP, IP, ShifterOperand(base), cond);
- base = IP;
- offset = 0;
- }
- CHECK(Address::CanHoldLoadOffsetArm(kLoadDWord, offset));
- vldrd(reg, Address(base, offset), cond);
-}
-
-
-// Implementation note: this method must emit at most one instruction when
-// Address::CanHoldStoreOffsetArm.
-void Arm32Assembler::StoreToOffset(StoreOperandType type,
- Register reg,
- Register base,
- int32_t offset,
- Condition cond) {
- if (!Address::CanHoldStoreOffsetArm(type, offset)) {
- CHECK(reg != IP);
- CHECK(base != IP);
- LoadImmediate(IP, offset, cond);
- add(IP, IP, ShifterOperand(base), cond);
- base = IP;
- offset = 0;
- }
- CHECK(Address::CanHoldStoreOffsetArm(type, offset));
- switch (type) {
- case kStoreByte:
- strb(reg, Address(base, offset), cond);
- break;
- case kStoreHalfword:
- strh(reg, Address(base, offset), cond);
- break;
- case kStoreWord:
- str(reg, Address(base, offset), cond);
- break;
- case kStoreWordPair:
- strd(reg, Address(base, offset), cond);
- break;
- default:
- LOG(FATAL) << "UNREACHABLE";
- UNREACHABLE();
- }
-}
-
-
-// Implementation note: this method must emit at most one instruction when
-// Address::CanHoldStoreOffsetArm, as expected by JIT::GuardedStoreToOffset.
-void Arm32Assembler::StoreSToOffset(SRegister reg,
- Register base,
- int32_t offset,
- Condition cond) {
- if (!Address::CanHoldStoreOffsetArm(kStoreSWord, offset)) {
- CHECK_NE(base, IP);
- LoadImmediate(IP, offset, cond);
- add(IP, IP, ShifterOperand(base), cond);
- base = IP;
- offset = 0;
- }
- CHECK(Address::CanHoldStoreOffsetArm(kStoreSWord, offset));
- vstrs(reg, Address(base, offset), cond);
-}
-
-
-// Implementation note: this method must emit at most one instruction when
-// Address::CanHoldStoreOffsetArm, as expected by JIT::GuardedStoreSToOffset.
-void Arm32Assembler::StoreDToOffset(DRegister reg,
- Register base,
- int32_t offset,
- Condition cond) {
- if (!Address::CanHoldStoreOffsetArm(kStoreDWord, offset)) {
- CHECK_NE(base, IP);
- LoadImmediate(IP, offset, cond);
- add(IP, IP, ShifterOperand(base), cond);
- base = IP;
- offset = 0;
- }
- CHECK(Address::CanHoldStoreOffsetArm(kStoreDWord, offset));
- vstrd(reg, Address(base, offset), cond);
-}
-
-
-void Arm32Assembler::dmb(DmbOptions flavor) {
- int32_t encoding = 0xf57ff05f; // dmb
- Emit(encoding | flavor);
-}
-
-
-void Arm32Assembler::cbz(Register rn ATTRIBUTE_UNUSED, Label* target ATTRIBUTE_UNUSED) {
- LOG(FATAL) << "cbz is not supported on ARM32";
-}
-
-
-void Arm32Assembler::cbnz(Register rn ATTRIBUTE_UNUSED, Label* target ATTRIBUTE_UNUSED) {
- LOG(FATAL) << "cbnz is not supported on ARM32";
-}
-
-
-void Arm32Assembler::CompareAndBranchIfZero(Register r, Label* label) {
- cmp(r, ShifterOperand(0));
- b(label, EQ);
-}
-
-
-void Arm32Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
- cmp(r, ShifterOperand(0));
- b(label, NE);
-}
-
-JumpTable* Arm32Assembler::CreateJumpTable(std::vector<Label*>&& labels ATTRIBUTE_UNUSED,
- Register base_reg ATTRIBUTE_UNUSED) {
- LOG(FATAL) << "CreateJumpTable is not supported on ARM32";
- UNREACHABLE();
-}
-
-void Arm32Assembler::EmitJumpTableDispatch(JumpTable* jump_table ATTRIBUTE_UNUSED,
- Register displacement_reg ATTRIBUTE_UNUSED) {
- LOG(FATAL) << "EmitJumpTableDispatch is not supported on ARM32";
- UNREACHABLE();
-}
-
-void Arm32Assembler::FinalizeCode() {
- ArmAssembler::FinalizeCode();
- // Currently the arm32 assembler does not support fixups, and thus no tracking. We must not call
- // FinalizeTrackedLabels(), which would lead to an abort.
-}
-
-} // namespace arm
-} // namespace art
diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h
deleted file mode 100644
index 0cb6b17..0000000
--- a/compiler/utils/arm/assembler_arm32.h
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM32_H_
-#define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM32_H_
-
-#include <vector>
-
-#include "base/logging.h"
-#include "constants_arm.h"
-#include "utils/arm/managed_register_arm.h"
-#include "utils/arm/assembler_arm.h"
-#include "offsets.h"
-
-namespace art {
-namespace arm {
-
-class Arm32Assembler FINAL : public ArmAssembler {
- public:
- explicit Arm32Assembler(ArenaAllocator* arena) : ArmAssembler(arena) {}
- virtual ~Arm32Assembler() {}
-
- bool IsThumb() const OVERRIDE {
- return false;
- }
-
- // Data-processing instructions.
- virtual void and_(Register rd, Register rn, const ShifterOperand& so,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
-
- virtual void eor(Register rd, Register rn, const ShifterOperand& so,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
-
- virtual void sub(Register rd, Register rn, const ShifterOperand& so,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
-
- virtual void rsb(Register rd, Register rn, const ShifterOperand& so,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
-
- virtual void add(Register rd, Register rn, const ShifterOperand& so,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
-
- virtual void adc(Register rd, Register rn, const ShifterOperand& so,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
-
- virtual void sbc(Register rd, Register rn, const ShifterOperand& so,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
-
- virtual void rsc(Register rd, Register rn, const ShifterOperand& so,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
-
- void tst(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE;
-
- void teq(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE;
-
- void cmp(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE;
-
- void cmn(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE;
-
- virtual void orr(Register rd, Register rn, const ShifterOperand& so,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
-
- virtual void orn(Register rd, Register rn, const ShifterOperand& so,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
-
- virtual void mov(Register rd, const ShifterOperand& so,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
-
- virtual void bic(Register rd, Register rn, const ShifterOperand& so,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
-
- virtual void mvn(Register rd, const ShifterOperand& so,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
-
- // Miscellaneous data-processing instructions.
- void clz(Register rd, Register rm, Condition cond = AL) OVERRIDE;
- void movw(Register rd, uint16_t imm16, Condition cond = AL) OVERRIDE;
- void movt(Register rd, uint16_t imm16, Condition cond = AL) OVERRIDE;
- void rbit(Register rd, Register rm, Condition cond = AL) OVERRIDE;
- void rev(Register rd, Register rm, Condition cond = AL) OVERRIDE;
- void rev16(Register rd, Register rm, Condition cond = AL) OVERRIDE;
- void revsh(Register rd, Register rm, Condition cond = AL) OVERRIDE;
-
- // Multiply instructions.
- void mul(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE;
- void mla(Register rd, Register rn, Register rm, Register ra,
- Condition cond = AL) OVERRIDE;
- void mls(Register rd, Register rn, Register rm, Register ra,
- Condition cond = AL) OVERRIDE;
- void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
- Condition cond = AL) OVERRIDE;
- void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
- Condition cond = AL) OVERRIDE;
-
- void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE;
- void udiv(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE;
-
- // Bit field extract instructions.
- void sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond = AL) OVERRIDE;
- void ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond = AL) OVERRIDE;
-
- // Load/store instructions.
- void ldr(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
- void str(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
-
- void ldrb(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
- void strb(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
-
- void ldrh(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
- void strh(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
-
- void ldrsb(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
- void ldrsh(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
-
- void ldrd(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
- void strd(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
-
- void ldm(BlockAddressMode am, Register base,
- RegList regs, Condition cond = AL) OVERRIDE;
- void stm(BlockAddressMode am, Register base,
- RegList regs, Condition cond = AL) OVERRIDE;
-
- void ldrex(Register rd, Register rn, Condition cond = AL) OVERRIDE;
- void strex(Register rd, Register rt, Register rn, Condition cond = AL) OVERRIDE;
- void ldrexd(Register rt, Register rt2, Register rn, Condition cond = AL) OVERRIDE;
- void strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond = AL) OVERRIDE;
-
- // Miscellaneous instructions.
- void clrex(Condition cond = AL) OVERRIDE;
- void nop(Condition cond = AL) OVERRIDE;
-
- // Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0.
- void bkpt(uint16_t imm16) OVERRIDE;
- void svc(uint32_t imm24) OVERRIDE;
-
- void cbz(Register rn, Label* target) OVERRIDE;
- void cbnz(Register rn, Label* target) OVERRIDE;
-
- // Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles).
- void vmovsr(SRegister sn, Register rt, Condition cond = AL) OVERRIDE;
- void vmovrs(Register rt, SRegister sn, Condition cond = AL) OVERRIDE;
- void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL) OVERRIDE;
- void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL) OVERRIDE;
- void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL) OVERRIDE;
- void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL) OVERRIDE;
- void vmovs(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
- void vmovd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE;
-
- // Returns false if the immediate cannot be encoded.
- bool vmovs(SRegister sd, float s_imm, Condition cond = AL) OVERRIDE;
- bool vmovd(DRegister dd, double d_imm, Condition cond = AL) OVERRIDE;
-
- void vldrs(SRegister sd, const Address& ad, Condition cond = AL) OVERRIDE;
- void vstrs(SRegister sd, const Address& ad, Condition cond = AL) OVERRIDE;
- void vldrd(DRegister dd, const Address& ad, Condition cond = AL) OVERRIDE;
- void vstrd(DRegister dd, const Address& ad, Condition cond = AL) OVERRIDE;
-
- void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE;
- void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE;
- void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE;
- void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE;
- void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE;
- void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE;
- void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE;
- void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE;
- void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE;
- void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE;
- void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE;
- void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE;
-
- void vabss(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
- void vabsd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE;
- void vnegs(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
- void vnegd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE;
- void vsqrts(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
- void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE;
-
- void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL) OVERRIDE;
- void vcvtds(DRegister dd, SRegister sm, Condition cond = AL) OVERRIDE;
- void vcvtis(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
- void vcvtid(SRegister sd, DRegister dm, Condition cond = AL) OVERRIDE;
- void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
- void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL) OVERRIDE;
- void vcvtus(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
- void vcvtud(SRegister sd, DRegister dm, Condition cond = AL) OVERRIDE;
- void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
- void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL) OVERRIDE;
-
- void vcmps(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
- void vcmpd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE;
- void vcmpsz(SRegister sd, Condition cond = AL) OVERRIDE;
- void vcmpdz(DRegister dd, Condition cond = AL) OVERRIDE;
- void vmstat(Condition cond = AL) OVERRIDE; // VMRS APSR_nzcv, FPSCR
-
- void vcntd(DRegister dd, DRegister dm) OVERRIDE;
- void vpaddld(DRegister dd, DRegister dm, int32_t size, bool is_unsigned) OVERRIDE;
-
- void vpushs(SRegister reg, int nregs, Condition cond = AL) OVERRIDE;
- void vpushd(DRegister reg, int nregs, Condition cond = AL) OVERRIDE;
- void vpops(SRegister reg, int nregs, Condition cond = AL) OVERRIDE;
- void vpopd(DRegister reg, int nregs, Condition cond = AL) OVERRIDE;
- void vldmiad(Register base_reg, DRegister reg, int nregs, Condition cond = AL) OVERRIDE;
- void vstmiad(Register base_reg, DRegister reg, int nregs, Condition cond = AL) OVERRIDE;
-
- // Branch instructions.
- void b(Label* label, Condition cond = AL) OVERRIDE;
- void bl(Label* label, Condition cond = AL) OVERRIDE;
- void blx(Register rm, Condition cond = AL) OVERRIDE;
- void bx(Register rm, Condition cond = AL) OVERRIDE;
- virtual void Lsl(Register rd, Register rm, uint32_t shift_imm,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
- virtual void Lsr(Register rd, Register rm, uint32_t shift_imm,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
- virtual void Asr(Register rd, Register rm, uint32_t shift_imm,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
- virtual void Ror(Register rd, Register rm, uint32_t shift_imm,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
- virtual void Rrx(Register rd, Register rm,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
-
- virtual void Lsl(Register rd, Register rm, Register rn,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
- virtual void Lsr(Register rd, Register rm, Register rn,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
- virtual void Asr(Register rd, Register rm, Register rn,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
- virtual void Ror(Register rd, Register rm, Register rn,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
-
- void Push(Register rd, Condition cond = AL) OVERRIDE;
- void Pop(Register rd, Condition cond = AL) OVERRIDE;
-
- void PushList(RegList regs, Condition cond = AL) OVERRIDE;
- void PopList(RegList regs, Condition cond = AL) OVERRIDE;
-
- void Mov(Register rd, Register rm, Condition cond = AL) OVERRIDE;
-
- void CompareAndBranchIfZero(Register r, Label* label) OVERRIDE;
- void CompareAndBranchIfNonZero(Register r, Label* label) OVERRIDE;
-
- // Memory barriers.
- void dmb(DmbOptions flavor) OVERRIDE;
-
- // Get the final position of a label after local fixup based on the old position
- // recorded before FinalizeCode().
- uint32_t GetAdjustedPosition(uint32_t old_position) OVERRIDE;
-
- Literal* NewLiteral(size_t size, const uint8_t* data) OVERRIDE;
- void LoadLiteral(Register rt, Literal* literal) OVERRIDE;
- void LoadLiteral(Register rt, Register rt2, Literal* literal) OVERRIDE;
- void LoadLiteral(SRegister sd, Literal* literal) OVERRIDE;
- void LoadLiteral(DRegister dd, Literal* literal) OVERRIDE;
-
- // Add signed constant value to rd. May clobber IP.
- void AddConstant(Register rd, Register rn, int32_t value,
- Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
-
- void CmpConstant(Register rn, int32_t value, Condition cond = AL) OVERRIDE;
-
- // Load and Store. May clobber IP.
- void LoadImmediate(Register rd, int32_t value, Condition cond = AL) OVERRIDE;
- void LoadDImmediate(DRegister dd, double value, Condition cond = AL) OVERRIDE;
- void MarkExceptionHandler(Label* label) OVERRIDE;
- void LoadFromOffset(LoadOperandType type,
- Register reg,
- Register base,
- int32_t offset,
- Condition cond = AL) OVERRIDE;
- void StoreToOffset(StoreOperandType type,
- Register reg,
- Register base,
- int32_t offset,
- Condition cond = AL) OVERRIDE;
- void LoadSFromOffset(SRegister reg,
- Register base,
- int32_t offset,
- Condition cond = AL) OVERRIDE;
- void StoreSToOffset(SRegister reg,
- Register base,
- int32_t offset,
- Condition cond = AL) OVERRIDE;
- void LoadDFromOffset(DRegister reg,
- Register base,
- int32_t offset,
- Condition cond = AL) OVERRIDE;
- void StoreDToOffset(DRegister reg,
- Register base,
- int32_t offset,
- Condition cond = AL) OVERRIDE;
-
- bool ShifterOperandCanHold(Register rd,
- Register rn,
- Opcode opcode,
- uint32_t immediate,
- SetCc set_cc,
- ShifterOperand* shifter_op) OVERRIDE;
- using ArmAssembler::ShifterOperandCanHold; // Don't hide the non-virtual override.
-
- bool ShifterOperandCanAlwaysHold(uint32_t immediate) OVERRIDE;
-
- static bool IsInstructionForExceptionHandling(uintptr_t pc);
-
- // Emit data (e.g. encoded instruction or immediate) to the
- // instruction stream.
- void Emit(int32_t value);
- void Bind(Label* label) OVERRIDE;
-
- JumpTable* CreateJumpTable(std::vector<Label*>&& labels, Register base_reg) OVERRIDE;
- void EmitJumpTableDispatch(JumpTable* jump_table, Register displacement_reg) OVERRIDE;
-
- void FinalizeCode() OVERRIDE;
-
- private:
- void EmitType01(Condition cond,
- int type,
- Opcode opcode,
- SetCc set_cc,
- Register rn,
- Register rd,
- const ShifterOperand& so);
-
- void EmitType5(Condition cond, int offset, bool link);
-
- void EmitMemOp(Condition cond,
- bool load,
- bool byte,
- Register rd,
- const Address& ad);
-
- void EmitMemOpAddressMode3(Condition cond,
- int32_t mode,
- Register rd,
- const Address& ad);
-
- void EmitMultiMemOp(Condition cond,
- BlockAddressMode am,
- bool load,
- Register base,
- RegList regs);
-
- void EmitShiftImmediate(Condition cond,
- Shift opcode,
- Register rd,
- Register rm,
- const ShifterOperand& so);
-
- void EmitShiftRegister(Condition cond,
- Shift opcode,
- Register rd,
- Register rm,
- const ShifterOperand& so);
-
- void EmitMulOp(Condition cond,
- int32_t opcode,
- Register rd,
- Register rn,
- Register rm,
- Register rs);
-
- void EmitVFPsss(Condition cond,
- int32_t opcode,
- SRegister sd,
- SRegister sn,
- SRegister sm);
-
- void EmitVFPddd(Condition cond,
- int32_t opcode,
- DRegister dd,
- DRegister dn,
- DRegister dm);
-
- void EmitVFPsd(Condition cond,
- int32_t opcode,
- SRegister sd,
- DRegister dm);
-
- void EmitVFPds(Condition cond,
- int32_t opcode,
- DRegister dd,
- SRegister sm);
-
- void EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond);
-
- void EmitMiscellaneous(Condition cond, uint8_t op1, uint8_t op2,
- uint32_t a_part, uint32_t rest);
- void EmitReverseBytes(Register rd, Register rm, Condition cond,
- uint8_t op1, uint8_t op2);
-
- void EmitBranch(Condition cond, Label* label, bool link);
- static int32_t EncodeBranchOffset(int offset, int32_t inst);
- static int DecodeBranchOffset(int32_t inst);
- bool ShifterOperandCanHoldArm32(uint32_t immediate, ShifterOperand* shifter_op);
-};
-
-} // namespace arm
-} // namespace art
-
-#endif // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM32_H_
diff --git a/compiler/utils/arm/assembler_arm32_test.cc b/compiler/utils/arm/assembler_arm32_test.cc
deleted file mode 100644
index b214062..0000000
--- a/compiler/utils/arm/assembler_arm32_test.cc
+++ /dev/null
@@ -1,941 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "assembler_arm32.h"
-
-#include <functional>
-#include <type_traits>
-
-#include "base/macros.h"
-#include "base/stl_util.h"
-#include "utils/arm/assembler_arm_test.h"
-
-namespace art {
-
-using std::placeholders::_1;
-using std::placeholders::_2;
-using std::placeholders::_3;
-using std::placeholders::_4;
-using std::placeholders::_5;
-
-// To speed up tests, don't use all register combinations.
-static constexpr bool kUseSparseRegisterList = true;
-
-// To speed up tests, don't use all condition codes.
-static constexpr bool kUseSparseConditionList = true;
-
-// To speed up tests, don't use all shift immediates.
-static constexpr bool kUseSparseShiftImmediates = true;
-
-class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler,
- arm::Register, arm::SRegister,
- uint32_t, arm::ShifterOperand, arm::Condition,
- arm::SetCc> {
- protected:
- std::string GetArchitectureString() OVERRIDE {
- return "arm";
- }
-
- std::string GetAssemblerParameters() OVERRIDE {
- // Arm-v7a, cortex-a15 (means we have sdiv).
- return " -march=armv7-a -mcpu=cortex-a15 -mfpu=neon";
- }
-
- const char* GetAssemblyHeader() OVERRIDE {
- return kArm32AssemblyHeader;
- }
-
- std::string GetDisassembleParameters() OVERRIDE {
- return " -D -bbinary -marm --no-show-raw-insn";
- }
-
- void SetUpHelpers() OVERRIDE {
- if (registers_.size() == 0) {
- if (kUseSparseRegisterList) {
- registers_.insert(end(registers_),
- { // NOLINT(whitespace/braces)
- new arm::Register(arm::R0),
- new arm::Register(arm::R1),
- new arm::Register(arm::R4),
- new arm::Register(arm::R8),
- new arm::Register(arm::R11),
- new arm::Register(arm::R12),
- new arm::Register(arm::R13),
- new arm::Register(arm::R14),
- new arm::Register(arm::R15)
- });
- } else {
- registers_.insert(end(registers_),
- { // NOLINT(whitespace/braces)
- new arm::Register(arm::R0),
- new arm::Register(arm::R1),
- new arm::Register(arm::R2),
- new arm::Register(arm::R3),
- new arm::Register(arm::R4),
- new arm::Register(arm::R5),
- new arm::Register(arm::R6),
- new arm::Register(arm::R7),
- new arm::Register(arm::R8),
- new arm::Register(arm::R9),
- new arm::Register(arm::R10),
- new arm::Register(arm::R11),
- new arm::Register(arm::R12),
- new arm::Register(arm::R13),
- new arm::Register(arm::R14),
- new arm::Register(arm::R15)
- });
- }
- }
-
- if (!kUseSparseConditionList) {
- conditions_.push_back(arm::Condition::EQ);
- conditions_.push_back(arm::Condition::NE);
- conditions_.push_back(arm::Condition::CS);
- conditions_.push_back(arm::Condition::CC);
- conditions_.push_back(arm::Condition::MI);
- conditions_.push_back(arm::Condition::PL);
- conditions_.push_back(arm::Condition::VS);
- conditions_.push_back(arm::Condition::VC);
- conditions_.push_back(arm::Condition::HI);
- conditions_.push_back(arm::Condition::LS);
- conditions_.push_back(arm::Condition::GE);
- conditions_.push_back(arm::Condition::LT);
- conditions_.push_back(arm::Condition::GT);
- conditions_.push_back(arm::Condition::LE);
- conditions_.push_back(arm::Condition::AL);
- } else {
- conditions_.push_back(arm::Condition::EQ);
- conditions_.push_back(arm::Condition::NE);
- conditions_.push_back(arm::Condition::CC);
- conditions_.push_back(arm::Condition::VC);
- conditions_.push_back(arm::Condition::HI);
- conditions_.push_back(arm::Condition::LT);
- conditions_.push_back(arm::Condition::AL);
- }
-
- set_ccs_.push_back(arm::kCcDontCare);
- set_ccs_.push_back(arm::kCcSet);
- set_ccs_.push_back(arm::kCcKeep);
-
- shifter_operands_.push_back(arm::ShifterOperand(0));
- shifter_operands_.push_back(arm::ShifterOperand(1));
- shifter_operands_.push_back(arm::ShifterOperand(2));
- shifter_operands_.push_back(arm::ShifterOperand(3));
- shifter_operands_.push_back(arm::ShifterOperand(4));
- shifter_operands_.push_back(arm::ShifterOperand(5));
- shifter_operands_.push_back(arm::ShifterOperand(127));
- shifter_operands_.push_back(arm::ShifterOperand(128));
- shifter_operands_.push_back(arm::ShifterOperand(254));
- shifter_operands_.push_back(arm::ShifterOperand(255));
-
- if (!kUseSparseRegisterList) {
- shifter_operands_.push_back(arm::ShifterOperand(arm::R0));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R1));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R2));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R3));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R4));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R5));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R6));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R7));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R8));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R9));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R10));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R11));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R12));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R13));
- } else {
- shifter_operands_.push_back(arm::ShifterOperand(arm::R0));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R1));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R4));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R8));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R11));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R12));
- shifter_operands_.push_back(arm::ShifterOperand(arm::R13));
- }
-
- std::vector<arm::Shift> shifts {
- arm::Shift::LSL, arm::Shift::LSR, arm::Shift::ASR, arm::Shift::ROR, arm::Shift::RRX
- };
-
- // ShifterOperands of form "reg shift-type imm."
- for (arm::Shift shift : shifts) {
- for (arm::Register* reg : registers_) { // Note: this will pick up the sparse set.
- if (*reg == arm::R15) { // Skip PC.
- continue;
- }
- if (shift != arm::Shift::RRX) {
- if (!kUseSparseShiftImmediates) {
- for (uint32_t imm = 1; imm < 32; ++imm) {
- shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, imm));
- }
- } else {
- shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 1));
- shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 2));
- shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 3));
- shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 7));
- shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 15));
- shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 16));
- shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 30));
- shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 31));
- }
- } else {
- // RRX doesn't have an immediate.
- shifter_operands_.push_back(arm::ShifterOperand(*reg, shift, 0));
- }
- }
- }
- }
-
- std::vector<arm::ShifterOperand> CreateRegisterShifts(std::vector<arm::Register*>& base_regs,
- int32_t shift_min, int32_t shift_max) {
- std::vector<arm::ShifterOperand> res;
- static constexpr arm::Shift kShifts[] = { arm::Shift::LSL, arm::Shift::LSR, arm::Shift::ASR,
- arm::Shift::ROR };
-
- for (arm::Shift shift : kShifts) {
- for (arm::Register* reg : base_regs) {
- // Take the min, the max, and three values in between.
- res.push_back(arm::ShifterOperand(*reg, shift, shift_min));
- if (shift_min != shift_max) {
- res.push_back(arm::ShifterOperand(*reg, shift, shift_max));
- int32_t middle = (shift_min + shift_max) / 2;
- res.push_back(arm::ShifterOperand(*reg, shift, middle));
- res.push_back(arm::ShifterOperand(*reg, shift, middle - 1));
- res.push_back(arm::ShifterOperand(*reg, shift, middle + 1));
- }
- }
- }
-
- return res;
- }
-
- void TearDown() OVERRIDE {
- AssemblerArmTest::TearDown();
- STLDeleteElements(®isters_);
- }
-
- std::vector<arm::Register*> GetRegisters() OVERRIDE {
- return registers_;
- }
-
- uint32_t CreateImmediate(int64_t imm_value) OVERRIDE {
- return imm_value;
- }
-
- std::vector<arm::Condition>& GetConditions() OVERRIDE {
- return conditions_;
- }
-
- std::string GetConditionString(arm::Condition c) OVERRIDE {
- std::ostringstream oss;
- oss << c;
- return oss.str();
- }
-
- std::vector<arm::SetCc>& GetSetCcs() OVERRIDE {
- return set_ccs_;
- }
-
- std::string GetSetCcString(arm::SetCc s) OVERRIDE {
- // For arm32, kCcDontCare defaults to not setting condition codes.
- return s == arm::kCcSet ? "s" : "";
- }
-
- arm::Register GetPCRegister() OVERRIDE {
- return arm::R15;
- }
-
- std::vector<arm::ShifterOperand>& GetShiftOperands() OVERRIDE {
- return shifter_operands_;
- }
-
- std::string GetShiftString(arm::ShifterOperand sop) OVERRIDE {
- std::ostringstream oss;
- if (sop.IsShift()) {
- // Not a rotate...
- if (sop.GetShift() == arm::Shift::RRX) {
- oss << sop.GetRegister() << ", " << sop.GetShift();
- } else {
- oss << sop.GetRegister() << ", " << sop.GetShift() << " #" << sop.GetImmediate();
- }
- } else if (sop.IsRegister()) {
- oss << sop.GetRegister();
- } else {
- CHECK(sop.IsImmediate());
- oss << "#" << sop.GetImmediate();
- }
- return oss.str();
- }
-
- static const char* GetRegTokenFromDepth(int depth) {
- switch (depth) {
- case 0:
- return Base::REG1_TOKEN;
- case 1:
- return Base::REG2_TOKEN;
- case 2:
- return Base::REG3_TOKEN;
- case 3:
- return REG4_TOKEN;
- default:
- LOG(FATAL) << "Depth problem.";
- UNREACHABLE();
- }
- }
-
- void ExecuteAndPrint(std::function<void()> f, std::string fmt, std::ostringstream& oss) {
- if (first_) {
- first_ = false;
- } else {
- oss << "\n";
- }
- oss << fmt;
-
- f();
- }
-
- // NOTE: Only support simple test like "aaa=bbb"
- bool EvalFilterString(std::string filter) {
- if (filter.compare("") == 0) {
- return false;
- }
-
- size_t equal_sign_index = filter.find('=');
- if (equal_sign_index == std::string::npos) {
- EXPECT_TRUE(false) << "Unsupported filter string.";
- }
-
- std::string lhs = filter.substr(0, equal_sign_index);
- std::string rhs = filter.substr(equal_sign_index + 1, std::string::npos);
- return lhs.compare(rhs) == 0;
- }
-
- void TemplateHelper(std::function<void(arm::Register)> f, int depth ATTRIBUTE_UNUSED,
- bool without_pc, std::string fmt, std::string filter,
- std::ostringstream& oss) {
- std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
- for (auto reg : registers) {
- std::string after_reg = fmt;
- std::string after_reg_filter = filter;
-
- std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
- size_t reg_index;
- const char* reg_token = GetRegTokenFromDepth(depth);
-
- while ((reg_index = after_reg.find(reg_token)) != std::string::npos) {
- after_reg.replace(reg_index, strlen(reg_token), reg_string);
- }
-
- while ((reg_index = after_reg_filter.find(reg_token)) != std::string::npos) {
- after_reg_filter.replace(reg_index, strlen(reg_token), reg_string);
- }
- if (EvalFilterString(after_reg_filter)) {
- continue;
- }
-
- ExecuteAndPrint([&] () { f(*reg); }, after_reg, oss);
- }
- }
-
- void TemplateHelper(std::function<void(const arm::ShifterOperand&)> f, int depth ATTRIBUTE_UNUSED,
- bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
- std::ostringstream& oss) {
- for (const arm::ShifterOperand& shift : GetShiftOperands()) {
- std::string after_shift = fmt;
- std::string after_shift_filter = filter;
-
- std::string shift_string = GetShiftString(shift);
- size_t shift_index;
- while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
- after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
- }
-
- while ((shift_index = after_shift_filter.find(SHIFT_TOKEN)) != std::string::npos) {
- after_shift_filter.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
- }
- if (EvalFilterString(after_shift_filter)) {
- continue;
- }
-
- ExecuteAndPrint([&] () { f(shift); }, after_shift, oss);
- }
- }
-
- void TemplateHelper(std::function<void(arm::Condition)> f, int depth ATTRIBUTE_UNUSED,
- bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
- std::ostringstream& oss) {
- for (arm::Condition c : GetConditions()) {
- std::string after_cond = fmt;
- std::string after_cond_filter = filter;
-
- size_t cond_index = after_cond.find(COND_TOKEN);
- if (cond_index != std::string::npos) {
- after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
- }
-
- cond_index = after_cond_filter.find(COND_TOKEN);
- if (cond_index != std::string::npos) {
- after_cond_filter.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
- }
- if (EvalFilterString(after_cond_filter)) {
- continue;
- }
-
- ExecuteAndPrint([&] () { f(c); }, after_cond, oss);
- }
- }
-
- void TemplateHelper(std::function<void(arm::SetCc)> f, int depth ATTRIBUTE_UNUSED,
- bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
- std::ostringstream& oss) {
- for (arm::SetCc s : GetSetCcs()) {
- std::string after_cond = fmt;
- std::string after_cond_filter = filter;
-
- size_t cond_index = after_cond.find(SET_CC_TOKEN);
- if (cond_index != std::string::npos) {
- after_cond.replace(cond_index, ConstexprStrLen(SET_CC_TOKEN), GetSetCcString(s));
- }
-
- cond_index = after_cond_filter.find(SET_CC_TOKEN);
- if (cond_index != std::string::npos) {
- after_cond_filter.replace(cond_index, ConstexprStrLen(SET_CC_TOKEN), GetSetCcString(s));
- }
- if (EvalFilterString(after_cond_filter)) {
- continue;
- }
-
- ExecuteAndPrint([&] () { f(s); }, after_cond, oss);
- }
- }
-
- template <typename... Args>
- void TemplateHelper(std::function<void(arm::Register, Args...)> f, int depth, bool without_pc,
- std::string fmt, std::string filter, std::ostringstream& oss) {
- std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
- for (auto reg : registers) {
- std::string after_reg = fmt;
- std::string after_reg_filter = filter;
-
- std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
- size_t reg_index;
- const char* reg_token = GetRegTokenFromDepth(depth);
-
- while ((reg_index = after_reg.find(reg_token)) != std::string::npos) {
- after_reg.replace(reg_index, strlen(reg_token), reg_string);
- }
-
- while ((reg_index = after_reg_filter.find(reg_token)) != std::string::npos) {
- after_reg_filter.replace(reg_index, strlen(reg_token), reg_string);
- }
- if (EvalFilterString(after_reg_filter)) {
- continue;
- }
-
- auto lambda = [&] (Args... args) { f(*reg, args...); }; // NOLINT [readability/braces] [4]
- TemplateHelper(std::function<void(Args...)>(lambda), depth + 1, without_pc,
- after_reg, after_reg_filter, oss);
- }
- }
-
- template <typename... Args>
- void TemplateHelper(std::function<void(const arm::ShifterOperand&, Args...)> f, int depth,
- bool without_pc, std::string fmt, std::string filter,
- std::ostringstream& oss) {
- for (const arm::ShifterOperand& shift : GetShiftOperands()) {
- std::string after_shift = fmt;
- std::string after_shift_filter = filter;
-
- std::string shift_string = GetShiftString(shift);
- size_t shift_index;
- while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) {
- after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
- }
-
- while ((shift_index = after_shift_filter.find(SHIFT_TOKEN)) != std::string::npos) {
- after_shift_filter.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
- }
- if (EvalFilterString(after_shift_filter)) {
- continue;
- }
-
- auto lambda = [&] (Args... args) { f(shift, args...); }; // NOLINT [readability/braces] [4]
- TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
- after_shift, after_shift_filter, oss);
- }
- }
-
- template <typename... Args>
- void TemplateHelper(std::function<void(arm::Condition, Args...)> f, int depth, bool without_pc,
- std::string fmt, std::string filter, std::ostringstream& oss) {
- for (arm::Condition c : GetConditions()) {
- std::string after_cond = fmt;
- std::string after_cond_filter = filter;
-
- size_t cond_index = after_cond.find(COND_TOKEN);
- if (cond_index != std::string::npos) {
- after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
- }
-
- cond_index = after_cond_filter.find(COND_TOKEN);
- if (cond_index != std::string::npos) {
- after_cond_filter.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c));
- }
- if (EvalFilterString(after_cond_filter)) {
- continue;
- }
-
- auto lambda = [&] (Args... args) { f(c, args...); }; // NOLINT [readability/braces] [4]
- TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
- after_cond, after_cond_filter, oss);
- }
- }
-
- template <typename... Args>
- void TemplateHelper(std::function<void(arm::SetCc, Args...)> f, int depth, bool without_pc,
- std::string fmt, std::string filter, std::ostringstream& oss) {
- for (arm::SetCc s : GetSetCcs()) {
- std::string after_cond = fmt;
- std::string after_cond_filter = filter;
-
- size_t cond_index = after_cond.find(SET_CC_TOKEN);
- if (cond_index != std::string::npos) {
- after_cond.replace(cond_index, ConstexprStrLen(SET_CC_TOKEN), GetSetCcString(s));
- }
-
- cond_index = after_cond_filter.find(SET_CC_TOKEN);
- if (cond_index != std::string::npos) {
- after_cond_filter.replace(cond_index, ConstexprStrLen(SET_CC_TOKEN), GetSetCcString(s));
- }
- if (EvalFilterString(after_cond_filter)) {
- continue;
- }
-
- auto lambda = [&] (Args... args) { f(s, args...); }; // NOLINT [readability/braces] [4]
- TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
- after_cond, after_cond_filter, oss);
- }
- }
-
- template <typename Assembler, typename T1, typename T2>
- std::function<void(T1, T2)> GetBoundFunction2(void (Assembler::*f)(T1, T2)) {
- return std::bind(f, GetAssembler(), _1, _2);
- }
-
- template <typename Assembler, typename T1, typename T2, typename T3>
- std::function<void(T1, T2, T3)> GetBoundFunction3(void (Assembler::*f)(T1, T2, T3)) {
- return std::bind(f, GetAssembler(), _1, _2, _3);
- }
-
- template <typename Assembler, typename T1, typename T2, typename T3, typename T4>
- std::function<void(T1, T2, T3, T4)> GetBoundFunction4(
- void (Assembler::*f)(T1, T2, T3, T4)) {
- return std::bind(f, GetAssembler(), _1, _2, _3, _4);
- }
-
- template <typename Assembler, typename T1, typename T2, typename T3, typename T4, typename T5>
- std::function<void(T1, T2, T3, T4, T5)> GetBoundFunction5(
- void (Assembler::*f)(T1, T2, T3, T4, T5)) {
- return std::bind(f, GetAssembler(), _1, _2, _3, _4, _5);
- }
-
- template <typename... Args>
- void GenericTemplateHelper(std::function<void(Args...)> f, bool without_pc,
- std::string fmt, std::string test_name, std::string filter) {
- first_ = false;
- WarnOnCombinations(CountHelper<Args...>(without_pc));
-
- std::ostringstream oss;
-
- TemplateHelper(f, 0, without_pc, fmt, filter, oss);
-
- oss << "\n"; // Trailing newline.
-
- DriverStr(oss.str(), test_name);
- }
-
- template <typename Assembler, typename... Args>
- void T2Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
- std::string test_name, std::string filter = "") {
- GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name, filter);
- }
-
- template <typename Assembler, typename... Args>
- void T3Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
- std::string test_name, std::string filter = "") {
- GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name, filter);
- }
-
- template <typename Assembler, typename... Args>
- void T4Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
- std::string test_name, std::string filter = "") {
- GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name, filter);
- }
-
- template <typename Assembler, typename... Args>
- void T5Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt,
- std::string test_name, std::string filter = "") {
- GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name, filter);
- }
-
- private:
- template <typename T>
- size_t CountHelper(bool without_pc) {
- size_t tmp;
- if (std::is_same<T, arm::Register>::value) {
- tmp = GetRegisters().size();
- if (without_pc) {
- tmp--;; // Approximation...
- }
- return tmp;
- } else if (std::is_same<T, const arm::ShifterOperand&>::value) {
- return GetShiftOperands().size();
- } else if (std::is_same<T, arm::Condition>::value) {
- return GetConditions().size();
- } else {
- LOG(WARNING) << "Unknown type while counting.";
- return 1;
- }
- }
-
- template <typename T1, typename T2, typename... Args>
- size_t CountHelper(bool without_pc) {
- size_t tmp;
- if (std::is_same<T1, arm::Register>::value) {
- tmp = GetRegisters().size();
- if (without_pc) {
- tmp--;; // Approximation...
- }
- } else if (std::is_same<T1, const arm::ShifterOperand&>::value) {
- tmp = GetShiftOperands().size();
- } else if (std::is_same<T1, arm::Condition>::value) {
- tmp = GetConditions().size();
- } else {
- LOG(WARNING) << "Unknown type while counting.";
- tmp = 1;
- }
- size_t rec = CountHelper<T2, Args...>(without_pc);
- return rec * tmp;
- }
-
- bool first_;
-
- static constexpr const char* kArm32AssemblyHeader = ".arm\n";
-
- std::vector<arm::Register*> registers_;
- std::vector<arm::Condition> conditions_;
- std::vector<arm::SetCc> set_ccs_;
- std::vector<arm::ShifterOperand> shifter_operands_;
-};
-
-
-TEST_F(AssemblerArm32Test, Toolchain) {
- EXPECT_TRUE(CheckTools());
-}
-
-TEST_F(AssemblerArm32Test, Sbfx) {
- std::vector<std::pair<uint32_t, uint32_t>> immediates;
- immediates.push_back({0, 1});
- immediates.push_back({0, 8});
- immediates.push_back({0, 15});
- immediates.push_back({0, 16});
- immediates.push_back({0, 31});
- immediates.push_back({0, 32});
-
- immediates.push_back({1, 1});
- immediates.push_back({1, 15});
- immediates.push_back({1, 31});
-
- immediates.push_back({8, 1});
- immediates.push_back({8, 15});
- immediates.push_back({8, 16});
- immediates.push_back({8, 24});
-
- immediates.push_back({31, 1});
-
- DriverStr(RepeatRRiiC(&arm::Arm32Assembler::sbfx, immediates,
- "sbfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "sbfx");
-}
-
-TEST_F(AssemblerArm32Test, Ubfx) {
- std::vector<std::pair<uint32_t, uint32_t>> immediates;
- immediates.push_back({0, 1});
- immediates.push_back({0, 8});
- immediates.push_back({0, 15});
- immediates.push_back({0, 16});
- immediates.push_back({0, 31});
- immediates.push_back({0, 32});
-
- immediates.push_back({1, 1});
- immediates.push_back({1, 15});
- immediates.push_back({1, 31});
-
- immediates.push_back({8, 1});
- immediates.push_back({8, 15});
- immediates.push_back({8, 16});
- immediates.push_back({8, 24});
-
- immediates.push_back({31, 1});
-
- DriverStr(RepeatRRiiC(&arm::Arm32Assembler::ubfx, immediates,
- "ubfx{cond} {reg1}, {reg2}, #{imm1}, #{imm2}"), "ubfx");
-}
-
-TEST_F(AssemblerArm32Test, Mul) {
- T4Helper(&arm::Arm32Assembler::mul, true, "mul{cond} {reg1}, {reg2}, {reg3}", "mul");
-}
-
-TEST_F(AssemblerArm32Test, Mla) {
- T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mla");
-}
-
-TEST_F(AssemblerArm32Test, Umull) {
- T5Helper(&arm::Arm32Assembler::umull, true, "umull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
- "umull", "{reg1}={reg2}"); // Skip the cases where reg1 == reg2.
-}
-
-TEST_F(AssemblerArm32Test, Smull) {
- T5Helper(&arm::Arm32Assembler::smull, true, "smull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
- "smull", "{reg1}={reg2}"); // Skip the cases where reg1 == reg2.
-}
-
-TEST_F(AssemblerArm32Test, Sdiv) {
- T4Helper(&arm::Arm32Assembler::sdiv, true, "sdiv{cond} {reg1}, {reg2}, {reg3}", "sdiv");
-}
-
-TEST_F(AssemblerArm32Test, Udiv) {
- T4Helper(&arm::Arm32Assembler::udiv, true, "udiv{cond} {reg1}, {reg2}, {reg3}", "udiv");
-}
-
-TEST_F(AssemblerArm32Test, And) {
- T5Helper(&arm::Arm32Assembler::and_, true, "and{cond}{s} {reg1}, {reg2}, {shift}", "and");
-}
-
-TEST_F(AssemblerArm32Test, Ands) {
- T4Helper(&arm::Arm32Assembler::ands, true, "and{cond}s {reg1}, {reg2}, {shift}", "ands");
-}
-
-TEST_F(AssemblerArm32Test, Eor) {
- T5Helper(&arm::Arm32Assembler::eor, true, "eor{cond}{s} {reg1}, {reg2}, {shift}", "eor");
-}
-
-TEST_F(AssemblerArm32Test, Eors) {
- T4Helper(&arm::Arm32Assembler::eors, true, "eor{cond}s {reg1}, {reg2}, {shift}", "eors");
-}
-
-TEST_F(AssemblerArm32Test, Orr) {
- T5Helper(&arm::Arm32Assembler::orr, true, "orr{cond}{s} {reg1}, {reg2}, {shift}", "orr");
-}
-
-TEST_F(AssemblerArm32Test, Orrs) {
- T4Helper(&arm::Arm32Assembler::orrs, true, "orr{cond}s {reg1}, {reg2}, {shift}", "orrs");
-}
-
-TEST_F(AssemblerArm32Test, Bic) {
- T5Helper(&arm::Arm32Assembler::bic, true, "bic{cond}{s} {reg1}, {reg2}, {shift}", "bic");
-}
-
-TEST_F(AssemblerArm32Test, Bics) {
- T4Helper(&arm::Arm32Assembler::bics, true, "bic{cond}s {reg1}, {reg2}, {shift}", "bics");
-}
-
-TEST_F(AssemblerArm32Test, Mov) {
- T4Helper(&arm::Arm32Assembler::mov, true, "mov{cond}{s} {reg1}, {shift}", "mov");
-}
-
-TEST_F(AssemblerArm32Test, Movs) {
- T3Helper(&arm::Arm32Assembler::movs, true, "mov{cond}s {reg1}, {shift}", "movs");
-}
-
-TEST_F(AssemblerArm32Test, Mvn) {
- T4Helper(&arm::Arm32Assembler::mvn, true, "mvn{cond}{s} {reg1}, {shift}", "mvn");
-}
-
-TEST_F(AssemblerArm32Test, Mvns) {
- T3Helper(&arm::Arm32Assembler::mvns, true, "mvn{cond}s {reg1}, {shift}", "mvns");
-}
-
-TEST_F(AssemblerArm32Test, Add) {
- T5Helper(&arm::Arm32Assembler::add, false, "add{cond}{s} {reg1}, {reg2}, {shift}", "add");
-}
-
-TEST_F(AssemblerArm32Test, Adds) {
- T4Helper(&arm::Arm32Assembler::adds, false, "add{cond}s {reg1}, {reg2}, {shift}", "adds");
-}
-
-TEST_F(AssemblerArm32Test, Adc) {
- T5Helper(&arm::Arm32Assembler::adc, false, "adc{cond}{s} {reg1}, {reg2}, {shift}", "adc");
-}
-
-TEST_F(AssemblerArm32Test, Adcs) {
- T4Helper(&arm::Arm32Assembler::adcs, false, "adc{cond}s {reg1}, {reg2}, {shift}", "adcs");
-}
-
-TEST_F(AssemblerArm32Test, Sub) {
- T5Helper(&arm::Arm32Assembler::sub, false, "sub{cond}{s} {reg1}, {reg2}, {shift}", "sub");
-}
-
-TEST_F(AssemblerArm32Test, Subs) {
- T4Helper(&arm::Arm32Assembler::subs, false, "sub{cond}s {reg1}, {reg2}, {shift}", "subs");
-}
-
-TEST_F(AssemblerArm32Test, Sbc) {
- T5Helper(&arm::Arm32Assembler::sbc, false, "sbc{cond}{s} {reg1}, {reg2}, {shift}", "sbc");
-}
-
-TEST_F(AssemblerArm32Test, Sbcs) {
- T4Helper(&arm::Arm32Assembler::sbcs, false, "sbc{cond}s {reg1}, {reg2}, {shift}", "sbcs");
-}
-
-TEST_F(AssemblerArm32Test, Rsb) {
- T5Helper(&arm::Arm32Assembler::rsb, true, "rsb{cond}{s} {reg1}, {reg2}, {shift}", "rsb");
-}
-
-TEST_F(AssemblerArm32Test, Rsbs) {
- T4Helper(&arm::Arm32Assembler::rsbs, true, "rsb{cond}s {reg1}, {reg2}, {shift}", "rsbs");
-}
-
-TEST_F(AssemblerArm32Test, Rsc) {
- T5Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond}{s} {reg1}, {reg2}, {shift}", "rsc");
-}
-
-TEST_F(AssemblerArm32Test, Rscs) {
- T4Helper(&arm::Arm32Assembler::rscs, false, "rsc{cond}s {reg1}, {reg2}, {shift}", "rscs");
-}
-
-/* TODO: Need better filter support.
-TEST_F(AssemblerArm32Test, Strex) {
- T4Helper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex",
- "{reg1}={reg2}||{reg1}={reg3}"); // Skip the cases where reg1 == reg2 || reg1 == reg3.
-}
-*/
-
-TEST_F(AssemblerArm32Test, Clz) {
- T3Helper(&arm::Arm32Assembler::clz, true, "clz{cond} {reg1}, {reg2}", "clz");
-}
-
-TEST_F(AssemblerArm32Test, Tst) {
- T3Helper(&arm::Arm32Assembler::tst, true, "tst{cond} {reg1}, {shift}", "tst");
-}
-
-TEST_F(AssemblerArm32Test, Teq) {
- T3Helper(&arm::Arm32Assembler::teq, true, "teq{cond} {reg1}, {shift}", "teq");
-}
-
-TEST_F(AssemblerArm32Test, Cmp) {
- T3Helper(&arm::Arm32Assembler::cmp, true, "cmp{cond} {reg1}, {shift}", "cmp");
-}
-
-TEST_F(AssemblerArm32Test, Cmn) {
- T3Helper(&arm::Arm32Assembler::cmn, true, "cmn{cond} {reg1}, {shift}", "cmn");
-}
-
-TEST_F(AssemblerArm32Test, Blx) {
- T2Helper(&arm::Arm32Assembler::blx, true, "blx{cond} {reg1}", "blx");
-}
-
-TEST_F(AssemblerArm32Test, Bx) {
- T2Helper(&arm::Arm32Assembler::bx, true, "bx{cond} {reg1}", "bx");
-}
-
-TEST_F(AssemblerArm32Test, Vmstat) {
- GetAssembler()->vmstat();
-
- const char* expected = "vmrs APSR_nzcv, FPSCR\n";
-
- DriverStr(expected, "vmrs");
-}
-
-TEST_F(AssemblerArm32Test, ldrexd) {
- GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R0);
- GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R1);
- GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R2);
-
- const char* expected =
- "ldrexd r0, r1, [r0]\n"
- "ldrexd r0, r1, [r1]\n"
- "ldrexd r0, r1, [r2]\n";
- DriverStr(expected, "ldrexd");
-}
-
-TEST_F(AssemblerArm32Test, strexd) {
- GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R0);
- GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R1);
- GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R2);
-
- const char* expected =
- "strexd r9, r0, r1, [r0]\n"
- "strexd r9, r0, r1, [r1]\n"
- "strexd r9, r0, r1, [r2]\n";
- DriverStr(expected, "strexd");
-}
-
-TEST_F(AssemblerArm32Test, rbit) {
- T3Helper(&arm::Arm32Assembler::rbit, true, "rbit{cond} {reg1}, {reg2}", "rbit");
-}
-
-TEST_F(AssemblerArm32Test, rev) {
- T3Helper(&arm::Arm32Assembler::rev, true, "rev{cond} {reg1}, {reg2}", "rev");
-}
-
-TEST_F(AssemblerArm32Test, rev16) {
- T3Helper(&arm::Arm32Assembler::rev16, true, "rev16{cond} {reg1}, {reg2}", "rev16");
-}
-
-TEST_F(AssemblerArm32Test, revsh) {
- T3Helper(&arm::Arm32Assembler::revsh, true, "revsh{cond} {reg1}, {reg2}", "revsh");
-}
-
-TEST_F(AssemblerArm32Test, vcnt) {
- // Different D register numbers are used here, to test register encoding.
- // Source register number is encoded as M:Vm, destination register number is encoded as D:Vd,
- // For source and destination registers which use D0..D15, the M bit and D bit should be 0.
- // For source and destination registers which use D16..D32, the M bit and D bit should be 1.
- GetAssembler()->vcntd(arm::D0, arm::D1);
- GetAssembler()->vcntd(arm::D19, arm::D20);
- GetAssembler()->vcntd(arm::D0, arm::D9);
- GetAssembler()->vcntd(arm::D16, arm::D20);
-
- std::string expected =
- "vcnt.8 d0, d1\n"
- "vcnt.8 d19, d20\n"
- "vcnt.8 d0, d9\n"
- "vcnt.8 d16, d20\n";
-
- DriverStr(expected, "vcnt");
-}
-
-TEST_F(AssemblerArm32Test, vpaddl) {
- // Different D register numbers are used here, to test register encoding.
- // Source register number is encoded as M:Vm, destination register number is encoded as D:Vd,
- // For source and destination registers which use D0..D15, the M bit and D bit should be 0.
- // For source and destination registers which use D16..D32, the M bit and D bit should be 1.
- // Different data types (signed and unsigned) are also tested.
- GetAssembler()->vpaddld(arm::D0, arm::D0, 8, true);
- GetAssembler()->vpaddld(arm::D20, arm::D20, 8, false);
- GetAssembler()->vpaddld(arm::D0, arm::D20, 16, false);
- GetAssembler()->vpaddld(arm::D20, arm::D0, 32, true);
-
- std::string expected =
- "vpaddl.u8 d0, d0\n"
- "vpaddl.s8 d20, d20\n"
- "vpaddl.s16 d0, d20\n"
- "vpaddl.u32 d20, d0\n";
-
- DriverStr(expected, "vpaddl");
-}
-
-} // namespace art
diff --git a/compiler/utils/arm/assembler_arm_shared.h b/compiler/utils/arm/assembler_arm_shared.h
new file mode 100644
index 0000000..21f13ee
--- /dev/null
+++ b/compiler/utils/arm/assembler_arm_shared.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_SHARED_H_
+#define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_SHARED_H_
+
+namespace art {
+namespace arm {
+
+enum LoadOperandType {
+ kLoadSignedByte,
+ kLoadUnsignedByte,
+ kLoadSignedHalfword,
+ kLoadUnsignedHalfword,
+ kLoadWord,
+ kLoadWordPair,
+ kLoadSWord,
+ kLoadDWord
+};
+
+enum StoreOperandType {
+ kStoreByte,
+ kStoreHalfword,
+ kStoreWord,
+ kStoreWordPair,
+ kStoreSWord,
+ kStoreDWord
+};
+
+// Set condition codes request.
+enum SetCc {
+ kCcDontCare, // Allows prioritizing 16-bit instructions on Thumb2 whether they set CCs or not.
+ kCcSet,
+ kCcKeep,
+};
+
+} // namespace arm
+} // namespace art
+
+#endif // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_SHARED_H_
diff --git a/compiler/utils/arm/assembler_arm_vixl.cc b/compiler/utils/arm/assembler_arm_vixl.cc
new file mode 100644
index 0000000..3c5973e
--- /dev/null
+++ b/compiler/utils/arm/assembler_arm_vixl.cc
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <type_traits>
+
+#include "assembler_arm_vixl.h"
+#include "entrypoints/quick/quick_entrypoints.h"
+#include "thread.h"
+
+using namespace vixl::aarch32; // NOLINT(build/namespaces)
+
+namespace art {
+namespace arm {
+
+#ifdef ___
+#error "ARM Assembler macro already defined."
+#else
+#define ___ vixl_masm_.
+#endif
+
+extern const vixl32::Register tr(TR);
+
+void ArmVIXLAssembler::FinalizeCode() {
+ vixl_masm_.FinalizeCode();
+}
+
+size_t ArmVIXLAssembler::CodeSize() const {
+ return vixl_masm_.GetSizeOfCodeGenerated();
+}
+
+const uint8_t* ArmVIXLAssembler::CodeBufferBaseAddress() const {
+ return vixl_masm_.GetStartAddress<uint8_t*>();
+}
+
+void ArmVIXLAssembler::FinalizeInstructions(const MemoryRegion& region) {
+ // Copy the instructions from the buffer.
+ MemoryRegion from(vixl_masm_.GetStartAddress<void*>(), CodeSize());
+ region.CopyFrom(0, from);
+}
+
+void ArmVIXLAssembler::PoisonHeapReference(vixl::aarch32::Register reg) {
+ // reg = -reg.
+ ___ Rsb(reg, reg, 0);
+}
+
+void ArmVIXLAssembler::UnpoisonHeapReference(vixl::aarch32::Register reg) {
+ // reg = -reg.
+ ___ Rsb(reg, reg, 0);
+}
+
+void ArmVIXLAssembler::MaybeUnpoisonHeapReference(vixl32::Register reg) {
+ if (kPoisonHeapReferences) {
+ UnpoisonHeapReference(reg);
+ }
+}
+
+void ArmVIXLAssembler::LoadImmediate(vixl32::Register rd, int32_t value) {
+ // TODO(VIXL): Implement this optimization in VIXL.
+ if (!ShifterOperandCanAlwaysHold(value) && ShifterOperandCanAlwaysHold(~value)) {
+ ___ Mvn(rd, ~value);
+ } else {
+ ___ Mov(rd, value);
+ }
+}
+
+bool ArmVIXLAssembler::ShifterOperandCanAlwaysHold(uint32_t immediate) {
+ return vixl_masm_.IsModifiedImmediate(immediate);
+}
+
+bool ArmVIXLAssembler::ShifterOperandCanHold(Opcode opcode, uint32_t immediate, SetCc set_cc) {
+ switch (opcode) {
+ case ADD:
+ case SUB:
+ // Less than (or equal to) 12 bits can be done if we don't need to set condition codes.
+ if (IsUint<12>(immediate) && set_cc != kCcSet) {
+ return true;
+ }
+ return ShifterOperandCanAlwaysHold(immediate);
+
+ case MOV:
+ // TODO: Support less than or equal to 12bits.
+ return ShifterOperandCanAlwaysHold(immediate);
+
+ case MVN:
+ default:
+ return ShifterOperandCanAlwaysHold(immediate);
+ }
+}
+
+bool ArmVIXLAssembler::CanSplitLoadStoreOffset(int32_t allowed_offset_bits,
+ int32_t offset,
+ /*out*/ int32_t* add_to_base,
+ /*out*/ int32_t* offset_for_load_store) {
+ int32_t other_bits = offset & ~allowed_offset_bits;
+ if (ShifterOperandCanAlwaysHold(other_bits) || ShifterOperandCanAlwaysHold(-other_bits)) {
+ *add_to_base = offset & ~allowed_offset_bits;
+ *offset_for_load_store = offset & allowed_offset_bits;
+ return true;
+ }
+ return false;
+}
+
+int32_t ArmVIXLAssembler::AdjustLoadStoreOffset(int32_t allowed_offset_bits,
+ vixl32::Register temp,
+ vixl32::Register base,
+ int32_t offset) {
+ DCHECK_NE(offset & ~allowed_offset_bits, 0);
+ int32_t add_to_base, offset_for_load;
+ if (CanSplitLoadStoreOffset(allowed_offset_bits, offset, &add_to_base, &offset_for_load)) {
+ ___ Add(temp, base, add_to_base);
+ return offset_for_load;
+ } else {
+ ___ Mov(temp, offset);
+ ___ Add(temp, temp, base);
+ return 0;
+ }
+}
+
+// TODO(VIXL): Implement this in VIXL.
+int32_t ArmVIXLAssembler::GetAllowedLoadOffsetBits(LoadOperandType type) {
+ switch (type) {
+ case kLoadSignedByte:
+ case kLoadSignedHalfword:
+ case kLoadUnsignedHalfword:
+ case kLoadUnsignedByte:
+ case kLoadWord:
+ // We can encode imm12 offset.
+ return 0xfff;
+ case kLoadSWord:
+ case kLoadDWord:
+ case kLoadWordPair:
+ // We can encode imm8:'00' offset.
+ return 0xff << 2;
+ default:
+ LOG(FATAL) << "UNREACHABLE";
+ UNREACHABLE();
+ }
+}
+
+// TODO(VIXL): Implement this in VIXL.
+int32_t ArmVIXLAssembler::GetAllowedStoreOffsetBits(StoreOperandType type) {
+ switch (type) {
+ case kStoreHalfword:
+ case kStoreByte:
+ case kStoreWord:
+ // We can encode imm12 offset.
+ return 0xfff;
+ case kStoreSWord:
+ case kStoreDWord:
+ case kStoreWordPair:
+ // We can encode imm8:'00' offset.
+ return 0xff << 2;
+ default:
+ LOG(FATAL) << "UNREACHABLE";
+ UNREACHABLE();
+ }
+}
+
+// TODO(VIXL): Implement this in VIXL.
+static bool CanHoldLoadOffsetThumb(LoadOperandType type, int offset) {
+ switch (type) {
+ case kLoadSignedByte:
+ case kLoadSignedHalfword:
+ case kLoadUnsignedHalfword:
+ case kLoadUnsignedByte:
+ case kLoadWord:
+ return IsAbsoluteUint<12>(offset);
+ case kLoadSWord:
+ case kLoadDWord:
+ return IsAbsoluteUint<10>(offset) && IsAligned<4>(offset); // VFP addressing mode.
+ case kLoadWordPair:
+ return IsAbsoluteUint<10>(offset) && IsAligned<4>(offset);
+ default:
+ LOG(FATAL) << "UNREACHABLE";
+ UNREACHABLE();
+ }
+}
+
+// TODO(VIXL): Implement this in VIXL.
+static bool CanHoldStoreOffsetThumb(StoreOperandType type, int offset) {
+ switch (type) {
+ case kStoreHalfword:
+ case kStoreByte:
+ case kStoreWord:
+ return IsAbsoluteUint<12>(offset);
+ case kStoreSWord:
+ case kStoreDWord:
+ return IsAbsoluteUint<10>(offset) && IsAligned<4>(offset); // VFP addressing mode.
+ case kStoreWordPair:
+ return IsAbsoluteUint<10>(offset) && IsAligned<4>(offset);
+ default:
+ LOG(FATAL) << "UNREACHABLE";
+ UNREACHABLE();
+ }
+}
+
+// Implementation note: this method must emit at most one instruction when
+// Address::CanHoldStoreOffsetThumb.
+// TODO(VIXL): Implement AdjustLoadStoreOffset logic in VIXL.
+void ArmVIXLAssembler::StoreToOffset(StoreOperandType type,
+ vixl32::Register reg,
+ vixl32::Register base,
+ int32_t offset) {
+ vixl32::Register tmp_reg;
+ UseScratchRegisterScope temps(&vixl_masm_);
+
+ if (!CanHoldStoreOffsetThumb(type, offset)) {
+ CHECK_NE(base.GetCode(), kIpCode);
+ if ((reg.GetCode() != kIpCode) &&
+ ((type != kStoreWordPair) || (reg.GetCode() + 1 != kIpCode))) {
+ tmp_reg = temps.Acquire();
+ } else {
+ // Be careful not to use ip twice (for `reg` (or `reg` + 1 in
+ // the case of a word-pair store) and `base`) to build the
+ // Address object used by the store instruction(s) below.
+ // Instead, save R5 on the stack (or R6 if R5 is already used by
+ // `base`), use it as secondary temporary register, and restore
+ // it after the store instruction has been emitted.
+ tmp_reg = (base.GetCode() != 5) ? r5 : r6;
+ ___ Push(tmp_reg);
+ if (base.GetCode() == kSpCode) {
+ offset += kRegisterSize;
+ }
+ }
+ // TODO: Implement indexed store (not available for STRD), inline AdjustLoadStoreOffset()
+ // and in the "unsplittable" path get rid of the "add" by using the store indexed instead.
+ offset = AdjustLoadStoreOffset(GetAllowedStoreOffsetBits(type), tmp_reg, base, offset);
+ base = tmp_reg;
+ }
+ DCHECK(CanHoldStoreOffsetThumb(type, offset));
+ switch (type) {
+ case kStoreByte:
+ ___ Strb(reg, MemOperand(base, offset));
+ break;
+ case kStoreHalfword:
+ ___ Strh(reg, MemOperand(base, offset));
+ break;
+ case kStoreWord:
+ ___ Str(reg, MemOperand(base, offset));
+ break;
+ case kStoreWordPair:
+ ___ Strd(reg, vixl32::Register(reg.GetCode() + 1), MemOperand(base, offset));
+ break;
+ default:
+ LOG(FATAL) << "UNREACHABLE";
+ UNREACHABLE();
+ }
+ if ((tmp_reg.IsValid()) && (tmp_reg.GetCode() != kIpCode)) {
+ CHECK(tmp_reg.Is(r5) || tmp_reg.Is(r6)) << tmp_reg;
+ ___ Pop(tmp_reg);
+ }
+}
+
+// Implementation note: this method must emit at most one instruction when
+// Address::CanHoldLoadOffsetThumb.
+// TODO(VIXL): Implement AdjustLoadStoreOffset logic in VIXL.
+void ArmVIXLAssembler::LoadFromOffset(LoadOperandType type,
+ vixl32::Register dest,
+ vixl32::Register base,
+ int32_t offset) {
+ if (!CanHoldLoadOffsetThumb(type, offset)) {
+ CHECK(!base.Is(ip));
+ // Inlined AdjustLoadStoreOffset() allows us to pull a few more tricks.
+ int32_t allowed_offset_bits = GetAllowedLoadOffsetBits(type);
+ DCHECK_NE(offset & ~allowed_offset_bits, 0);
+ int32_t add_to_base, offset_for_load;
+ if (CanSplitLoadStoreOffset(allowed_offset_bits, offset, &add_to_base, &offset_for_load)) {
+ // Use reg for the adjusted base. If it's low reg, we may end up using 16-bit load.
+ AddConstant(dest, base, add_to_base);
+ base = dest;
+ offset = offset_for_load;
+ } else {
+ UseScratchRegisterScope temps(&vixl_masm_);
+ vixl32::Register temp = (dest.Is(base)) ? temps.Acquire() : dest;
+ LoadImmediate(temp, offset);
+ // TODO: Implement indexed load (not available for LDRD) and use it here to avoid the ADD.
+ // Use reg for the adjusted base. If it's low reg, we may end up using 16-bit load.
+ ___ Add(dest, dest, (dest.Is(base)) ? temp : base);
+ base = dest;
+ offset = 0;
+ }
+ }
+
+ DCHECK(CanHoldLoadOffsetThumb(type, offset));
+ switch (type) {
+ case kLoadSignedByte:
+ ___ Ldrsb(dest, MemOperand(base, offset));
+ break;
+ case kLoadUnsignedByte:
+ ___ Ldrb(dest, MemOperand(base, offset));
+ break;
+ case kLoadSignedHalfword:
+ ___ Ldrsh(dest, MemOperand(base, offset));
+ break;
+ case kLoadUnsignedHalfword:
+ ___ Ldrh(dest, MemOperand(base, offset));
+ break;
+ case kLoadWord:
+ CHECK(!dest.IsSP());
+ ___ Ldr(dest, MemOperand(base, offset));
+ break;
+ case kLoadWordPair:
+ ___ Ldrd(dest, vixl32::Register(dest.GetCode() + 1), MemOperand(base, offset));
+ break;
+ default:
+ LOG(FATAL) << "UNREACHABLE";
+ UNREACHABLE();
+ }
+}
+
+void ArmVIXLAssembler::StoreSToOffset(vixl32::SRegister source,
+ vixl32::Register base,
+ int32_t offset) {
+ ___ Vstr(source, MemOperand(base, offset));
+}
+
+void ArmVIXLAssembler::StoreDToOffset(vixl32::DRegister source,
+ vixl32::Register base,
+ int32_t offset) {
+ ___ Vstr(source, MemOperand(base, offset));
+}
+
+void ArmVIXLAssembler::LoadSFromOffset(vixl32::SRegister reg,
+ vixl32::Register base,
+ int32_t offset) {
+ ___ Vldr(reg, MemOperand(base, offset));
+}
+
+void ArmVIXLAssembler::LoadDFromOffset(vixl32::DRegister reg,
+ vixl32::Register base,
+ int32_t offset) {
+ ___ Vldr(reg, MemOperand(base, offset));
+}
+
+void ArmVIXLAssembler::AddConstant(vixl32::Register rd, int32_t value) {
+ AddConstant(rd, rd, value);
+}
+
+// TODO(VIXL): think about using adds which updates flags where possible.
+void ArmVIXLAssembler::AddConstant(vixl32::Register rd,
+ vixl32::Register rn,
+ int32_t value) {
+ DCHECK(vixl_masm_.OutsideITBlock());
+ // TODO(VIXL): implement this optimization in VIXL.
+ if (value == 0) {
+ if (!rd.Is(rn)) {
+ ___ Mov(rd, rn);
+ }
+ return;
+ }
+ ___ Add(rd, rn, value);
+}
+
+// Inside IT block we must use assembler, macroassembler instructions are not permitted.
+void ArmVIXLAssembler::AddConstantInIt(vixl32::Register rd,
+ vixl32::Register rn,
+ int32_t value,
+ vixl32::Condition cond) {
+ DCHECK(vixl_masm_.InITBlock());
+ if (value == 0) {
+ ___ mov(cond, rd, rn);
+ } else {
+ ___ add(cond, rd, rn, value);
+ }
+}
+
+} // namespace arm
+} // namespace art
diff --git a/compiler/utils/arm/assembler_arm_vixl.h b/compiler/utils/arm/assembler_arm_vixl.h
new file mode 100644
index 0000000..c8f3a9b
--- /dev/null
+++ b/compiler/utils/arm/assembler_arm_vixl.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_VIXL_H_
+#define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_VIXL_H_
+
+#include "base/arena_containers.h"
+#include "base/logging.h"
+#include "constants_arm.h"
+#include "offsets.h"
+#include "utils/arm/assembler_arm_shared.h"
+#include "utils/arm/managed_register_arm.h"
+#include "utils/assembler.h"
+#include "utils/jni_macro_assembler.h"
+
+// TODO(VIXL): Make VIXL compile with -Wshadow and remove pragmas.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#include "aarch32/macro-assembler-aarch32.h"
+#pragma GCC diagnostic pop
+
+namespace vixl32 = vixl::aarch32;
+
+namespace art {
+namespace arm {
+
+class ArmVIXLAssembler FINAL : public Assembler {
+ private:
+ class ArmException;
+ public:
+ explicit ArmVIXLAssembler(ArenaAllocator* arena)
+ : Assembler(arena) {
+ // Use Thumb2 instruction set.
+ vixl_masm_.UseT32();
+ }
+
+ virtual ~ArmVIXLAssembler() {}
+ vixl32::MacroAssembler* GetVIXLAssembler() { return &vixl_masm_; }
+ void FinalizeCode() OVERRIDE;
+
+ // Size of generated code.
+ size_t CodeSize() const OVERRIDE;
+ const uint8_t* CodeBufferBaseAddress() const OVERRIDE;
+
+ // Copy instructions out of assembly buffer into the given region of memory.
+ void FinalizeInstructions(const MemoryRegion& region) OVERRIDE;
+
+ void Bind(Label* label ATTRIBUTE_UNUSED) OVERRIDE {
+ UNIMPLEMENTED(FATAL) << "Do not use Bind for ARM";
+ }
+ void Jump(Label* label ATTRIBUTE_UNUSED) OVERRIDE {
+ UNIMPLEMENTED(FATAL) << "Do not use Jump for ARM";
+ }
+
+ //
+ // Heap poisoning.
+ //
+ // Poison a heap reference contained in `reg`.
+ void PoisonHeapReference(vixl32::Register reg);
+ // Unpoison a heap reference contained in `reg`.
+ void UnpoisonHeapReference(vixl32::Register reg);
+ // Unpoison a heap reference contained in `reg` if heap poisoning is enabled.
+ void MaybeUnpoisonHeapReference(vixl32::Register reg);
+
+ void StoreToOffset(StoreOperandType type,
+ vixl32::Register reg,
+ vixl32::Register base,
+ int32_t offset);
+ void StoreSToOffset(vixl32::SRegister source, vixl32::Register base, int32_t offset);
+ void StoreDToOffset(vixl32::DRegister source, vixl32::Register base, int32_t offset);
+
+ void LoadImmediate(vixl32::Register dest, int32_t value);
+ void LoadFromOffset(LoadOperandType type,
+ vixl32::Register reg,
+ vixl32::Register base,
+ int32_t offset);
+ void LoadSFromOffset(vixl32::SRegister reg, vixl32::Register base, int32_t offset);
+ void LoadDFromOffset(vixl32::DRegister reg, vixl32::Register base, int32_t offset);
+
+ bool ShifterOperandCanAlwaysHold(uint32_t immediate);
+ bool ShifterOperandCanHold(Opcode opcode, uint32_t immediate, SetCc set_cc);
+ bool CanSplitLoadStoreOffset(int32_t allowed_offset_bits,
+ int32_t offset,
+ /*out*/ int32_t* add_to_base,
+ /*out*/ int32_t* offset_for_load_store);
+ int32_t AdjustLoadStoreOffset(int32_t allowed_offset_bits,
+ vixl32::Register temp,
+ vixl32::Register base,
+ int32_t offset);
+ int32_t GetAllowedLoadOffsetBits(LoadOperandType type);
+ int32_t GetAllowedStoreOffsetBits(StoreOperandType type);
+
+ void AddConstant(vixl32::Register rd, int32_t value);
+ void AddConstant(vixl32::Register rd, vixl32::Register rn, int32_t value);
+ void AddConstantInIt(vixl32::Register rd,
+ vixl32::Register rn,
+ int32_t value,
+ vixl32::Condition cond = vixl32::al);
+
+ private:
+ // VIXL assembler.
+ vixl32::MacroAssembler vixl_masm_;
+};
+
+// Thread register declaration.
+extern const vixl32::Register tr;
+
+} // namespace arm
+} // namespace art
+
+#endif // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_VIXL_H_
diff --git a/compiler/utils/arm/jni_macro_assembler_arm.cc b/compiler/utils/arm/jni_macro_assembler_arm.cc
index af5ebb4..e0bfa12 100644
--- a/compiler/utils/arm/jni_macro_assembler_arm.cc
+++ b/compiler/utils/arm/jni_macro_assembler_arm.cc
@@ -18,7 +18,6 @@
#include <algorithm>
-#include "assembler_arm32.h"
#include "assembler_thumb2.h"
#include "base/arena_allocator.h"
#include "base/bit_utils.h"
@@ -47,9 +46,6 @@
ArmJNIMacroAssembler::ArmJNIMacroAssembler(ArenaAllocator* arena, InstructionSet isa) {
switch (isa) {
case kArm:
- asm_.reset(new (arena) Arm32Assembler(arena));
- break;
-
case kThumb2:
asm_.reset(new (arena) Thumb2Assembler(arena));
break;
diff --git a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
new file mode 100644
index 0000000..719fe7f
--- /dev/null
+++ b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
@@ -0,0 +1,599 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <type_traits>
+
+#include "jni_macro_assembler_arm_vixl.h"
+#include "entrypoints/quick/quick_entrypoints.h"
+#include "thread.h"
+
+using namespace vixl::aarch32; // NOLINT(build/namespaces)
+namespace vixl32 = vixl::aarch32;
+
+namespace art {
+namespace arm {
+
+#ifdef ___
+#error "ARM Assembler macro already defined."
+#else
+#define ___ asm_.GetVIXLAssembler()->
+#endif
+
+void ArmVIXLJNIMacroAssembler::FinalizeCode() {
+ for (const std::unique_ptr<
+ ArmVIXLJNIMacroAssembler::ArmException>& exception : exception_blocks_) {
+ EmitExceptionPoll(exception.get());
+ }
+ asm_.FinalizeCode();
+}
+
+static dwarf::Reg DWARFReg(vixl32::Register reg) {
+ return dwarf::Reg::ArmCore(static_cast<int>(reg.GetCode()));
+}
+
+static dwarf::Reg DWARFReg(vixl32::SRegister reg) {
+ return dwarf::Reg::ArmFp(static_cast<int>(reg.GetCode()));
+}
+
+static constexpr size_t kFramePointerSize = static_cast<size_t>(kArmPointerSize);;
+
+void ArmVIXLJNIMacroAssembler::BuildFrame(size_t frame_size,
+ ManagedRegister method_reg,
+ ArrayRef<const ManagedRegister> callee_save_regs,
+ const ManagedRegisterEntrySpills& entry_spills) {
+ CHECK_ALIGNED(frame_size, kStackAlignment);
+ CHECK(r0.Is(method_reg.AsArm().AsVIXLRegister()));
+
+ // Push callee saves and link register.
+ RegList core_spill_mask = 1 << LR;
+ uint32_t fp_spill_mask = 0;
+ for (const ManagedRegister& reg : callee_save_regs) {
+ if (reg.AsArm().IsCoreRegister()) {
+ core_spill_mask |= 1 << reg.AsArm().AsCoreRegister();
+ } else {
+ fp_spill_mask |= 1 << reg.AsArm().AsSRegister();
+ }
+ }
+ ___ Push(RegisterList(core_spill_mask));
+ cfi().AdjustCFAOffset(POPCOUNT(core_spill_mask) * kFramePointerSize);
+ cfi().RelOffsetForMany(DWARFReg(r0), 0, core_spill_mask, kFramePointerSize);
+ if (fp_spill_mask != 0) {
+ uint32_t first = CTZ(fp_spill_mask);
+ uint32_t last = first + POPCOUNT(fp_spill_mask) - 1;
+
+ // Check that list is contiguous.
+ DCHECK_EQ(fp_spill_mask >> CTZ(fp_spill_mask), ~0u >> (32 - POPCOUNT(fp_spill_mask)));
+
+ ___ Vpush(SRegisterList(vixl32::SRegister(first), vixl32::SRegister(last)));
+ cfi().AdjustCFAOffset(POPCOUNT(fp_spill_mask) * kFramePointerSize);
+ cfi().RelOffsetForMany(DWARFReg(s0), 0, fp_spill_mask, kFramePointerSize);
+ }
+
+ // Increase frame to required size.
+ int pushed_values = POPCOUNT(core_spill_mask) + POPCOUNT(fp_spill_mask);
+ // Must at least have space for Method*.
+ CHECK_GT(frame_size, pushed_values * kFramePointerSize);
+ IncreaseFrameSize(frame_size - pushed_values * kFramePointerSize); // handles CFI as well.
+
+ // Write out Method*.
+ asm_.StoreToOffset(kStoreWord, r0, sp, 0);
+
+ // Write out entry spills.
+ int32_t offset = frame_size + kFramePointerSize;
+ for (size_t i = 0; i < entry_spills.size(); ++i) {
+ ArmManagedRegister reg = entry_spills.at(i).AsArm();
+ if (reg.IsNoRegister()) {
+ // only increment stack offset.
+ ManagedRegisterSpill spill = entry_spills.at(i);
+ offset += spill.getSize();
+ } else if (reg.IsCoreRegister()) {
+ asm_.StoreToOffset(kStoreWord, reg.AsVIXLRegister(), sp, offset);
+ offset += 4;
+ } else if (reg.IsSRegister()) {
+ asm_.StoreSToOffset(reg.AsVIXLSRegister(), sp, offset);
+ offset += 4;
+ } else if (reg.IsDRegister()) {
+ asm_.StoreDToOffset(reg.AsVIXLDRegister(), sp, offset);
+ offset += 8;
+ }
+ }
+}
+
+void ArmVIXLJNIMacroAssembler::RemoveFrame(size_t frame_size,
+ ArrayRef<const ManagedRegister> callee_save_regs) {
+ CHECK_ALIGNED(frame_size, kStackAlignment);
+ cfi().RememberState();
+
+ // Compute callee saves to pop and PC.
+ RegList core_spill_mask = 1 << PC;
+ uint32_t fp_spill_mask = 0;
+ for (const ManagedRegister& reg : callee_save_regs) {
+ if (reg.AsArm().IsCoreRegister()) {
+ core_spill_mask |= 1 << reg.AsArm().AsCoreRegister();
+ } else {
+ fp_spill_mask |= 1 << reg.AsArm().AsSRegister();
+ }
+ }
+
+ // Decrease frame to start of callee saves.
+ int pop_values = POPCOUNT(core_spill_mask) + POPCOUNT(fp_spill_mask);
+ CHECK_GT(frame_size, pop_values * kFramePointerSize);
+ DecreaseFrameSize(frame_size - (pop_values * kFramePointerSize)); // handles CFI as well.
+
+ if (fp_spill_mask != 0) {
+ uint32_t first = CTZ(fp_spill_mask);
+ uint32_t last = first + POPCOUNT(fp_spill_mask) - 1;
+ // Check that list is contiguous.
+ DCHECK_EQ(fp_spill_mask >> CTZ(fp_spill_mask), ~0u >> (32 - POPCOUNT(fp_spill_mask)));
+
+ ___ Vpop(SRegisterList(vixl32::SRegister(first), vixl32::SRegister(last)));
+ cfi().AdjustCFAOffset(-kFramePointerSize * POPCOUNT(fp_spill_mask));
+ cfi().RestoreMany(DWARFReg(s0), fp_spill_mask);
+ }
+
+ // Pop callee saves and PC.
+ ___ Pop(RegisterList(core_spill_mask));
+
+ // The CFI should be restored for any code that follows the exit block.
+ cfi().RestoreState();
+ cfi().DefCFAOffset(frame_size);
+}
+
+
+void ArmVIXLJNIMacroAssembler::IncreaseFrameSize(size_t adjust) {
+ asm_.AddConstant(sp, -adjust);
+ cfi().AdjustCFAOffset(adjust);
+}
+
+void ArmVIXLJNIMacroAssembler::DecreaseFrameSize(size_t adjust) {
+ asm_.AddConstant(sp, adjust);
+ cfi().AdjustCFAOffset(-adjust);
+}
+
+void ArmVIXLJNIMacroAssembler::Store(FrameOffset dest, ManagedRegister m_src, size_t size) {
+ ArmManagedRegister src = m_src.AsArm();
+ if (src.IsNoRegister()) {
+ CHECK_EQ(0u, size);
+ } else if (src.IsCoreRegister()) {
+ CHECK_EQ(4u, size);
+ asm_.StoreToOffset(kStoreWord, src.AsVIXLRegister(), sp, dest.Int32Value());
+ } else if (src.IsRegisterPair()) {
+ CHECK_EQ(8u, size);
+ asm_.StoreToOffset(kStoreWord, src.AsVIXLRegisterPairLow(), sp, dest.Int32Value());
+ asm_.StoreToOffset(kStoreWord, src.AsVIXLRegisterPairHigh(), sp, dest.Int32Value() + 4);
+ } else if (src.IsSRegister()) {
+ CHECK_EQ(4u, size);
+ asm_.StoreSToOffset(src.AsVIXLSRegister(), sp, dest.Int32Value());
+ } else {
+ CHECK_EQ(8u, size);
+ CHECK(src.IsDRegister()) << src;
+ asm_.StoreDToOffset(src.AsVIXLDRegister(), sp, dest.Int32Value());
+ }
+}
+
+void ArmVIXLJNIMacroAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
+ ArmManagedRegister src = msrc.AsArm();
+ CHECK(src.IsCoreRegister()) << src;
+ asm_.StoreToOffset(kStoreWord, src.AsVIXLRegister(), sp, dest.Int32Value());
+}
+
+void ArmVIXLJNIMacroAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
+ ArmManagedRegister src = msrc.AsArm();
+ CHECK(src.IsCoreRegister()) << src;
+ asm_.StoreToOffset(kStoreWord, src.AsVIXLRegister(), sp, dest.Int32Value());
+}
+
+void ArmVIXLJNIMacroAssembler::StoreSpanning(FrameOffset dest,
+ ManagedRegister msrc,
+ FrameOffset in_off,
+ ManagedRegister mscratch) {
+ ArmManagedRegister src = msrc.AsArm();
+ ArmManagedRegister scratch = mscratch.AsArm();
+ asm_.StoreToOffset(kStoreWord, src.AsVIXLRegister(), sp, dest.Int32Value());
+ asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), sp, in_off.Int32Value());
+ asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), sp, dest.Int32Value() + 4);
+}
+
+void ArmVIXLJNIMacroAssembler::CopyRef(FrameOffset dest,
+ FrameOffset src,
+ ManagedRegister mscratch) {
+ ArmManagedRegister scratch = mscratch.AsArm();
+ asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), sp, src.Int32Value());
+ asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), sp, dest.Int32Value());
+}
+
+void ArmVIXLJNIMacroAssembler::LoadRef(ManagedRegister dest,
+ ManagedRegister base,
+ MemberOffset offs,
+ bool unpoison_reference) {
+ ArmManagedRegister dst = dest.AsArm();
+ CHECK(dst.IsCoreRegister() && dst.IsCoreRegister()) << dst;
+ asm_.LoadFromOffset(kLoadWord,
+ dst.AsVIXLRegister(),
+ base.AsArm().AsVIXLRegister(),
+ offs.Int32Value());
+
+ if (unpoison_reference) {
+ asm_.MaybeUnpoisonHeapReference(dst.AsVIXLRegister());
+ }
+}
+
+void ArmVIXLJNIMacroAssembler::LoadRef(ManagedRegister dest ATTRIBUTE_UNUSED,
+ FrameOffset src ATTRIBUTE_UNUSED) {
+ UNIMPLEMENTED(FATAL);
+}
+
+void ArmVIXLJNIMacroAssembler::LoadRawPtr(ManagedRegister dest ATTRIBUTE_UNUSED,
+ ManagedRegister base ATTRIBUTE_UNUSED,
+ Offset offs ATTRIBUTE_UNUSED) {
+ UNIMPLEMENTED(FATAL);
+}
+
+void ArmVIXLJNIMacroAssembler::StoreImmediateToFrame(FrameOffset dest,
+ uint32_t imm,
+ ManagedRegister scratch) {
+ ArmManagedRegister mscratch = scratch.AsArm();
+ CHECK(mscratch.IsCoreRegister()) << mscratch;
+ asm_.LoadImmediate(mscratch.AsVIXLRegister(), imm);
+ asm_.StoreToOffset(kStoreWord, mscratch.AsVIXLRegister(), sp, dest.Int32Value());
+}
+
+void ArmVIXLJNIMacroAssembler::Load(ManagedRegister m_dst, FrameOffset src, size_t size) {
+ return Load(m_dst.AsArm(), sp, src.Int32Value(), size);
+}
+
+void ArmVIXLJNIMacroAssembler::LoadFromThread(ManagedRegister m_dst ATTRIBUTE_UNUSED,
+ ThreadOffset32 src ATTRIBUTE_UNUSED,
+ size_t size ATTRIBUTE_UNUSED) {
+ UNIMPLEMENTED(FATAL);
+}
+
+void ArmVIXLJNIMacroAssembler::LoadRawPtrFromThread(ManagedRegister m_dst, ThreadOffset32 offs) {
+ ArmManagedRegister dst = m_dst.AsArm();
+ CHECK(dst.IsCoreRegister()) << dst;
+ asm_.LoadFromOffset(kLoadWord, dst.AsVIXLRegister(), tr, offs.Int32Value());
+}
+
+void ArmVIXLJNIMacroAssembler::CopyRawPtrFromThread(FrameOffset fr_offs,
+ ThreadOffset32 thr_offs,
+ ManagedRegister mscratch) {
+ ArmManagedRegister scratch = mscratch.AsArm();
+ CHECK(scratch.IsCoreRegister()) << scratch;
+ asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), tr, thr_offs.Int32Value());
+ asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), sp, fr_offs.Int32Value());
+}
+
+void ArmVIXLJNIMacroAssembler::CopyRawPtrToThread(ThreadOffset32 thr_offs ATTRIBUTE_UNUSED,
+ FrameOffset fr_offs ATTRIBUTE_UNUSED,
+ ManagedRegister mscratch ATTRIBUTE_UNUSED) {
+ UNIMPLEMENTED(FATAL);
+}
+
+void ArmVIXLJNIMacroAssembler::StoreStackOffsetToThread(ThreadOffset32 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister mscratch) {
+ ArmManagedRegister scratch = mscratch.AsArm();
+ CHECK(scratch.IsCoreRegister()) << scratch;
+ asm_.AddConstant(scratch.AsVIXLRegister(), sp, fr_offs.Int32Value());
+ asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), tr, thr_offs.Int32Value());
+}
+
+void ArmVIXLJNIMacroAssembler::StoreStackPointerToThread(ThreadOffset32 thr_offs) {
+ asm_.StoreToOffset(kStoreWord, sp, tr, thr_offs.Int32Value());
+}
+
+void ArmVIXLJNIMacroAssembler::SignExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
+ size_t size ATTRIBUTE_UNUSED) {
+ UNIMPLEMENTED(FATAL) << "no sign extension necessary for arm";
+}
+
+void ArmVIXLJNIMacroAssembler::ZeroExtend(ManagedRegister mreg ATTRIBUTE_UNUSED,
+ size_t size ATTRIBUTE_UNUSED) {
+ UNIMPLEMENTED(FATAL) << "no zero extension necessary for arm";
+}
+
+void ArmVIXLJNIMacroAssembler::Move(ManagedRegister m_dst,
+ ManagedRegister m_src,
+ size_t size ATTRIBUTE_UNUSED) {
+ ArmManagedRegister dst = m_dst.AsArm();
+ ArmManagedRegister src = m_src.AsArm();
+ if (!dst.Equals(src)) {
+ if (dst.IsCoreRegister()) {
+ CHECK(src.IsCoreRegister()) << src;
+ ___ Mov(dst.AsVIXLRegister(), src.AsVIXLRegister());
+ } else if (dst.IsDRegister()) {
+ CHECK(src.IsDRegister()) << src;
+ ___ Vmov(F64, dst.AsVIXLDRegister(), src.AsVIXLDRegister());
+ } else if (dst.IsSRegister()) {
+ CHECK(src.IsSRegister()) << src;
+ ___ Vmov(F32, dst.AsVIXLSRegister(), src.AsVIXLSRegister());
+ } else {
+ CHECK(dst.IsRegisterPair()) << dst;
+ CHECK(src.IsRegisterPair()) << src;
+ // Ensure that the first move doesn't clobber the input of the second.
+ if (src.AsRegisterPairHigh() != dst.AsRegisterPairLow()) {
+ ___ Mov(dst.AsVIXLRegisterPairLow(), src.AsVIXLRegisterPairLow());
+ ___ Mov(dst.AsVIXLRegisterPairHigh(), src.AsVIXLRegisterPairHigh());
+ } else {
+ ___ Mov(dst.AsVIXLRegisterPairHigh(), src.AsVIXLRegisterPairHigh());
+ ___ Mov(dst.AsVIXLRegisterPairLow(), src.AsVIXLRegisterPairLow());
+ }
+ }
+ }
+}
+
+void ArmVIXLJNIMacroAssembler::Copy(FrameOffset dest,
+ FrameOffset src,
+ ManagedRegister scratch,
+ size_t size) {
+ ArmManagedRegister temp = scratch.AsArm();
+ CHECK(temp.IsCoreRegister()) << temp;
+ CHECK(size == 4 || size == 8) << size;
+ if (size == 4) {
+ asm_.LoadFromOffset(kLoadWord, temp.AsVIXLRegister(), sp, src.Int32Value());
+ asm_.StoreToOffset(kStoreWord, temp.AsVIXLRegister(), sp, dest.Int32Value());
+ } else if (size == 8) {
+ asm_.LoadFromOffset(kLoadWord, temp.AsVIXLRegister(), sp, src.Int32Value());
+ asm_.StoreToOffset(kStoreWord, temp.AsVIXLRegister(), sp, dest.Int32Value());
+ asm_.LoadFromOffset(kLoadWord, temp.AsVIXLRegister(), sp, src.Int32Value() + 4);
+ asm_.StoreToOffset(kStoreWord, temp.AsVIXLRegister(), sp, dest.Int32Value() + 4);
+ }
+}
+
+void ArmVIXLJNIMacroAssembler::Copy(FrameOffset dest ATTRIBUTE_UNUSED,
+ ManagedRegister src_base ATTRIBUTE_UNUSED,
+ Offset src_offset ATTRIBUTE_UNUSED,
+ ManagedRegister mscratch ATTRIBUTE_UNUSED,
+ size_t size ATTRIBUTE_UNUSED) {
+ UNIMPLEMENTED(FATAL);
+}
+
+void ArmVIXLJNIMacroAssembler::Copy(ManagedRegister dest_base ATTRIBUTE_UNUSED,
+ Offset dest_offset ATTRIBUTE_UNUSED,
+ FrameOffset src ATTRIBUTE_UNUSED,
+ ManagedRegister mscratch ATTRIBUTE_UNUSED,
+ size_t size ATTRIBUTE_UNUSED) {
+ UNIMPLEMENTED(FATAL);
+}
+
+void ArmVIXLJNIMacroAssembler::Copy(FrameOffset dst ATTRIBUTE_UNUSED,
+ FrameOffset src_base ATTRIBUTE_UNUSED,
+ Offset src_offset ATTRIBUTE_UNUSED,
+ ManagedRegister mscratch ATTRIBUTE_UNUSED,
+ size_t size ATTRIBUTE_UNUSED) {
+ UNIMPLEMENTED(FATAL);
+}
+
+void ArmVIXLJNIMacroAssembler::Copy(ManagedRegister dest ATTRIBUTE_UNUSED,
+ Offset dest_offset ATTRIBUTE_UNUSED,
+ ManagedRegister src ATTRIBUTE_UNUSED,
+ Offset src_offset ATTRIBUTE_UNUSED,
+ ManagedRegister mscratch ATTRIBUTE_UNUSED,
+ size_t size ATTRIBUTE_UNUSED) {
+ UNIMPLEMENTED(FATAL);
+}
+
+void ArmVIXLJNIMacroAssembler::Copy(FrameOffset dst ATTRIBUTE_UNUSED,
+ Offset dest_offset ATTRIBUTE_UNUSED,
+ FrameOffset src ATTRIBUTE_UNUSED,
+ Offset src_offset ATTRIBUTE_UNUSED,
+ ManagedRegister scratch ATTRIBUTE_UNUSED,
+ size_t size ATTRIBUTE_UNUSED) {
+ UNIMPLEMENTED(FATAL);
+}
+
+static constexpr uint32_t kArmInstrMaxSizeInBytes = 4;
+
+void ArmVIXLJNIMacroAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
+ FrameOffset handle_scope_offset,
+ ManagedRegister min_reg,
+ bool null_allowed) {
+ ArmManagedRegister out_reg = mout_reg.AsArm();
+ ArmManagedRegister in_reg = min_reg.AsArm();
+ CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
+ CHECK(out_reg.IsCoreRegister()) << out_reg;
+ if (null_allowed) {
+ // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
+ // the address in the handle scope holding the reference.
+ // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
+ if (in_reg.IsNoRegister()) {
+ asm_.LoadFromOffset(kLoadWord,
+ out_reg.AsVIXLRegister(),
+ sp,
+ handle_scope_offset.Int32Value());
+ in_reg = out_reg;
+ }
+ ___ Cmp(in_reg.AsVIXLRegister(), 0);
+
+ if (asm_.ShifterOperandCanHold(ADD, handle_scope_offset.Int32Value(), kCcDontCare)) {
+ if (!out_reg.Equals(in_reg)) {
+ AssemblerAccurateScope guard(asm_.GetVIXLAssembler(),
+ 3 * kArmInstrMaxSizeInBytes,
+ CodeBufferCheckScope::kMaximumSize);
+ ___ it(eq, 0xc);
+ ___ mov(eq, out_reg.AsVIXLRegister(), 0);
+ asm_.AddConstantInIt(out_reg.AsVIXLRegister(), sp, handle_scope_offset.Int32Value(), ne);
+ } else {
+ AssemblerAccurateScope guard(asm_.GetVIXLAssembler(),
+ 2 * kArmInstrMaxSizeInBytes,
+ CodeBufferCheckScope::kMaximumSize);
+ ___ it(ne, 0x8);
+ asm_.AddConstantInIt(out_reg.AsVIXLRegister(), sp, handle_scope_offset.Int32Value(), ne);
+ }
+ } else {
+ // TODO: Implement this (old arm assembler would have crashed here).
+ UNIMPLEMENTED(FATAL);
+ }
+ } else {
+ asm_.AddConstant(out_reg.AsVIXLRegister(), sp, handle_scope_offset.Int32Value());
+ }
+}
+
+void ArmVIXLJNIMacroAssembler::CreateHandleScopeEntry(FrameOffset out_off,
+ FrameOffset handle_scope_offset,
+ ManagedRegister mscratch,
+ bool null_allowed) {
+ ArmManagedRegister scratch = mscratch.AsArm();
+ CHECK(scratch.IsCoreRegister()) << scratch;
+ if (null_allowed) {
+ asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), sp, handle_scope_offset.Int32Value());
+ // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
+ // the address in the handle scope holding the reference.
+ // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
+ ___ Cmp(scratch.AsVIXLRegister(), 0);
+
+ if (asm_.ShifterOperandCanHold(ADD, handle_scope_offset.Int32Value(), kCcDontCare)) {
+ AssemblerAccurateScope guard(asm_.GetVIXLAssembler(),
+ 2 * kArmInstrMaxSizeInBytes,
+ CodeBufferCheckScope::kMaximumSize);
+ ___ it(ne, 0x8);
+ asm_.AddConstantInIt(scratch.AsVIXLRegister(), sp, handle_scope_offset.Int32Value(), ne);
+ } else {
+ // TODO: Implement this (old arm assembler would have crashed here).
+ UNIMPLEMENTED(FATAL);
+ }
+ } else {
+ asm_.AddConstant(scratch.AsVIXLRegister(), sp, handle_scope_offset.Int32Value());
+ }
+ asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), sp, out_off.Int32Value());
+}
+
+void ArmVIXLJNIMacroAssembler::LoadReferenceFromHandleScope(
+ ManagedRegister mout_reg ATTRIBUTE_UNUSED,
+ ManagedRegister min_reg ATTRIBUTE_UNUSED) {
+ UNIMPLEMENTED(FATAL);
+}
+
+void ArmVIXLJNIMacroAssembler::VerifyObject(ManagedRegister src ATTRIBUTE_UNUSED,
+ bool could_be_null ATTRIBUTE_UNUSED) {
+ // TODO: not validating references.
+}
+
+void ArmVIXLJNIMacroAssembler::VerifyObject(FrameOffset src ATTRIBUTE_UNUSED,
+ bool could_be_null ATTRIBUTE_UNUSED) {
+ // TODO: not validating references.
+}
+
+void ArmVIXLJNIMacroAssembler::Call(ManagedRegister mbase,
+ Offset offset,
+ ManagedRegister mscratch) {
+ ArmManagedRegister base = mbase.AsArm();
+ ArmManagedRegister scratch = mscratch.AsArm();
+ CHECK(base.IsCoreRegister()) << base;
+ CHECK(scratch.IsCoreRegister()) << scratch;
+ asm_.LoadFromOffset(kLoadWord,
+ scratch.AsVIXLRegister(),
+ base.AsVIXLRegister(),
+ offset.Int32Value());
+ ___ Blx(scratch.AsVIXLRegister());
+ // TODO: place reference map on call.
+}
+
+void ArmVIXLJNIMacroAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
+ ArmManagedRegister scratch = mscratch.AsArm();
+ CHECK(scratch.IsCoreRegister()) << scratch;
+ // Call *(*(SP + base) + offset)
+ asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), sp, base.Int32Value());
+ asm_.LoadFromOffset(kLoadWord,
+ scratch.AsVIXLRegister(),
+ scratch.AsVIXLRegister(),
+ offset.Int32Value());
+ ___ Blx(scratch.AsVIXLRegister());
+ // TODO: place reference map on call
+}
+
+void ArmVIXLJNIMacroAssembler::CallFromThread(ThreadOffset32 offset ATTRIBUTE_UNUSED,
+ ManagedRegister scratch ATTRIBUTE_UNUSED) {
+ UNIMPLEMENTED(FATAL);
+}
+
+void ArmVIXLJNIMacroAssembler::GetCurrentThread(ManagedRegister mtr) {
+ ___ Mov(mtr.AsArm().AsVIXLRegister(), tr);
+}
+
+void ArmVIXLJNIMacroAssembler::GetCurrentThread(FrameOffset dest_offset,
+ ManagedRegister scratch ATTRIBUTE_UNUSED) {
+ asm_.StoreToOffset(kStoreWord, tr, sp, dest_offset.Int32Value());
+}
+
+void ArmVIXLJNIMacroAssembler::ExceptionPoll(ManagedRegister m_scratch, size_t stack_adjust) {
+ CHECK_ALIGNED(stack_adjust, kStackAlignment);
+ ArmManagedRegister scratch = m_scratch.AsArm();
+ exception_blocks_.emplace_back(
+ new ArmVIXLJNIMacroAssembler::ArmException(scratch, stack_adjust));
+ asm_.LoadFromOffset(kLoadWord,
+ scratch.AsVIXLRegister(),
+ tr,
+ Thread::ExceptionOffset<kArmPointerSize>().Int32Value());
+
+ ___ Cmp(scratch.AsVIXLRegister(), 0);
+ {
+ AssemblerAccurateScope guard(asm_.GetVIXLAssembler(),
+ kArmInstrMaxSizeInBytes,
+ CodeBufferCheckScope::kMaximumSize);
+ ___ b(ne, Narrow, exception_blocks_.back()->Entry());
+ }
+ // TODO: think about using CBNZ here.
+}
+
+void ArmVIXLJNIMacroAssembler::EmitExceptionPoll(
+ ArmVIXLJNIMacroAssembler::ArmException* exception) {
+ ___ Bind(exception->Entry());
+ if (exception->stack_adjust_ != 0) { // Fix up the frame.
+ DecreaseFrameSize(exception->stack_adjust_);
+ }
+ // Pass exception object as argument.
+ // Don't care about preserving r0 as this won't return.
+ ___ Mov(r0, exception->scratch_.AsVIXLRegister());
+ // TODO: check that exception->scratch_ is dead by this point.
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ vixl32::Register temp = temps.Acquire();
+ ___ Ldr(temp,
+ MemOperand(tr,
+ QUICK_ENTRYPOINT_OFFSET(kArmPointerSize, pDeliverException).Int32Value()));
+ ___ Blx(temp);
+}
+
+void ArmVIXLJNIMacroAssembler::MemoryBarrier(ManagedRegister scratch ATTRIBUTE_UNUSED) {
+ UNIMPLEMENTED(FATAL);
+}
+
+void ArmVIXLJNIMacroAssembler::Load(ArmManagedRegister
+ dest,
+ vixl32::Register base,
+ int32_t offset,
+ size_t size) {
+ if (dest.IsNoRegister()) {
+ CHECK_EQ(0u, size) << dest;
+ } else if (dest.IsCoreRegister()) {
+ CHECK_EQ(4u, size) << dest;
+ CHECK(!dest.AsVIXLRegister().Is(sp)) << dest;
+ ___ Ldr(dest.AsVIXLRegister(), MemOperand(base, offset));
+ } else if (dest.IsRegisterPair()) {
+ CHECK_EQ(8u, size) << dest;
+ ___ Ldr(dest.AsVIXLRegisterPairLow(), MemOperand(base, offset));
+ ___ Ldr(dest.AsVIXLRegisterPairHigh(), MemOperand(base, offset + 4));
+ } else if (dest.IsSRegister()) {
+ ___ Vldr(dest.AsVIXLSRegister(), MemOperand(base, offset));
+ } else {
+ CHECK(dest.IsDRegister()) << dest;
+ ___ Vldr(dest.AsVIXLDRegister(), MemOperand(base, offset));
+ }
+}
+
+} // namespace arm
+} // namespace art
diff --git a/compiler/utils/arm/jni_macro_assembler_arm_vixl.h b/compiler/utils/arm/jni_macro_assembler_arm_vixl.h
new file mode 100644
index 0000000..9fc683d
--- /dev/null
+++ b/compiler/utils/arm/jni_macro_assembler_arm_vixl.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_UTILS_ARM_JNI_MACRO_ASSEMBLER_ARM_VIXL_H_
+#define ART_COMPILER_UTILS_ARM_JNI_MACRO_ASSEMBLER_ARM_VIXL_H_
+
+#include "base/arena_containers.h"
+#include "base/logging.h"
+#include "constants_arm.h"
+#include "offsets.h"
+#include "utils/arm/assembler_arm_shared.h"
+#include "utils/arm/assembler_arm_vixl.h"
+#include "utils/arm/managed_register_arm.h"
+#include "utils/assembler.h"
+#include "utils/jni_macro_assembler.h"
+
+namespace art {
+namespace arm {
+
+class ArmVIXLJNIMacroAssembler FINAL
+ : public JNIMacroAssemblerFwd<ArmVIXLAssembler, PointerSize::k32> {
+ private:
+ class ArmException;
+ public:
+ explicit ArmVIXLJNIMacroAssembler(ArenaAllocator* arena)
+ : JNIMacroAssemblerFwd(arena),
+ exception_blocks_(arena->Adapter(kArenaAllocAssembler)) {}
+
+ virtual ~ArmVIXLJNIMacroAssembler() {}
+ void FinalizeCode() OVERRIDE;
+
+ //
+ // Overridden common assembler high-level functionality
+ //
+
+ // Emit code that will create an activation on the stack.
+ void BuildFrame(size_t frame_size,
+ ManagedRegister method_reg,
+ ArrayRef<const ManagedRegister> callee_save_regs,
+ const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
+
+ // Emit code that will remove an activation from the stack.
+ void RemoveFrame(size_t frame_size,
+ ArrayRef<const ManagedRegister> callee_save_regs) OVERRIDE;
+
+ void IncreaseFrameSize(size_t adjust) OVERRIDE;
+ void DecreaseFrameSize(size_t adjust) OVERRIDE;
+
+ // Store routines.
+ void Store(FrameOffset offs, ManagedRegister src, size_t size) OVERRIDE;
+ void StoreRef(FrameOffset dest, ManagedRegister src) OVERRIDE;
+ void StoreRawPtr(FrameOffset dest, ManagedRegister src) OVERRIDE;
+
+ void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister scratch) OVERRIDE;
+
+ void StoreStackOffsetToThread(ThreadOffset32 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister scratch) OVERRIDE;
+
+ void StoreStackPointerToThread(ThreadOffset32 thr_offs) OVERRIDE;
+
+ void StoreSpanning(FrameOffset dest,
+ ManagedRegister src,
+ FrameOffset in_off,
+ ManagedRegister scratch) OVERRIDE;
+
+ // Load routines.
+ void Load(ManagedRegister dest, FrameOffset src, size_t size) OVERRIDE;
+
+ void LoadFromThread(ManagedRegister dest,
+ ThreadOffset32 src,
+ size_t size) OVERRIDE;
+
+ void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
+
+ void LoadRef(ManagedRegister dest,
+ ManagedRegister base,
+ MemberOffset offs,
+ bool unpoison_reference) OVERRIDE;
+
+ void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE;
+
+ void LoadRawPtrFromThread(ManagedRegister dest, ThreadOffset32 offs) OVERRIDE;
+
+ // Copying routines.
+ void Move(ManagedRegister dest, ManagedRegister src, size_t size) OVERRIDE;
+
+ void CopyRawPtrFromThread(FrameOffset fr_offs,
+ ThreadOffset32 thr_offs,
+ ManagedRegister scratch) OVERRIDE;
+
+ void CopyRawPtrToThread(ThreadOffset32 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister scratch) OVERRIDE;
+
+ void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch) OVERRIDE;
+
+ void Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch, size_t size) OVERRIDE;
+
+ void Copy(FrameOffset dest,
+ ManagedRegister src_base,
+ Offset src_offset,
+ ManagedRegister scratch,
+ size_t size) OVERRIDE;
+
+ void Copy(ManagedRegister dest_base,
+ Offset dest_offset,
+ FrameOffset src,
+ ManagedRegister scratch,
+ size_t size) OVERRIDE;
+
+ void Copy(FrameOffset dest,
+ FrameOffset src_base,
+ Offset src_offset,
+ ManagedRegister scratch,
+ size_t size) OVERRIDE;
+
+ void Copy(ManagedRegister dest,
+ Offset dest_offset,
+ ManagedRegister src,
+ Offset src_offset,
+ ManagedRegister scratch,
+ size_t size) OVERRIDE;
+
+ void Copy(FrameOffset dest,
+ Offset dest_offset,
+ FrameOffset src,
+ Offset src_offset,
+ ManagedRegister scratch,
+ size_t size) OVERRIDE;
+
+ // Sign extension.
+ void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE;
+
+ // Zero extension.
+ void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE;
+
+ // Exploit fast access in managed code to Thread::Current().
+ void GetCurrentThread(ManagedRegister mtr) OVERRIDE;
+ void GetCurrentThread(FrameOffset dest_offset,
+ ManagedRegister scratch) OVERRIDE;
+
+ // Set up out_reg to hold a Object** into the handle scope, or to be null if the
+ // value is null and null_allowed. in_reg holds a possibly stale reference
+ // that can be used to avoid loading the handle scope entry to see if the value is
+ // null.
+ void CreateHandleScopeEntry(ManagedRegister out_reg,
+ FrameOffset handlescope_offset,
+ ManagedRegister in_reg,
+ bool null_allowed) OVERRIDE;
+
+ // Set up out_off to hold a Object** into the handle scope, or to be null if the
+ // value is null and null_allowed.
+ void CreateHandleScopeEntry(FrameOffset out_off,
+ FrameOffset handlescope_offset,
+ ManagedRegister scratch,
+ bool null_allowed) OVERRIDE;
+
+ // src holds a handle scope entry (Object**) load this into dst.
+ void LoadReferenceFromHandleScope(ManagedRegister dst,
+ ManagedRegister src) OVERRIDE;
+
+ // Heap::VerifyObject on src. In some cases (such as a reference to this) we
+ // know that src may not be null.
+ void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE;
+ void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE;
+
+ // Call to address held at [base+offset].
+ void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) OVERRIDE;
+ void Call(FrameOffset base, Offset offset, ManagedRegister scratch) OVERRIDE;
+ void CallFromThread(ThreadOffset32 offset, ManagedRegister scratch) OVERRIDE;
+
+ // Generate code to check if Thread::Current()->exception_ is non-null
+ // and branch to a ExceptionSlowPath if it is.
+ void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust);
+
+ void MemoryBarrier(ManagedRegister scratch) OVERRIDE;
+
+ void EmitExceptionPoll(ArmVIXLJNIMacroAssembler::ArmException *exception);
+ void Load(ArmManagedRegister dest, vixl32::Register base, int32_t offset, size_t size);
+
+ private:
+ class ArmException {
+ private:
+ ArmException(ArmManagedRegister scratch, size_t stack_adjust)
+ : scratch_(scratch), stack_adjust_(stack_adjust) {}
+
+ vixl32::Label* Entry() { return &exception_entry_; }
+
+ // Register used for passing Thread::Current()->exception_ .
+ const ArmManagedRegister scratch_;
+
+ // Stack adjust for ExceptionPool.
+ const size_t stack_adjust_;
+
+ vixl32::Label exception_entry_;
+
+ friend class ArmVIXLJNIMacroAssembler;
+ DISALLOW_COPY_AND_ASSIGN(ArmException);
+ };
+
+ // List of exception blocks to generate at the end of the code cache.
+ ArenaVector<std::unique_ptr<ArmVIXLJNIMacroAssembler::ArmException>> exception_blocks_;
+ // Used for testing.
+ friend class ArmVIXLAssemblerTest_VixlLoadFromOffset_Test;
+ friend class ArmVIXLAssemblerTest_VixlStoreToOffset_Test;
+};
+
+} // namespace arm
+} // namespace art
+
+#endif // ART_COMPILER_UTILS_ARM_JNI_MACRO_ASSEMBLER_ARM_VIXL_H_
diff --git a/compiler/utils/arm/managed_register_arm.h b/compiler/utils/arm/managed_register_arm.h
index 276db44..2be2d56 100644
--- a/compiler/utils/arm/managed_register_arm.h
+++ b/compiler/utils/arm/managed_register_arm.h
@@ -22,6 +22,12 @@
#include "debug/dwarf/register.h"
#include "utils/managed_register.h"
+// TODO(VIXL): Make VIXL compile with -Wshadow.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#include "aarch32/macro-assembler-aarch32.h"
+#pragma GCC diagnostic pop
+
namespace art {
namespace arm {
@@ -90,16 +96,31 @@
return static_cast<Register>(id_);
}
+ vixl::aarch32::Register AsVIXLRegister() const {
+ CHECK(IsCoreRegister());
+ return vixl::aarch32::Register(id_);
+ }
+
constexpr SRegister AsSRegister() const {
CHECK(IsSRegister());
return static_cast<SRegister>(id_ - kNumberOfCoreRegIds);
}
+ vixl::aarch32::SRegister AsVIXLSRegister() const {
+ CHECK(IsSRegister());
+ return vixl::aarch32::SRegister(id_ - kNumberOfCoreRegIds);
+ }
+
constexpr DRegister AsDRegister() const {
CHECK(IsDRegister());
return static_cast<DRegister>(id_ - kNumberOfCoreRegIds - kNumberOfSRegIds);
}
+ vixl::aarch32::DRegister AsVIXLDRegister() const {
+ CHECK(IsDRegister());
+ return vixl::aarch32::DRegister(id_ - kNumberOfCoreRegIds - kNumberOfSRegIds);
+ }
+
constexpr SRegister AsOverlappingDRegisterLow() const {
CHECK(IsOverlappingDRegister());
DRegister d_reg = AsDRegister();
@@ -128,12 +149,20 @@
return FromRegId(AllocIdLow()).AsCoreRegister();
}
+ vixl::aarch32::Register AsVIXLRegisterPairLow() const {
+ return vixl::aarch32::Register(AsRegisterPairLow());
+ }
+
constexpr Register AsRegisterPairHigh() const {
CHECK(IsRegisterPair());
// Appropriate mapping of register ids allows to use AllocIdHigh().
return FromRegId(AllocIdHigh()).AsCoreRegister();
}
+ vixl::aarch32::Register AsVIXLRegisterPairHigh() const {
+ return vixl::aarch32::Register(AsRegisterPairHigh());
+ }
+
constexpr bool IsCoreRegister() const {
CHECK(IsValidManagedRegister());
return (0 <= id_) && (id_ < kNumberOfCoreRegIds);
diff --git a/compiler/utils/assembler.cc b/compiler/utils/assembler.cc
index 81159e6..57f3b15 100644
--- a/compiler/utils/assembler.cc
+++ b/compiler/utils/assembler.cc
@@ -20,7 +20,6 @@
#include <vector>
#ifdef ART_ENABLE_CODEGEN_arm
-#include "arm/assembler_arm32.h"
#include "arm/assembler_thumb2.h"
#endif
#ifdef ART_ENABLE_CODEGEN_arm64
diff --git a/compiler/utils/assembler_thumb_test.cc b/compiler/utils/assembler_thumb_test.cc
index 9c9271d..367ed97 100644
--- a/compiler/utils/assembler_thumb_test.cc
+++ b/compiler/utils/assembler_thumb_test.cc
@@ -23,6 +23,10 @@
#include "gtest/gtest.h"
#include "utils/arm/assembler_thumb2.h"
+
+#include "jni/quick/calling_convention.h"
+#include "utils/arm/jni_macro_assembler_arm_vixl.h"
+
#include "base/hex_dump.h"
#include "common_runtime_test.h"
@@ -1608,6 +1612,196 @@
EmitAndCheck(&assembler, "CmpConstant");
}
+#define ENABLE_VIXL_TEST
+
+#ifdef ENABLE_VIXL_TEST
+
+#define ARM_VIXL
+
+#ifdef ARM_VIXL
+typedef arm::ArmVIXLJNIMacroAssembler JniAssemblerType;
+#else
+typedef arm::Thumb2Assembler AssemblerType;
+#endif
+
+class ArmVIXLAssemblerTest : public ::testing::Test {
+ public:
+ ArmVIXLAssemblerTest() : pool(), arena(&pool), assembler(&arena) { }
+
+ ArenaPool pool;
+ ArenaAllocator arena;
+ JniAssemblerType assembler;
+};
+
#undef __
+#define __ assembler->
+
+void EmitAndCheck(JniAssemblerType* assembler, const char* testname,
+ const char* const* results) {
+ __ FinalizeCode();
+ size_t cs = __ CodeSize();
+ std::vector<uint8_t> managed_code(cs);
+ MemoryRegion code(&managed_code[0], managed_code.size());
+ __ FinalizeInstructions(code);
+
+ DumpAndCheck(managed_code, testname, results);
+}
+
+void EmitAndCheck(JniAssemblerType* assembler, const char* testname) {
+ InitResults();
+ std::map<std::string, const char* const*>::iterator results = test_results.find(testname);
+ ASSERT_NE(results, test_results.end());
+
+ EmitAndCheck(assembler, testname, results->second);
+}
+
+#undef __
+#define __ assembler.
+
+TEST_F(ArmVIXLAssemblerTest, VixlJniHelpers) {
+ const bool is_static = true;
+ const bool is_synchronized = false;
+ const char* shorty = "IIFII";
+
+ ArenaPool pool;
+ ArenaAllocator arena(&pool);
+
+ std::unique_ptr<JniCallingConvention> jni_conv(
+ JniCallingConvention::Create(&arena, is_static, is_synchronized, shorty, kThumb2));
+ std::unique_ptr<ManagedRuntimeCallingConvention> mr_conv(
+ ManagedRuntimeCallingConvention::Create(&arena, is_static, is_synchronized, shorty, kThumb2));
+ const int frame_size(jni_conv->FrameSize());
+ ArrayRef<const ManagedRegister> callee_save_regs = jni_conv->CalleeSaveRegisters();
+
+ const ManagedRegister method_register = ArmManagedRegister::FromCoreRegister(R0);
+ const ManagedRegister scratch_register = ArmManagedRegister::FromCoreRegister(R12);
+
+ __ BuildFrame(frame_size, mr_conv->MethodRegister(), callee_save_regs, mr_conv->EntrySpills());
+ __ IncreaseFrameSize(32);
+
+ // Loads
+ __ IncreaseFrameSize(4096);
+ __ Load(method_register, FrameOffset(32), 4);
+ __ Load(method_register, FrameOffset(124), 4);
+ __ Load(method_register, FrameOffset(132), 4);
+ __ Load(method_register, FrameOffset(1020), 4);
+ __ Load(method_register, FrameOffset(1024), 4);
+ __ Load(scratch_register, FrameOffset(4092), 4);
+ __ Load(scratch_register, FrameOffset(4096), 4);
+ __ LoadRawPtrFromThread(scratch_register, ThreadOffset32(512));
+ __ LoadRef(method_register, scratch_register, MemberOffset(128), /* unpoison_reference */ false);
+
+ // Stores
+ __ Store(FrameOffset(32), method_register, 4);
+ __ Store(FrameOffset(124), method_register, 4);
+ __ Store(FrameOffset(132), method_register, 4);
+ __ Store(FrameOffset(1020), method_register, 4);
+ __ Store(FrameOffset(1024), method_register, 4);
+ __ Store(FrameOffset(4092), scratch_register, 4);
+ __ Store(FrameOffset(4096), scratch_register, 4);
+ __ StoreImmediateToFrame(FrameOffset(48), 0xFF, scratch_register);
+ __ StoreImmediateToFrame(FrameOffset(48), 0xFFFFFF, scratch_register);
+ __ StoreRawPtr(FrameOffset(48), scratch_register);
+ __ StoreRef(FrameOffset(48), scratch_register);
+ __ StoreSpanning(FrameOffset(48), method_register, FrameOffset(48), scratch_register);
+ __ StoreStackOffsetToThread(ThreadOffset32(512), FrameOffset(4096), scratch_register);
+ __ StoreStackPointerToThread(ThreadOffset32(512));
+
+ // Other
+ __ Call(method_register, FrameOffset(48), scratch_register);
+ __ Copy(FrameOffset(48), FrameOffset(44), scratch_register, 4);
+ __ CopyRawPtrFromThread(FrameOffset(44), ThreadOffset32(512), scratch_register);
+ __ CopyRef(FrameOffset(48), FrameOffset(44), scratch_register);
+ __ GetCurrentThread(method_register);
+ __ GetCurrentThread(FrameOffset(48), scratch_register);
+ __ Move(scratch_register, method_register, 4);
+ __ VerifyObject(scratch_register, false);
+
+ __ CreateHandleScopeEntry(scratch_register, FrameOffset(48), scratch_register, true);
+ __ CreateHandleScopeEntry(scratch_register, FrameOffset(48), scratch_register, false);
+ __ CreateHandleScopeEntry(method_register, FrameOffset(48), scratch_register, true);
+ __ CreateHandleScopeEntry(FrameOffset(48), FrameOffset(64), scratch_register, true);
+ __ CreateHandleScopeEntry(method_register, FrameOffset(0), scratch_register, true);
+ __ CreateHandleScopeEntry(method_register, FrameOffset(1025), scratch_register, true);
+ __ CreateHandleScopeEntry(scratch_register, FrameOffset(1025), scratch_register, true);
+
+ __ ExceptionPoll(scratch_register, 0);
+
+ __ DecreaseFrameSize(4096);
+ __ DecreaseFrameSize(32);
+ __ RemoveFrame(frame_size, callee_save_regs);
+
+ EmitAndCheck(&assembler, "VixlJniHelpers");
+}
+
+#ifdef ARM_VIXL
+#define R0 vixl::aarch32::r0
+#define R2 vixl::aarch32::r2
+#define R4 vixl::aarch32::r4
+#define R12 vixl::aarch32::r12
+#undef __
+#define __ assembler.asm_.
+#endif
+
+TEST_F(ArmVIXLAssemblerTest, VixlLoadFromOffset) {
+ __ LoadFromOffset(kLoadWord, R2, R4, 12);
+ __ LoadFromOffset(kLoadWord, R2, R4, 0xfff);
+ __ LoadFromOffset(kLoadWord, R2, R4, 0x1000);
+ __ LoadFromOffset(kLoadWord, R2, R4, 0x1000a4);
+ __ LoadFromOffset(kLoadWord, R2, R4, 0x101000);
+ __ LoadFromOffset(kLoadWord, R4, R4, 0x101000);
+ __ LoadFromOffset(kLoadUnsignedHalfword, R2, R4, 12);
+ __ LoadFromOffset(kLoadUnsignedHalfword, R2, R4, 0xfff);
+ __ LoadFromOffset(kLoadUnsignedHalfword, R2, R4, 0x1000);
+ __ LoadFromOffset(kLoadUnsignedHalfword, R2, R4, 0x1000a4);
+ __ LoadFromOffset(kLoadUnsignedHalfword, R2, R4, 0x101000);
+ __ LoadFromOffset(kLoadUnsignedHalfword, R4, R4, 0x101000);
+ __ LoadFromOffset(kLoadWordPair, R2, R4, 12);
+ __ LoadFromOffset(kLoadWordPair, R2, R4, 0x3fc);
+ __ LoadFromOffset(kLoadWordPair, R2, R4, 0x400);
+ __ LoadFromOffset(kLoadWordPair, R2, R4, 0x400a4);
+ __ LoadFromOffset(kLoadWordPair, R2, R4, 0x40400);
+ __ LoadFromOffset(kLoadWordPair, R4, R4, 0x40400);
+
+ __ LoadFromOffset(kLoadWord, R0, R12, 12); // 32-bit because of R12.
+ __ LoadFromOffset(kLoadWord, R2, R4, 0xa4 - 0x100000);
+
+ __ LoadFromOffset(kLoadSignedByte, R2, R4, 12);
+ __ LoadFromOffset(kLoadUnsignedByte, R2, R4, 12);
+ __ LoadFromOffset(kLoadSignedHalfword, R2, R4, 12);
+
+ EmitAndCheck(&assembler, "VixlLoadFromOffset");
+}
+
+TEST_F(ArmVIXLAssemblerTest, VixlStoreToOffset) {
+ __ StoreToOffset(kStoreWord, R2, R4, 12);
+ __ StoreToOffset(kStoreWord, R2, R4, 0xfff);
+ __ StoreToOffset(kStoreWord, R2, R4, 0x1000);
+ __ StoreToOffset(kStoreWord, R2, R4, 0x1000a4);
+ __ StoreToOffset(kStoreWord, R2, R4, 0x101000);
+ __ StoreToOffset(kStoreWord, R4, R4, 0x101000);
+ __ StoreToOffset(kStoreHalfword, R2, R4, 12);
+ __ StoreToOffset(kStoreHalfword, R2, R4, 0xfff);
+ __ StoreToOffset(kStoreHalfword, R2, R4, 0x1000);
+ __ StoreToOffset(kStoreHalfword, R2, R4, 0x1000a4);
+ __ StoreToOffset(kStoreHalfword, R2, R4, 0x101000);
+ __ StoreToOffset(kStoreHalfword, R4, R4, 0x101000);
+ __ StoreToOffset(kStoreWordPair, R2, R4, 12);
+ __ StoreToOffset(kStoreWordPair, R2, R4, 0x3fc);
+ __ StoreToOffset(kStoreWordPair, R2, R4, 0x400);
+ __ StoreToOffset(kStoreWordPair, R2, R4, 0x400a4);
+ __ StoreToOffset(kStoreWordPair, R2, R4, 0x40400);
+ __ StoreToOffset(kStoreWordPair, R4, R4, 0x40400);
+
+ __ StoreToOffset(kStoreWord, R0, R12, 12); // 32-bit because of R12.
+ __ StoreToOffset(kStoreWord, R2, R4, 0xa4 - 0x100000);
+
+ __ StoreToOffset(kStoreByte, R2, R4, 12);
+
+ EmitAndCheck(&assembler, "VixlStoreToOffset");
+}
+
+#undef __
+#endif // ENABLE_VIXL_TEST
} // namespace arm
} // namespace art
diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc
index 6736015..81c6ec5 100644
--- a/compiler/utils/assembler_thumb_test_expected.cc.inc
+++ b/compiler/utils/assembler_thumb_test_expected.cc.inc
@@ -5468,6 +5468,199 @@
nullptr
};
+const char* const VixlJniHelpersResults[] = {
+ " 0: e92d 4de0 stmdb sp!, {r5, r6, r7, r8, sl, fp, lr}\n",
+ " 4: ed2d 8a10 vpush {s16-s31}\n",
+ " 8: b089 sub sp, #36 ; 0x24\n",
+ " a: 9000 str r0, [sp, #0]\n",
+ " c: 9121 str r1, [sp, #132] ; 0x84\n",
+ " e: ed8d 0a22 vstr s0, [sp, #136] ; 0x88\n",
+ " 12: 9223 str r2, [sp, #140] ; 0x8c\n",
+ " 14: 9324 str r3, [sp, #144] ; 0x90\n",
+ " 16: b088 sub sp, #32\n",
+ " 18: f5ad 5d80 sub.w sp, sp, #4096 ; 0x1000\n",
+ " 1c: 9808 ldr r0, [sp, #32]\n",
+ " 1e: 981f ldr r0, [sp, #124] ; 0x7c\n",
+ " 20: 9821 ldr r0, [sp, #132] ; 0x84\n",
+ " 22: 98ff ldr r0, [sp, #1020] ; 0x3fc\n",
+ " 24: f8dd 0400 ldr.w r0, [sp, #1024] ; 0x400\n",
+ " 28: f8dd cffc ldr.w ip, [sp, #4092] ; 0xffc\n",
+ " 2c: f50d 5c80 add.w ip, sp, #4096 ; 0x1000\n",
+ " 30: f8dc c000 ldr.w ip, [ip]\n",
+ " 34: f8d9 c200 ldr.w ip, [r9, #512] ; 0x200\n",
+ " 38: f8dc 0080 ldr.w r0, [ip, #128] ; 0x80\n",
+ " 3c: 9008 str r0, [sp, #32]\n",
+ " 3e: 901f str r0, [sp, #124] ; 0x7c\n",
+ " 40: 9021 str r0, [sp, #132] ; 0x84\n",
+ " 42: 90ff str r0, [sp, #1020] ; 0x3fc\n",
+ " 44: f8cd 0400 str.w r0, [sp, #1024] ; 0x400\n",
+ " 48: f8cd cffc str.w ip, [sp, #4092] ; 0xffc\n",
+ " 4c: f84d 5d04 str.w r5, [sp, #-4]!\n",
+ " 50: f50d 5580 add.w r5, sp, #4096 ; 0x1000\n",
+ " 54: f8c5 c004 str.w ip, [r5, #4]\n",
+ " 58: f85d 5b04 ldr.w r5, [sp], #4\n",
+ " 5c: f04f 0cff mov.w ip, #255 ; 0xff\n",
+ " 60: f8cd c030 str.w ip, [sp, #48] ; 0x30\n",
+ " 64: f06f 4c7f mvn.w ip, #4278190080 ; 0xff000000\n",
+ " 68: f8cd c030 str.w ip, [sp, #48] ; 0x30\n",
+ " 6c: f8cd c030 str.w ip, [sp, #48] ; 0x30\n",
+ " 70: f8cd c030 str.w ip, [sp, #48] ; 0x30\n",
+ " 74: 900c str r0, [sp, #48] ; 0x30\n",
+ " 76: f8dd c030 ldr.w ip, [sp, #48] ; 0x30\n",
+ " 7a: f8cd c034 str.w ip, [sp, #52] ; 0x34\n",
+ " 7e: f50d 5c80 add.w ip, sp, #4096 ; 0x1000\n",
+ " 82: f8c9 c200 str.w ip, [r9, #512] ; 0x200\n",
+ " 86: f8c9 d200 str.w sp, [r9, #512] ; 0x200\n",
+ " 8a: f8d0 c030 ldr.w ip, [r0, #48] ; 0x30\n",
+ " 8e: 47e0 blx ip\n",
+ " 90: f8dd c02c ldr.w ip, [sp, #44] ; 0x2c\n",
+ " 94: f8cd c030 str.w ip, [sp, #48] ; 0x30\n",
+ " 98: f8d9 c200 ldr.w ip, [r9, #512] ; 0x200\n",
+ " 9c: f8cd c02c str.w ip, [sp, #44] ; 0x2c\n",
+ " a0: f8dd c02c ldr.w ip, [sp, #44] ; 0x2c\n",
+ " a4: f8cd c030 str.w ip, [sp, #48] ; 0x30\n",
+ " a8: 4648 mov r0, r9\n",
+ " aa: f8cd 9030 str.w r9, [sp, #48] ; 0x30\n",
+ " ae: 4684 mov ip, r0\n",
+ " b0: f1bc 0f00 cmp.w ip, #0\n",
+ " b4: bf18 it ne\n",
+ " b6: f10d 0c30 addne.w ip, sp, #48 ; 0x30\n",
+ " ba: f10d 0c30 add.w ip, sp, #48 ; 0x30\n",
+ " be: f1bc 0f00 cmp.w ip, #0\n",
+ " c2: bf0c ite eq\n",
+ " c4: 2000 moveq r0, #0\n",
+ " c6: a80c addne r0, sp, #48 ; 0x30\n",
+ " c8: f8dd c040 ldr.w ip, [sp, #64] ; 0x40\n",
+ " cc: f1bc 0f00 cmp.w ip, #0\n",
+ " d0: bf18 it ne\n",
+ " d2: f10d 0c40 addne.w ip, sp, #64 ; 0x40\n",
+ " d6: f8cd c030 str.w ip, [sp, #48] ; 0x30\n",
+ " da: f1bc 0f00 cmp.w ip, #0\n",
+ " de: bf0c ite eq\n",
+ " e0: 2000 moveq r0, #0\n",
+ " e2: 4668 movne r0, sp\n",
+ " e4: f1bc 0f00 cmp.w ip, #0\n",
+ " e8: bf0c ite eq\n",
+ " ea: 2000 moveq r0, #0\n",
+ " ec: f20d 4001 addwne r0, sp, #1025 ; 0x401\n",
+ " f0: f1bc 0f00 cmp.w ip, #0\n",
+ " f4: bf18 it ne\n",
+ " f6: f20d 4c01 addwne ip, sp, #1025 ; 0x401\n",
+ " fa: f8d9 c084 ldr.w ip, [r9, #132] ; 0x84\n",
+ " fe: f1bc 0f00 cmp.w ip, #0\n",
+ " 102: d107 bne.n 114 <VixlJniHelpers+0x114>\n",
+ " 104: f50d 5d80 add.w sp, sp, #4096 ; 0x1000\n",
+ " 108: b008 add sp, #32\n",
+ " 10a: b009 add sp, #36 ; 0x24\n",
+ " 10c: ecbd 8a10 vpop {s16-s31}\n",
+ " 110: e8bd 8de0 ldmia.w sp!, {r5, r6, r7, r8, sl, fp, pc}\n",
+ " 114: 4660 mov r0, ip\n",
+ " 116: f8d9 c2ac ldr.w ip, [r9, #684] ; 0x2ac\n",
+ " 11a: 47e0 blx ip\n",
+ nullptr
+};
+
+const char* const VixlLoadFromOffsetResults[] = {
+ " 0: 68e2 ldr r2, [r4, #12]\n",
+ " 2: f8d4 2fff ldr.w r2, [r4, #4095] ; 0xfff\n",
+ " 6: f504 5280 add.w r2, r4, #4096 ; 0x1000\n",
+ " a: 6812 ldr r2, [r2, #0]\n",
+ " c: f504 1280 add.w r2, r4, #1048576 ; 0x100000\n",
+ " 10: f8d2 20a4 ldr.w r2, [r2, #164] ; 0xa4\n",
+ " 14: f44f 5280 mov.w r2, #4096 ; 0x1000\n",
+ " 18: f2c0 0210 movt r2, #16\n",
+ " 1c: 4422 add r2, r4\n",
+ " 1e: 6812 ldr r2, [r2, #0]\n",
+ " 20: f44f 5c80 mov.w ip, #4096 ; 0x1000\n",
+ " 24: f2c0 0c10 movt ip, #16\n",
+ " 28: 4464 add r4, ip\n",
+ " 2a: 6824 ldr r4, [r4, #0]\n",
+ " 2c: 89a2 ldrh r2, [r4, #12]\n",
+ " 2e: f8b4 2fff ldrh.w r2, [r4, #4095] ; 0xfff\n",
+ " 32: f504 5280 add.w r2, r4, #4096 ; 0x1000\n",
+ " 36: 8812 ldrh r2, [r2, #0]\n",
+ " 38: f504 1280 add.w r2, r4, #1048576 ; 0x100000\n",
+ " 3c: f8b2 20a4 ldrh.w r2, [r2, #164] ; 0xa4\n",
+ " 40: f44f 5280 mov.w r2, #4096 ; 0x1000\n",
+ " 44: f2c0 0210 movt r2, #16\n",
+ " 48: 4422 add r2, r4\n",
+ " 4a: 8812 ldrh r2, [r2, #0]\n",
+ " 4c: f44f 5c80 mov.w ip, #4096 ; 0x1000\n",
+ " 50: f2c0 0c10 movt ip, #16\n",
+ " 54: 4464 add r4, ip\n",
+ " 56: 8824 ldrh r4, [r4, #0]\n",
+ " 58: e9d4 2303 ldrd r2, r3, [r4, #12]\n",
+ " 5c: e9d4 23ff ldrd r2, r3, [r4, #1020] ; 0x3fc\n",
+ " 60: f504 6280 add.w r2, r4, #1024 ; 0x400\n",
+ " 64: e9d2 2300 ldrd r2, r3, [r2]\n",
+ " 68: f504 2280 add.w r2, r4, #262144 ; 0x40000\n",
+ " 6c: e9d2 2329 ldrd r2, r3, [r2, #164] ; 0xa4\n",
+ " 70: f44f 6280 mov.w r2, #1024 ; 0x400\n",
+ " 74: f2c0 0204 movt r2, #4\n",
+ " 78: 4422 add r2, r4\n",
+ " 7a: e9d2 2300 ldrd r2, r3, [r2]\n",
+ " 7e: f44f 6c80 mov.w ip, #1024 ; 0x400\n",
+ " 82: f2c0 0c04 movt ip, #4\n",
+ " 86: 4464 add r4, ip\n",
+ " 88: e9d4 4500 ldrd r4, r5, [r4]\n",
+ " 8c: f8dc 000c ldr.w r0, [ip, #12]\n",
+ " 90: f5a4 1280 sub.w r2, r4, #1048576 ; 0x100000\n",
+ " 94: f8d2 20a4 ldr.w r2, [r2, #164] ; 0xa4\n",
+ " 98: f994 200c ldrsb.w r2, [r4, #12]\n",
+ " 9c: 7b22 ldrb r2, [r4, #12]\n",
+ " 9e: f9b4 200c ldrsh.w r2, [r4, #12]\n",
+ nullptr
+};
+const char* const VixlStoreToOffsetResults[] = {
+ " 0: 60e2 str r2, [r4, #12]\n",
+ " 2: f8c4 2fff str.w r2, [r4, #4095] ; 0xfff\n",
+ " 6: f504 5c80 add.w ip, r4, #4096 ; 0x1000\n",
+ " a: f8cc 2000 str.w r2, [ip]\n",
+ " e: f504 1c80 add.w ip, r4, #1048576 ; 0x100000\n",
+ " 12: f8cc 20a4 str.w r2, [ip, #164] ; 0xa4\n",
+ " 16: f44f 5c80 mov.w ip, #4096 ; 0x1000\n",
+ " 1a: f2c0 0c10 movt ip, #16\n",
+ " 1e: 44a4 add ip, r4\n",
+ " 20: f8cc 2000 str.w r2, [ip]\n",
+ " 24: f44f 5c80 mov.w ip, #4096 ; 0x1000\n",
+ " 28: f2c0 0c10 movt ip, #16\n",
+ " 2c: 44a4 add ip, r4\n",
+ " 2e: f8cc 4000 str.w r4, [ip]\n",
+ " 32: 81a2 strh r2, [r4, #12]\n",
+ " 34: f8a4 2fff strh.w r2, [r4, #4095] ; 0xfff\n",
+ " 38: f504 5c80 add.w ip, r4, #4096 ; 0x1000\n",
+ " 3c: f8ac 2000 strh.w r2, [ip]\n",
+ " 40: f504 1c80 add.w ip, r4, #1048576 ; 0x100000\n",
+ " 44: f8ac 20a4 strh.w r2, [ip, #164] ; 0xa4\n",
+ " 48: f44f 5c80 mov.w ip, #4096 ; 0x1000\n",
+ " 4c: f2c0 0c10 movt ip, #16\n",
+ " 50: 44a4 add ip, r4\n",
+ " 52: f8ac 2000 strh.w r2, [ip]\n",
+ " 56: f44f 5c80 mov.w ip, #4096 ; 0x1000\n",
+ " 5a: f2c0 0c10 movt ip, #16\n",
+ " 5e: 44a4 add ip, r4\n",
+ " 60: f8ac 4000 strh.w r4, [ip]\n",
+ " 64: e9c4 2303 strd r2, r3, [r4, #12]\n",
+ " 68: e9c4 23ff strd r2, r3, [r4, #1020] ; 0x3fc\n",
+ " 6c: f504 6c80 add.w ip, r4, #1024 ; 0x400\n",
+ " 70: e9cc 2300 strd r2, r3, [ip]\n",
+ " 74: f504 2c80 add.w ip, r4, #262144 ; 0x40000\n",
+ " 78: e9cc 2329 strd r2, r3, [ip, #164] ; 0xa4\n",
+ " 7c: f44f 6c80 mov.w ip, #1024 ; 0x400\n",
+ " 80: f2c0 0c04 movt ip, #4\n",
+ " 84: 44a4 add ip, r4\n",
+ " 86: e9cc 2300 strd r2, r3, [ip]\n",
+ " 8a: f44f 6c80 mov.w ip, #1024 ; 0x400\n",
+ " 8e: f2c0 0c04 movt ip, #4\n",
+ " 92: 44a4 add ip, r4\n",
+ " 94: e9cc 4500 strd r4, r5, [ip]\n",
+ " 98: f8cc 000c str.w r0, [ip, #12]\n",
+ " 9c: f5a4 1c80 sub.w ip, r4, #1048576 ; 0x100000\n",
+ " a0: f8cc 20a4 str.w r2, [ip, #164] ; 0xa4\n",
+ " a4: 7322 strb r2, [r4, #12]\n",
+ nullptr
+};
+
std::map<std::string, const char* const*> test_results;
void setup_results() {
test_results["SimpleMov"] = SimpleMovResults;
@@ -5520,4 +5713,7 @@
test_results["CompareAndBranch"] = CompareAndBranchResults;
test_results["AddConstant"] = AddConstantResults;
test_results["CmpConstant"] = CmpConstantResults;
+ test_results["VixlJniHelpers"] = VixlJniHelpersResults;
+ test_results["VixlStoreToOffset"] = VixlStoreToOffsetResults;
+ test_results["VixlLoadFromOffset"] = VixlLoadFromOffsetResults;
}
diff --git a/compiler/utils/jni_macro_assembler.cc b/compiler/utils/jni_macro_assembler.cc
index 1b74313..2f154fb 100644
--- a/compiler/utils/jni_macro_assembler.cc
+++ b/compiler/utils/jni_macro_assembler.cc
@@ -20,7 +20,7 @@
#include <vector>
#ifdef ART_ENABLE_CODEGEN_arm
-#include "arm/jni_macro_assembler_arm.h"
+#include "arm/jni_macro_assembler_arm_vixl.h"
#endif
#ifdef ART_ENABLE_CODEGEN_arm64
#include "arm64/jni_macro_assembler_arm64.h"
@@ -58,7 +58,7 @@
#ifdef ART_ENABLE_CODEGEN_arm
case kArm:
case kThumb2:
- return MacroAsm32UniquePtr(new (arena) arm::ArmJNIMacroAssembler(arena, instruction_set));
+ return MacroAsm32UniquePtr(new (arena) arm::ArmVIXLJNIMacroAssembler(arena));
#endif
#ifdef ART_ENABLE_CODEGEN_mips
case kMips:
diff --git a/compiler/utils/label.h b/compiler/utils/label.h
index 1038f44..0f82ad5 100644
--- a/compiler/utils/label.h
+++ b/compiler/utils/label.h
@@ -28,7 +28,6 @@
namespace arm {
class ArmAssembler;
- class Arm32Assembler;
class Thumb2Assembler;
}
namespace arm64 {
@@ -118,7 +117,6 @@
}
friend class arm::ArmAssembler;
- friend class arm::Arm32Assembler;
friend class arm::Thumb2Assembler;
friend class arm64::Arm64Assembler;
friend class mips::MipsAssembler;
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index 8b7da3f..bfc63d1 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -1407,44 +1407,6 @@
}
}
-void MipsAssembler::StoreConst32ToOffset(int32_t value,
- Register base,
- int32_t offset,
- Register temp) {
- CHECK_NE(temp, AT); // Must not use AT as temp, so as not to overwrite the adjusted base.
- AdjustBaseAndOffset(base, offset, /* is_doubleword */ false);
- if (value == 0) {
- temp = ZERO;
- } else {
- LoadConst32(temp, value);
- }
- Sw(temp, base, offset);
-}
-
-void MipsAssembler::StoreConst64ToOffset(int64_t value,
- Register base,
- int32_t offset,
- Register temp) {
- CHECK_NE(temp, AT); // Must not use AT as temp, so as not to overwrite the adjusted base.
- AdjustBaseAndOffset(base, offset, /* is_doubleword */ true);
- uint32_t low = Low32Bits(value);
- uint32_t high = High32Bits(value);
- if (low == 0) {
- Sw(ZERO, base, offset);
- } else {
- LoadConst32(temp, low);
- Sw(temp, base, offset);
- }
- if (high == 0) {
- Sw(ZERO, base, offset + kMipsWordSize);
- } else {
- if (high != low) {
- LoadConst32(temp, high);
- }
- Sw(temp, base, offset + kMipsWordSize);
- }
-}
-
void MipsAssembler::LoadSConst32(FRegister r, int32_t value, Register temp) {
if (value == 0) {
temp = ZERO;
@@ -2533,61 +2495,19 @@
CHECK_EQ(misalignment, offset & (kMipsDoublewordSize - 1));
}
-void MipsAssembler::LoadFromOffset(LoadOperandType type, Register reg, Register base,
+void MipsAssembler::LoadFromOffset(LoadOperandType type,
+ Register reg,
+ Register base,
int32_t offset) {
- AdjustBaseAndOffset(base, offset, /* is_doubleword */ (type == kLoadDoubleword));
- switch (type) {
- case kLoadSignedByte:
- Lb(reg, base, offset);
- break;
- case kLoadUnsignedByte:
- Lbu(reg, base, offset);
- break;
- case kLoadSignedHalfword:
- Lh(reg, base, offset);
- break;
- case kLoadUnsignedHalfword:
- Lhu(reg, base, offset);
- break;
- case kLoadWord:
- Lw(reg, base, offset);
- break;
- case kLoadDoubleword:
- if (reg == base) {
- // This will clobber the base when loading the lower register. Since we have to load the
- // higher register as well, this will fail. Solution: reverse the order.
- Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
- Lw(reg, base, offset);
- } else {
- Lw(reg, base, offset);
- Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
- }
- break;
- default:
- LOG(FATAL) << "UNREACHABLE";
- }
+ LoadFromOffset<>(type, reg, base, offset);
}
void MipsAssembler::LoadSFromOffset(FRegister reg, Register base, int32_t offset) {
- AdjustBaseAndOffset(base, offset, /* is_doubleword */ false, /* is_float */ true);
- Lwc1(reg, base, offset);
+ LoadSFromOffset<>(reg, base, offset);
}
void MipsAssembler::LoadDFromOffset(FRegister reg, Register base, int32_t offset) {
- AdjustBaseAndOffset(base, offset, /* is_doubleword */ true, /* is_float */ true);
- if (offset & 0x7) {
- if (Is32BitFPU()) {
- Lwc1(reg, base, offset);
- Lwc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize);
- } else {
- // 64-bit FPU.
- Lwc1(reg, base, offset);
- Lw(T8, base, offset + kMipsWordSize);
- Mthc1(T8, reg);
- }
- } else {
- Ldc1(reg, base, offset);
- }
+ LoadDFromOffset<>(reg, base, offset);
}
void MipsAssembler::EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset,
@@ -2611,53 +2531,19 @@
}
}
-void MipsAssembler::StoreToOffset(StoreOperandType type, Register reg, Register base,
+void MipsAssembler::StoreToOffset(StoreOperandType type,
+ Register reg,
+ Register base,
int32_t offset) {
- // Must not use AT as `reg`, so as not to overwrite the value being stored
- // with the adjusted `base`.
- CHECK_NE(reg, AT);
- AdjustBaseAndOffset(base, offset, /* is_doubleword */ (type == kStoreDoubleword));
- switch (type) {
- case kStoreByte:
- Sb(reg, base, offset);
- break;
- case kStoreHalfword:
- Sh(reg, base, offset);
- break;
- case kStoreWord:
- Sw(reg, base, offset);
- break;
- case kStoreDoubleword:
- CHECK_NE(reg, base);
- CHECK_NE(static_cast<Register>(reg + 1), base);
- Sw(reg, base, offset);
- Sw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
- break;
- default:
- LOG(FATAL) << "UNREACHABLE";
- }
+ StoreToOffset<>(type, reg, base, offset);
}
void MipsAssembler::StoreSToOffset(FRegister reg, Register base, int32_t offset) {
- AdjustBaseAndOffset(base, offset, /* is_doubleword */ false, /* is_float */ true);
- Swc1(reg, base, offset);
+ StoreSToOffset<>(reg, base, offset);
}
void MipsAssembler::StoreDToOffset(FRegister reg, Register base, int32_t offset) {
- AdjustBaseAndOffset(base, offset, /* is_doubleword */ true, /* is_float */ true);
- if (offset & 0x7) {
- if (Is32BitFPU()) {
- Swc1(reg, base, offset);
- Swc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize);
- } else {
- // 64-bit FPU.
- Mfhc1(T8, reg);
- Swc1(reg, base, offset);
- Sw(T8, base, offset + kMipsWordSize);
- }
- } else {
- Sdc1(reg, base, offset);
- }
+ StoreDToOffset<>(reg, base, offset);
}
static dwarf::Reg DWARFReg(Register reg) {
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index 41b6c6b..434ca67 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -412,8 +412,6 @@
void LoadConst64(Register reg_hi, Register reg_lo, int64_t value);
void LoadDConst64(FRegister rd, int64_t value, Register temp);
void LoadSConst32(FRegister r, int32_t value, Register temp);
- void StoreConst32ToOffset(int32_t value, Register base, int32_t offset, Register temp);
- void StoreConst64ToOffset(int64_t value, Register base, int32_t offset, Register temp);
void Addiu32(Register rt, Register rs, int32_t value, Register rtmp = AT);
// These will generate R2 branches or R6 branches as appropriate.
@@ -444,6 +442,204 @@
int32_t& offset,
bool is_doubleword,
bool is_float = false);
+
+ private:
+ struct NoImplicitNullChecker {
+ void operator()() {}
+ };
+
+ public:
+ template <typename ImplicitNullChecker = NoImplicitNullChecker>
+ void StoreConst32ToOffset(int32_t value,
+ Register base,
+ int32_t offset,
+ Register temp,
+ ImplicitNullChecker null_checker = NoImplicitNullChecker()) {
+ CHECK_NE(temp, AT); // Must not use AT as temp, so as not to overwrite the adjusted base.
+ AdjustBaseAndOffset(base, offset, /* is_doubleword */ false);
+ if (value == 0) {
+ temp = ZERO;
+ } else {
+ LoadConst32(temp, value);
+ }
+ Sw(temp, base, offset);
+ null_checker();
+ }
+
+ template <typename ImplicitNullChecker = NoImplicitNullChecker>
+ void StoreConst64ToOffset(int64_t value,
+ Register base,
+ int32_t offset,
+ Register temp,
+ ImplicitNullChecker null_checker = NoImplicitNullChecker()) {
+ CHECK_NE(temp, AT); // Must not use AT as temp, so as not to overwrite the adjusted base.
+ AdjustBaseAndOffset(base, offset, /* is_doubleword */ true);
+ uint32_t low = Low32Bits(value);
+ uint32_t high = High32Bits(value);
+ if (low == 0) {
+ Sw(ZERO, base, offset);
+ } else {
+ LoadConst32(temp, low);
+ Sw(temp, base, offset);
+ }
+ null_checker();
+ if (high == 0) {
+ Sw(ZERO, base, offset + kMipsWordSize);
+ } else {
+ if (high != low) {
+ LoadConst32(temp, high);
+ }
+ Sw(temp, base, offset + kMipsWordSize);
+ }
+ }
+
+ template <typename ImplicitNullChecker = NoImplicitNullChecker>
+ void LoadFromOffset(LoadOperandType type,
+ Register reg,
+ Register base,
+ int32_t offset,
+ ImplicitNullChecker null_checker = NoImplicitNullChecker()) {
+ AdjustBaseAndOffset(base, offset, /* is_doubleword */ (type == kLoadDoubleword));
+ switch (type) {
+ case kLoadSignedByte:
+ Lb(reg, base, offset);
+ break;
+ case kLoadUnsignedByte:
+ Lbu(reg, base, offset);
+ break;
+ case kLoadSignedHalfword:
+ Lh(reg, base, offset);
+ break;
+ case kLoadUnsignedHalfword:
+ Lhu(reg, base, offset);
+ break;
+ case kLoadWord:
+ Lw(reg, base, offset);
+ break;
+ case kLoadDoubleword:
+ if (reg == base) {
+ // This will clobber the base when loading the lower register. Since we have to load the
+ // higher register as well, this will fail. Solution: reverse the order.
+ Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
+ null_checker();
+ Lw(reg, base, offset);
+ } else {
+ Lw(reg, base, offset);
+ null_checker();
+ Lw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
+ }
+ break;
+ default:
+ LOG(FATAL) << "UNREACHABLE";
+ }
+ if (type != kLoadDoubleword) {
+ null_checker();
+ }
+ }
+
+ template <typename ImplicitNullChecker = NoImplicitNullChecker>
+ void LoadSFromOffset(FRegister reg,
+ Register base,
+ int32_t offset,
+ ImplicitNullChecker null_checker = NoImplicitNullChecker()) {
+ AdjustBaseAndOffset(base, offset, /* is_doubleword */ false, /* is_float */ true);
+ Lwc1(reg, base, offset);
+ null_checker();
+ }
+
+ template <typename ImplicitNullChecker = NoImplicitNullChecker>
+ void LoadDFromOffset(FRegister reg,
+ Register base,
+ int32_t offset,
+ ImplicitNullChecker null_checker = NoImplicitNullChecker()) {
+ AdjustBaseAndOffset(base, offset, /* is_doubleword */ true, /* is_float */ true);
+ if (IsAligned<kMipsDoublewordSize>(offset)) {
+ Ldc1(reg, base, offset);
+ null_checker();
+ } else {
+ if (Is32BitFPU()) {
+ Lwc1(reg, base, offset);
+ null_checker();
+ Lwc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize);
+ } else {
+ // 64-bit FPU.
+ Lwc1(reg, base, offset);
+ null_checker();
+ Lw(T8, base, offset + kMipsWordSize);
+ Mthc1(T8, reg);
+ }
+ }
+ }
+
+ template <typename ImplicitNullChecker = NoImplicitNullChecker>
+ void StoreToOffset(StoreOperandType type,
+ Register reg,
+ Register base,
+ int32_t offset,
+ ImplicitNullChecker null_checker = NoImplicitNullChecker()) {
+ // Must not use AT as `reg`, so as not to overwrite the value being stored
+ // with the adjusted `base`.
+ CHECK_NE(reg, AT);
+ AdjustBaseAndOffset(base, offset, /* is_doubleword */ (type == kStoreDoubleword));
+ switch (type) {
+ case kStoreByte:
+ Sb(reg, base, offset);
+ break;
+ case kStoreHalfword:
+ Sh(reg, base, offset);
+ break;
+ case kStoreWord:
+ Sw(reg, base, offset);
+ break;
+ case kStoreDoubleword:
+ CHECK_NE(reg, base);
+ CHECK_NE(static_cast<Register>(reg + 1), base);
+ Sw(reg, base, offset);
+ null_checker();
+ Sw(static_cast<Register>(reg + 1), base, offset + kMipsWordSize);
+ break;
+ default:
+ LOG(FATAL) << "UNREACHABLE";
+ }
+ if (type != kStoreDoubleword) {
+ null_checker();
+ }
+ }
+
+ template <typename ImplicitNullChecker = NoImplicitNullChecker>
+ void StoreSToOffset(FRegister reg,
+ Register base,
+ int32_t offset,
+ ImplicitNullChecker null_checker = NoImplicitNullChecker()) {
+ AdjustBaseAndOffset(base, offset, /* is_doubleword */ false, /* is_float */ true);
+ Swc1(reg, base, offset);
+ null_checker();
+ }
+
+ template <typename ImplicitNullChecker = NoImplicitNullChecker>
+ void StoreDToOffset(FRegister reg,
+ Register base,
+ int32_t offset,
+ ImplicitNullChecker null_checker = NoImplicitNullChecker()) {
+ AdjustBaseAndOffset(base, offset, /* is_doubleword */ true, /* is_float */ true);
+ if (IsAligned<kMipsDoublewordSize>(offset)) {
+ Sdc1(reg, base, offset);
+ null_checker();
+ } else {
+ if (Is32BitFPU()) {
+ Swc1(reg, base, offset);
+ null_checker();
+ Swc1(static_cast<FRegister>(reg + 1), base, offset + kMipsWordSize);
+ } else {
+ // 64-bit FPU.
+ Mfhc1(T8, reg);
+ Swc1(reg, base, offset);
+ null_checker();
+ Sw(T8, base, offset + kMipsWordSize);
+ }
+ }
+ }
+
void LoadFromOffset(LoadOperandType type, Register reg, Register base, int32_t offset);
void LoadSFromOffset(FRegister reg, Register base, int32_t offset);
void LoadDFromOffset(FRegister reg, Register base, int32_t offset);
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index a2621cb..1a21df9 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -1038,129 +1038,15 @@
}
void Mips64Assembler::LoadConst32(GpuRegister rd, int32_t value) {
- if (IsUint<16>(value)) {
- // Use OR with (unsigned) immediate to encode 16b unsigned int.
- Ori(rd, ZERO, value);
- } else if (IsInt<16>(value)) {
- // Use ADD with (signed) immediate to encode 16b signed int.
- Addiu(rd, ZERO, value);
- } else {
- Lui(rd, value >> 16);
- if (value & 0xFFFF)
- Ori(rd, rd, value);
- }
+ TemplateLoadConst32(this, rd, value);
+}
+
+// This function is only used for testing purposes.
+void Mips64Assembler::RecordLoadConst64Path(int value ATTRIBUTE_UNUSED) {
}
void Mips64Assembler::LoadConst64(GpuRegister rd, int64_t value) {
- int bit31 = (value & UINT64_C(0x80000000)) != 0;
-
- // Loads with 1 instruction.
- if (IsUint<16>(value)) {
- Ori(rd, ZERO, value);
- } else if (IsInt<16>(value)) {
- Daddiu(rd, ZERO, value);
- } else if ((value & 0xFFFF) == 0 && IsInt<16>(value >> 16)) {
- Lui(rd, value >> 16);
- } else if (IsInt<32>(value)) {
- // Loads with 2 instructions.
- Lui(rd, value >> 16);
- Ori(rd, rd, value);
- } else if ((value & 0xFFFF0000) == 0 && IsInt<16>(value >> 32)) {
- Ori(rd, ZERO, value);
- Dahi(rd, value >> 32);
- } else if ((value & UINT64_C(0xFFFFFFFF0000)) == 0) {
- Ori(rd, ZERO, value);
- Dati(rd, value >> 48);
- } else if ((value & 0xFFFF) == 0 &&
- (-32768 - bit31) <= (value >> 32) && (value >> 32) <= (32767 - bit31)) {
- Lui(rd, value >> 16);
- Dahi(rd, (value >> 32) + bit31);
- } else if ((value & 0xFFFF) == 0 && ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF)) {
- Lui(rd, value >> 16);
- Dati(rd, (value >> 48) + bit31);
- } else if (IsPowerOfTwo(value + UINT64_C(1))) {
- int shift_cnt = 64 - CTZ(value + UINT64_C(1));
- Daddiu(rd, ZERO, -1);
- if (shift_cnt < 32) {
- Dsrl(rd, rd, shift_cnt);
- } else {
- Dsrl32(rd, rd, shift_cnt & 31);
- }
- } else {
- int shift_cnt = CTZ(value);
- int64_t tmp = value >> shift_cnt;
- if (IsUint<16>(tmp)) {
- Ori(rd, ZERO, tmp);
- if (shift_cnt < 32) {
- Dsll(rd, rd, shift_cnt);
- } else {
- Dsll32(rd, rd, shift_cnt & 31);
- }
- } else if (IsInt<16>(tmp)) {
- Daddiu(rd, ZERO, tmp);
- if (shift_cnt < 32) {
- Dsll(rd, rd, shift_cnt);
- } else {
- Dsll32(rd, rd, shift_cnt & 31);
- }
- } else if (IsInt<32>(tmp)) {
- // Loads with 3 instructions.
- Lui(rd, tmp >> 16);
- Ori(rd, rd, tmp);
- if (shift_cnt < 32) {
- Dsll(rd, rd, shift_cnt);
- } else {
- Dsll32(rd, rd, shift_cnt & 31);
- }
- } else {
- shift_cnt = 16 + CTZ(value >> 16);
- tmp = value >> shift_cnt;
- if (IsUint<16>(tmp)) {
- Ori(rd, ZERO, tmp);
- if (shift_cnt < 32) {
- Dsll(rd, rd, shift_cnt);
- } else {
- Dsll32(rd, rd, shift_cnt & 31);
- }
- Ori(rd, rd, value);
- } else if (IsInt<16>(tmp)) {
- Daddiu(rd, ZERO, tmp);
- if (shift_cnt < 32) {
- Dsll(rd, rd, shift_cnt);
- } else {
- Dsll32(rd, rd, shift_cnt & 31);
- }
- Ori(rd, rd, value);
- } else {
- // Loads with 3-4 instructions.
- uint64_t tmp2 = value;
- bool used_lui = false;
- if (((tmp2 >> 16) & 0xFFFF) != 0 || (tmp2 & 0xFFFFFFFF) == 0) {
- Lui(rd, tmp2 >> 16);
- used_lui = true;
- }
- if ((tmp2 & 0xFFFF) != 0) {
- if (used_lui) {
- Ori(rd, rd, tmp2);
- } else {
- Ori(rd, ZERO, tmp2);
- }
- }
- if (bit31) {
- tmp2 += UINT64_C(0x100000000);
- }
- if (((tmp2 >> 32) & 0xFFFF) != 0) {
- Dahi(rd, tmp2 >> 32);
- }
- if (tmp2 & UINT64_C(0x800000000000)) {
- tmp2 += UINT64_C(0x1000000000000);
- }
- if ((tmp2 >> 48) != 0) {
- Dati(rd, tmp2 >> 48);
- }
- }
- }
- }
+ TemplateLoadConst64(this, rd, value);
}
void Mips64Assembler::Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp) {
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index a7d350c..6277b5d 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -33,6 +33,237 @@
namespace art {
namespace mips64 {
+enum LoadConst64Path {
+ kLoadConst64PathZero = 0x0,
+ kLoadConst64PathOri = 0x1,
+ kLoadConst64PathDaddiu = 0x2,
+ kLoadConst64PathLui = 0x4,
+ kLoadConst64PathLuiOri = 0x8,
+ kLoadConst64PathOriDahi = 0x10,
+ kLoadConst64PathOriDati = 0x20,
+ kLoadConst64PathLuiDahi = 0x40,
+ kLoadConst64PathLuiDati = 0x80,
+ kLoadConst64PathDaddiuDsrlX = 0x100,
+ kLoadConst64PathOriDsllX = 0x200,
+ kLoadConst64PathDaddiuDsllX = 0x400,
+ kLoadConst64PathLuiOriDsllX = 0x800,
+ kLoadConst64PathOriDsllXOri = 0x1000,
+ kLoadConst64PathDaddiuDsllXOri = 0x2000,
+ kLoadConst64PathDaddiuDahi = 0x4000,
+ kLoadConst64PathDaddiuDati = 0x8000,
+ kLoadConst64PathDinsu1 = 0x10000,
+ kLoadConst64PathDinsu2 = 0x20000,
+ kLoadConst64PathCatchAll = 0x40000,
+ kLoadConst64PathAllPaths = 0x7ffff,
+};
+
+template <typename Asm>
+void TemplateLoadConst32(Asm* a, GpuRegister rd, int32_t value) {
+ if (IsUint<16>(value)) {
+ // Use OR with (unsigned) immediate to encode 16b unsigned int.
+ a->Ori(rd, ZERO, value);
+ } else if (IsInt<16>(value)) {
+ // Use ADD with (signed) immediate to encode 16b signed int.
+ a->Addiu(rd, ZERO, value);
+ } else {
+ // Set 16 most significant bits of value. The "lui" instruction
+ // also clears the 16 least significant bits to zero.
+ a->Lui(rd, value >> 16);
+ if (value & 0xFFFF) {
+ // If the 16 least significant bits are non-zero, set them
+ // here.
+ a->Ori(rd, rd, value);
+ }
+ }
+}
+
+static inline int InstrCountForLoadReplicatedConst32(int64_t value) {
+ int32_t x = Low32Bits(value);
+ int32_t y = High32Bits(value);
+
+ if (x == y) {
+ return (IsUint<16>(x) || IsInt<16>(x) || ((x & 0xFFFF) == 0 && IsInt<16>(value >> 16))) ? 2 : 3;
+ }
+
+ return INT_MAX;
+}
+
+template <typename Asm, typename Rtype, typename Vtype>
+void TemplateLoadConst64(Asm* a, Rtype rd, Vtype value) {
+ int bit31 = (value & UINT64_C(0x80000000)) != 0;
+ int rep32_count = InstrCountForLoadReplicatedConst32(value);
+
+ // Loads with 1 instruction.
+ if (IsUint<16>(value)) {
+ // 64-bit value can be loaded as an unsigned 16-bit number.
+ a->RecordLoadConst64Path(kLoadConst64PathOri);
+ a->Ori(rd, ZERO, value);
+ } else if (IsInt<16>(value)) {
+ // 64-bit value can be loaded as an signed 16-bit number.
+ a->RecordLoadConst64Path(kLoadConst64PathDaddiu);
+ a->Daddiu(rd, ZERO, value);
+ } else if ((value & 0xFFFF) == 0 && IsInt<16>(value >> 16)) {
+ // 64-bit value can be loaded as an signed 32-bit number which has all
+ // of its 16 least significant bits set to zero.
+ a->RecordLoadConst64Path(kLoadConst64PathLui);
+ a->Lui(rd, value >> 16);
+ } else if (IsInt<32>(value)) {
+ // Loads with 2 instructions.
+ // 64-bit value can be loaded as an signed 32-bit number which has some
+ // or all of its 16 least significant bits set to one.
+ a->RecordLoadConst64Path(kLoadConst64PathLuiOri);
+ a->Lui(rd, value >> 16);
+ a->Ori(rd, rd, value);
+ } else if ((value & 0xFFFF0000) == 0 && IsInt<16>(value >> 32)) {
+ // 64-bit value which consists of an unsigned 16-bit value in its
+ // least significant 32-bits, and a signed 16-bit value in its
+ // most significant 32-bits.
+ a->RecordLoadConst64Path(kLoadConst64PathOriDahi);
+ a->Ori(rd, ZERO, value);
+ a->Dahi(rd, value >> 32);
+ } else if ((value & UINT64_C(0xFFFFFFFF0000)) == 0) {
+ // 64-bit value which consists of an unsigned 16-bit value in its
+ // least significant 48-bits, and a signed 16-bit value in its
+ // most significant 16-bits.
+ a->RecordLoadConst64Path(kLoadConst64PathOriDati);
+ a->Ori(rd, ZERO, value);
+ a->Dati(rd, value >> 48);
+ } else if ((value & 0xFFFF) == 0 &&
+ (-32768 - bit31) <= (value >> 32) && (value >> 32) <= (32767 - bit31)) {
+ // 16 LSBs (Least Significant Bits) all set to zero.
+ // 48 MSBs (Most Significant Bits) hold a signed 32-bit value.
+ a->RecordLoadConst64Path(kLoadConst64PathLuiDahi);
+ a->Lui(rd, value >> 16);
+ a->Dahi(rd, (value >> 32) + bit31);
+ } else if ((value & 0xFFFF) == 0 && ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF)) {
+ // 16 LSBs all set to zero.
+ // 48 MSBs hold a signed value which can't be represented by signed
+ // 32-bit number, and the middle 16 bits are all zero, or all one.
+ a->RecordLoadConst64Path(kLoadConst64PathLuiDati);
+ a->Lui(rd, value >> 16);
+ a->Dati(rd, (value >> 48) + bit31);
+ } else if (IsInt<16>(static_cast<int32_t>(value)) &&
+ (-32768 - bit31) <= (value >> 32) && (value >> 32) <= (32767 - bit31)) {
+ // 32 LSBs contain an unsigned 16-bit number.
+ // 32 MSBs contain a signed 16-bit number.
+ a->RecordLoadConst64Path(kLoadConst64PathDaddiuDahi);
+ a->Daddiu(rd, ZERO, value);
+ a->Dahi(rd, (value >> 32) + bit31);
+ } else if (IsInt<16>(static_cast<int32_t>(value)) &&
+ ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF)) {
+ // 48 LSBs contain an unsigned 16-bit number.
+ // 16 MSBs contain a signed 16-bit number.
+ a->RecordLoadConst64Path(kLoadConst64PathDaddiuDati);
+ a->Daddiu(rd, ZERO, value);
+ a->Dati(rd, (value >> 48) + bit31);
+ } else if (IsPowerOfTwo(value + UINT64_C(1))) {
+ // 64-bit values which have their "n" MSBs set to one, and their
+ // "64-n" LSBs set to zero. "n" must meet the restrictions 0 < n < 64.
+ int shift_cnt = 64 - CTZ(value + UINT64_C(1));
+ a->RecordLoadConst64Path(kLoadConst64PathDaddiuDsrlX);
+ a->Daddiu(rd, ZERO, -1);
+ if (shift_cnt < 32) {
+ a->Dsrl(rd, rd, shift_cnt);
+ } else {
+ a->Dsrl32(rd, rd, shift_cnt & 31);
+ }
+ } else {
+ int shift_cnt = CTZ(value);
+ int64_t tmp = value >> shift_cnt;
+ a->RecordLoadConst64Path(kLoadConst64PathOriDsllX);
+ if (IsUint<16>(tmp)) {
+ // Value can be computed by loading a 16-bit unsigned value, and
+ // then shifting left.
+ a->Ori(rd, ZERO, tmp);
+ if (shift_cnt < 32) {
+ a->Dsll(rd, rd, shift_cnt);
+ } else {
+ a->Dsll32(rd, rd, shift_cnt & 31);
+ }
+ } else if (IsInt<16>(tmp)) {
+ // Value can be computed by loading a 16-bit signed value, and
+ // then shifting left.
+ a->RecordLoadConst64Path(kLoadConst64PathDaddiuDsllX);
+ a->Daddiu(rd, ZERO, tmp);
+ if (shift_cnt < 32) {
+ a->Dsll(rd, rd, shift_cnt);
+ } else {
+ a->Dsll32(rd, rd, shift_cnt & 31);
+ }
+ } else if (rep32_count < 3) {
+ // Value being loaded has 32 LSBs equal to the 32 MSBs, and the
+ // value loaded into the 32 LSBs can be loaded with a single
+ // MIPS instruction.
+ a->LoadConst32(rd, value);
+ a->Dinsu(rd, rd, 32, 32);
+ a->RecordLoadConst64Path(kLoadConst64PathDinsu1);
+ } else if (IsInt<32>(tmp)) {
+ // Loads with 3 instructions.
+ // Value can be computed by loading a 32-bit signed value, and
+ // then shifting left.
+ a->RecordLoadConst64Path(kLoadConst64PathLuiOriDsllX);
+ a->Lui(rd, tmp >> 16);
+ a->Ori(rd, rd, tmp);
+ if (shift_cnt < 32) {
+ a->Dsll(rd, rd, shift_cnt);
+ } else {
+ a->Dsll32(rd, rd, shift_cnt & 31);
+ }
+ } else {
+ shift_cnt = 16 + CTZ(value >> 16);
+ tmp = value >> shift_cnt;
+ if (IsUint<16>(tmp)) {
+ // Value can be computed by loading a 16-bit unsigned value,
+ // shifting left, and "or"ing in another 16-bit unsigned value.
+ a->RecordLoadConst64Path(kLoadConst64PathOriDsllXOri);
+ a->Ori(rd, ZERO, tmp);
+ if (shift_cnt < 32) {
+ a->Dsll(rd, rd, shift_cnt);
+ } else {
+ a->Dsll32(rd, rd, shift_cnt & 31);
+ }
+ a->Ori(rd, rd, value);
+ } else if (IsInt<16>(tmp)) {
+ // Value can be computed by loading a 16-bit signed value,
+ // shifting left, and "or"ing in a 16-bit unsigned value.
+ a->RecordLoadConst64Path(kLoadConst64PathDaddiuDsllXOri);
+ a->Daddiu(rd, ZERO, tmp);
+ if (shift_cnt < 32) {
+ a->Dsll(rd, rd, shift_cnt);
+ } else {
+ a->Dsll32(rd, rd, shift_cnt & 31);
+ }
+ a->Ori(rd, rd, value);
+ } else if (rep32_count < 4) {
+ // Value being loaded has 32 LSBs equal to the 32 MSBs, and the
+ // value in the 32 LSBs requires 2 MIPS instructions to load.
+ a->LoadConst32(rd, value);
+ a->Dinsu(rd, rd, 32, 32);
+ a->RecordLoadConst64Path(kLoadConst64PathDinsu2);
+ } else {
+ // Loads with 3-4 instructions.
+ // Catch-all case to get any other 64-bit values which aren't
+ // handled by special cases above.
+ uint64_t tmp2 = value;
+ a->RecordLoadConst64Path(kLoadConst64PathCatchAll);
+ a->LoadConst32(rd, value);
+ if (bit31) {
+ tmp2 += UINT64_C(0x100000000);
+ }
+ if (((tmp2 >> 32) & 0xFFFF) != 0) {
+ a->Dahi(rd, tmp2 >> 32);
+ }
+ if (tmp2 & UINT64_C(0x800000000000)) {
+ tmp2 += UINT64_C(0x1000000000000);
+ }
+ if ((tmp2 >> 48) != 0) {
+ a->Dati(rd, tmp2 >> 48);
+ }
+ }
+ }
+ }
+}
+
static constexpr size_t kMips64WordSize = 4;
static constexpr size_t kMips64DoublewordSize = 8;
@@ -326,9 +557,13 @@
void Not(GpuRegister rd, GpuRegister rs);
// Higher level composite instructions.
+ int InstrCountForLoadReplicatedConst32(int64_t);
void LoadConst32(GpuRegister rd, int32_t value);
void LoadConst64(GpuRegister rd, int64_t value); // MIPS64
+ // This function is only used for testing purposes.
+ void RecordLoadConst64Path(int value);
+
void Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp = AT); // MIPS64
void Bind(Label* label) OVERRIDE {
diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc
index b758d64..1fdef96 100644
--- a/compiler/utils/mips64/assembler_mips64_test.cc
+++ b/compiler/utils/mips64/assembler_mips64_test.cc
@@ -1636,6 +1636,177 @@
DriverStr(expected, "StoreFpuToOffset");
}
+///////////////////////
+// Loading Constants //
+///////////////////////
+
+TEST_F(AssemblerMIPS64Test, LoadConst32) {
+ // IsUint<16>(value)
+ __ LoadConst32(mips64::V0, 0);
+ __ LoadConst32(mips64::V0, 65535);
+ // IsInt<16>(value)
+ __ LoadConst32(mips64::V0, -1);
+ __ LoadConst32(mips64::V0, -32768);
+ // Everything else
+ __ LoadConst32(mips64::V0, 65536);
+ __ LoadConst32(mips64::V0, 65537);
+ __ LoadConst32(mips64::V0, 2147483647);
+ __ LoadConst32(mips64::V0, -32769);
+ __ LoadConst32(mips64::V0, -65536);
+ __ LoadConst32(mips64::V0, -65537);
+ __ LoadConst32(mips64::V0, -2147483647);
+ __ LoadConst32(mips64::V0, -2147483648);
+
+ const char* expected =
+ // IsUint<16>(value)
+ "ori $v0, $zero, 0\n" // __ LoadConst32(mips64::V0, 0);
+ "ori $v0, $zero, 65535\n" // __ LoadConst32(mips64::V0, 65535);
+ // IsInt<16>(value)
+ "addiu $v0, $zero, -1\n" // __ LoadConst32(mips64::V0, -1);
+ "addiu $v0, $zero, -32768\n" // __ LoadConst32(mips64::V0, -32768);
+ // Everything else
+ "lui $v0, 1\n" // __ LoadConst32(mips64::V0, 65536);
+ "lui $v0, 1\n" // __ LoadConst32(mips64::V0, 65537);
+ "ori $v0, 1\n" // "
+ "lui $v0, 32767\n" // __ LoadConst32(mips64::V0, 2147483647);
+ "ori $v0, 65535\n" // "
+ "lui $v0, 65535\n" // __ LoadConst32(mips64::V0, -32769);
+ "ori $v0, 32767\n" // "
+ "lui $v0, 65535\n" // __ LoadConst32(mips64::V0, -65536);
+ "lui $v0, 65534\n" // __ LoadConst32(mips64::V0, -65537);
+ "ori $v0, 65535\n" // "
+ "lui $v0, 32768\n" // __ LoadConst32(mips64::V0, -2147483647);
+ "ori $v0, 1\n" // "
+ "lui $v0, 32768\n"; // __ LoadConst32(mips64::V0, -2147483648);
+ DriverStr(expected, "LoadConst32");
+}
+
+static uint64_t SignExtend16To64(uint16_t n) {
+ return static_cast<int16_t>(n);
+}
+
+// The art::mips64::Mips64Assembler::LoadConst64() method uses a template
+// to minimize the number of instructions needed to load a 64-bit constant
+// value into a register. The template calls various methods which emit
+// MIPS machine instructions. This struct (class) uses the same template
+// but overrides the definitions of the methods which emit MIPS instructions
+// to use methods which simulate the operation of the corresponding MIPS
+// instructions. After invoking LoadConst64() the target register should
+// contain the same 64-bit value as was input to LoadConst64(). If the
+// simulated register doesn't contain the correct value then there is probably
+// an error in the template function.
+struct LoadConst64Tester {
+ LoadConst64Tester() {
+ // Initialize all of the registers for simulation to zero.
+ for (int r = 0; r < 32; r++) {
+ regs_[r] = 0;
+ }
+ // Clear all of the path flags.
+ loadconst64_paths_ = art::mips64::kLoadConst64PathZero;
+ }
+ void Addiu(mips64::GpuRegister rd, mips64::GpuRegister rs, uint16_t c) {
+ regs_[rd] = static_cast<int32_t>(regs_[rs] + SignExtend16To64(c));
+ }
+ void Daddiu(mips64::GpuRegister rd, mips64::GpuRegister rs, uint16_t c) {
+ regs_[rd] = regs_[rs] + SignExtend16To64(c);
+ }
+ void Dahi(mips64::GpuRegister rd, uint16_t c) {
+ regs_[rd] += SignExtend16To64(c) << 32;
+ }
+ void Dati(mips64::GpuRegister rd, uint16_t c) {
+ regs_[rd] += SignExtend16To64(c) << 48;
+ }
+ void Dinsu(mips64::GpuRegister rt, mips64::GpuRegister rs, int pos, int size) {
+ CHECK(IsUint<5>(pos - 32)) << pos;
+ CHECK(IsUint<5>(size - 1)) << size;
+ CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size;
+ uint64_t src_mask = (UINT64_C(1) << size) - 1;
+ uint64_t dsk_mask = ~(src_mask << pos);
+
+ regs_[rt] = (regs_[rt] & dsk_mask) | ((regs_[rs] & src_mask) << pos);
+ }
+ void Dsll(mips64::GpuRegister rd, mips64::GpuRegister rt, int shamt) {
+ regs_[rd] = regs_[rt] << (shamt & 0x1f);
+ }
+ void Dsll32(mips64::GpuRegister rd, mips64::GpuRegister rt, int shamt) {
+ regs_[rd] = regs_[rt] << (32 + (shamt & 0x1f));
+ }
+ void Dsrl(mips64::GpuRegister rd, mips64::GpuRegister rt, int shamt) {
+ regs_[rd] = regs_[rt] >> (shamt & 0x1f);
+ }
+ void Dsrl32(mips64::GpuRegister rd, mips64::GpuRegister rt, int shamt) {
+ regs_[rd] = regs_[rt] >> (32 + (shamt & 0x1f));
+ }
+ void Lui(mips64::GpuRegister rd, uint16_t c) {
+ regs_[rd] = SignExtend16To64(c) << 16;
+ }
+ void Ori(mips64::GpuRegister rd, mips64::GpuRegister rs, uint16_t c) {
+ regs_[rd] = regs_[rs] | c;
+ }
+ void LoadConst32(mips64::GpuRegister rd, int32_t c) {
+ CHECK_NE(rd, 0);
+ mips64::TemplateLoadConst32<LoadConst64Tester>(this, rd, c);
+ CHECK_EQ(regs_[rd], static_cast<uint64_t>(c));
+ }
+ void LoadConst64(mips64::GpuRegister rd, int64_t c) {
+ CHECK_NE(rd, 0);
+ mips64::TemplateLoadConst64<LoadConst64Tester>(this, rd, c);
+ CHECK_EQ(regs_[rd], static_cast<uint64_t>(c));
+ }
+ uint64_t regs_[32];
+
+ // Getter function for loadconst64_paths_.
+ int GetPathsCovered() {
+ return loadconst64_paths_;
+ }
+
+ void RecordLoadConst64Path(int value) {
+ loadconst64_paths_ |= value;
+ }
+
+ private:
+ // This variable holds a bitmask to tell us which paths were taken
+ // through the template function which loads 64-bit values.
+ int loadconst64_paths_;
+};
+
+TEST_F(AssemblerMIPS64Test, LoadConst64) {
+ const uint16_t imms[] = {
+ 0, 1, 2, 3, 4, 0x33, 0x66, 0x55, 0x99, 0xaa, 0xcc, 0xff, 0x5500, 0x5555,
+ 0x7ffc, 0x7ffd, 0x7ffe, 0x7fff, 0x8000, 0x8001, 0x8002, 0x8003, 0x8004,
+ 0xaaaa, 0xfffc, 0xfffd, 0xfffe, 0xffff
+ };
+ unsigned d0, d1, d2, d3;
+ LoadConst64Tester tester;
+
+ union {
+ int64_t v64;
+ uint16_t v16[4];
+ } u;
+
+ for (d3 = 0; d3 < sizeof imms / sizeof imms[0]; d3++) {
+ u.v16[3] = imms[d3];
+
+ for (d2 = 0; d2 < sizeof imms / sizeof imms[0]; d2++) {
+ u.v16[2] = imms[d2];
+
+ for (d1 = 0; d1 < sizeof imms / sizeof imms[0]; d1++) {
+ u.v16[1] = imms[d1];
+
+ for (d0 = 0; d0 < sizeof imms / sizeof imms[0]; d0++) {
+ u.v16[0] = imms[d0];
+
+ tester.LoadConst64(mips64::V0, u.v64);
+ }
+ }
+ }
+ }
+
+ // Verify that we tested all paths through the "load 64-bit value"
+ // function template.
+ EXPECT_EQ(tester.GetPathsCovered(), art::mips64::kLoadConst64PathAllPaths);
+}
+
#undef __
} // namespace art
diff --git a/dex2oat/Android.mk b/dex2oat/Android.mk
index 37acef6..a9d00d3 100644
--- a/dex2oat/Android.mk
+++ b/dex2oat/Android.mk
@@ -65,12 +65,6 @@
liblog \
libz \
libbacktrace \
- libLLVMObject \
- libLLVMBitReader \
- libLLVMMC \
- libLLVMMCParser \
- libLLVMCore \
- libLLVMSupport \
libcutils \
libunwindbacktrace \
libutils \
@@ -82,14 +76,14 @@
ifeq ($(ART_BUILD_HOST_NDEBUG),true)
$(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libart-compiler libsigchain libziparchive-host liblz4,art/compiler,host,ndebug,$(dex2oat_host_arch)))
ifeq ($(ART_BUILD_HOST_STATIC),true)
- $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libart libart-compiler libart libvixl-arm64 $(DEX2OAT_STATIC_DEPENDENCIES),art/compiler,host,ndebug,$(dex2oat_host_arch),static))
+ $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libart libart-compiler libart libvixl-arm libvixl-arm64 $(DEX2OAT_STATIC_DEPENDENCIES),art/compiler,host,ndebug,$(dex2oat_host_arch),static))
endif
endif
ifeq ($(ART_BUILD_HOST_DEBUG),true)
$(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libartd-compiler libsigchain libziparchive-host liblz4,art/compiler,host,debug,$(dex2oat_host_arch)))
ifeq ($(ART_BUILD_HOST_STATIC),true)
- $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libartd libartd-compiler libartd libvixld-arm64 $(DEX2OAT_STATIC_DEPENDENCIES),art/compiler,host,debug,$(dex2oat_host_arch),static))
+ $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libartd libartd-compiler libartd libvixld-arm libvixld-arm64 $(DEX2OAT_STATIC_DEPENDENCIES),art/compiler,host,debug,$(dex2oat_host_arch),static))
endif
endif
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index cfcfe1c..febfb63 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -495,7 +495,7 @@
public:
explicit Dex2Oat(TimingLogger* timings) :
compiler_kind_(Compiler::kOptimizing),
- instruction_set_(kRuntimeISA),
+ instruction_set_(kRuntimeISA == kArm ? kThumb2 : kRuntimeISA),
// Take the default set of instruction features from the build.
image_file_location_oat_checksum_(0),
image_file_location_oat_data_begin_(0),
diff --git a/runtime/Android.bp b/runtime/Android.bp
new file mode 100644
index 0000000..012256e
--- /dev/null
+++ b/runtime/Android.bp
@@ -0,0 +1,461 @@
+//
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Keep the __jit_debug_register_code symbol as a unique symbol during ICF for architectures where
+// we use gold as the linker (arm, x86, x86_64). The symbol is used by the debuggers to detect when
+// new jit code is generated. We don't want it to be called when a different function with the same
+// (empty) body is called.
+JIT_DEBUG_REGISTER_CODE_LDFLAGS = ["-Wl,--keep-unique,__jit_debug_register_code"]
+
+cc_defaults {
+ name: "libart_defaults",
+ defaults: ["art_defaults"],
+ host_supported: true,
+ srcs: [
+ "art_field.cc",
+ "art_method.cc",
+ "atomic.cc",
+ "barrier.cc",
+ "base/allocator.cc",
+ "base/arena_allocator.cc",
+ "base/arena_bit_vector.cc",
+ "base/bit_vector.cc",
+ "base/file_magic.cc",
+ "base/hex_dump.cc",
+ "base/logging.cc",
+ "base/mutex.cc",
+ "base/scoped_arena_allocator.cc",
+ "base/scoped_flock.cc",
+ "base/stringpiece.cc",
+ "base/stringprintf.cc",
+ "base/time_utils.cc",
+ "base/timing_logger.cc",
+ "base/unix_file/fd_file.cc",
+ "base/unix_file/random_access_file_utils.cc",
+ "check_jni.cc",
+ "class_linker.cc",
+ "class_table.cc",
+ "code_simulator_container.cc",
+ "common_throws.cc",
+ "compiler_filter.cc",
+ "debugger.cc",
+ "dex_file.cc",
+ "dex_file_verifier.cc",
+ "dex_instruction.cc",
+ "elf_file.cc",
+ "fault_handler.cc",
+ "gc/allocation_record.cc",
+ "gc/allocator/dlmalloc.cc",
+ "gc/allocator/rosalloc.cc",
+ "gc/accounting/bitmap.cc",
+ "gc/accounting/card_table.cc",
+ "gc/accounting/heap_bitmap.cc",
+ "gc/accounting/mod_union_table.cc",
+ "gc/accounting/remembered_set.cc",
+ "gc/accounting/space_bitmap.cc",
+ "gc/collector/concurrent_copying.cc",
+ "gc/collector/garbage_collector.cc",
+ "gc/collector/immune_region.cc",
+ "gc/collector/immune_spaces.cc",
+ "gc/collector/mark_compact.cc",
+ "gc/collector/mark_sweep.cc",
+ "gc/collector/partial_mark_sweep.cc",
+ "gc/collector/semi_space.cc",
+ "gc/collector/sticky_mark_sweep.cc",
+ "gc/gc_cause.cc",
+ "gc/heap.cc",
+ "gc/reference_processor.cc",
+ "gc/reference_queue.cc",
+ "gc/scoped_gc_critical_section.cc",
+ "gc/space/bump_pointer_space.cc",
+ "gc/space/dlmalloc_space.cc",
+ "gc/space/image_space.cc",
+ "gc/space/large_object_space.cc",
+ "gc/space/malloc_space.cc",
+ "gc/space/region_space.cc",
+ "gc/space/rosalloc_space.cc",
+ "gc/space/space.cc",
+ "gc/space/zygote_space.cc",
+ "gc/task_processor.cc",
+ "hprof/hprof.cc",
+ "image.cc",
+ "indirect_reference_table.cc",
+ "instrumentation.cc",
+ "intern_table.cc",
+ "interpreter/interpreter.cc",
+ "interpreter/interpreter_common.cc",
+ "interpreter/interpreter_goto_table_impl.cc",
+ "interpreter/interpreter_switch_impl.cc",
+ "interpreter/unstarted_runtime.cc",
+ "java_vm_ext.cc",
+ "jdwp/jdwp_event.cc",
+ "jdwp/jdwp_expand_buf.cc",
+ "jdwp/jdwp_handler.cc",
+ "jdwp/jdwp_main.cc",
+ "jdwp/jdwp_request.cc",
+ "jdwp/jdwp_socket.cc",
+ "jdwp/object_registry.cc",
+ "jni_env_ext.cc",
+ "jit/debugger_interface.cc",
+ "jit/jit.cc",
+ "jit/jit_code_cache.cc",
+ "jit/offline_profiling_info.cc",
+ "jit/profiling_info.cc",
+ "jit/profile_saver.cc",
+ "jni_internal.cc",
+ "jobject_comparator.cc",
+ "linear_alloc.cc",
+ "mem_map.cc",
+ "memory_region.cc",
+ "mirror/abstract_method.cc",
+ "mirror/array.cc",
+ "mirror/class.cc",
+ "mirror/dex_cache.cc",
+ "mirror/field.cc",
+ "mirror/method.cc",
+ "mirror/object.cc",
+ "mirror/reference.cc",
+ "mirror/stack_trace_element.cc",
+ "mirror/string.cc",
+ "mirror/throwable.cc",
+ "monitor.cc",
+ "native_bridge_art_interface.cc",
+ "native_stack_dump.cc",
+ "native/dalvik_system_DexFile.cc",
+ "native/dalvik_system_VMDebug.cc",
+ "native/dalvik_system_VMRuntime.cc",
+ "native/dalvik_system_VMStack.cc",
+ "native/dalvik_system_ZygoteHooks.cc",
+ "native/java_lang_Class.cc",
+ "native/java_lang_DexCache.cc",
+ "native/java_lang_Object.cc",
+ "native/java_lang_String.cc",
+ "native/java_lang_StringFactory.cc",
+ "native/java_lang_System.cc",
+ "native/java_lang_Thread.cc",
+ "native/java_lang_Throwable.cc",
+ "native/java_lang_VMClassLoader.cc",
+ "native/java_lang_ref_FinalizerReference.cc",
+ "native/java_lang_ref_Reference.cc",
+ "native/java_lang_reflect_AbstractMethod.cc",
+ "native/java_lang_reflect_Array.cc",
+ "native/java_lang_reflect_Constructor.cc",
+ "native/java_lang_reflect_Field.cc",
+ "native/java_lang_reflect_Method.cc",
+ "native/java_lang_reflect_Proxy.cc",
+ "native/java_util_concurrent_atomic_AtomicLong.cc",
+ "native/libcore_util_CharsetUtils.cc",
+ "native/org_apache_harmony_dalvik_ddmc_DdmServer.cc",
+ "native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc",
+ "native/sun_misc_Unsafe.cc",
+ "oat.cc",
+ "oat_file.cc",
+ "oat_file_assistant.cc",
+ "oat_file_manager.cc",
+ "oat_quick_method_header.cc",
+ "object_lock.cc",
+ "offsets.cc",
+ "os_linux.cc",
+ "parsed_options.cc",
+ "plugin.cc",
+ "primitive.cc",
+ "quick_exception_handler.cc",
+ "quick/inline_method_analyser.cc",
+ "reference_table.cc",
+ "reflection.cc",
+ "runtime.cc",
+ "runtime_options.cc",
+ "signal_catcher.cc",
+ "stack.cc",
+ "stack_map.cc",
+ "thread.cc",
+ "thread_list.cc",
+ "thread_pool.cc",
+ "ti/agent.cc",
+ "trace.cc",
+ "transaction.cc",
+ "type_lookup_table.cc",
+ "utf.cc",
+ "utils.cc",
+ "verifier/instruction_flags.cc",
+ "verifier/method_verifier.cc",
+ "verifier/reg_type.cc",
+ "verifier/reg_type_cache.cc",
+ "verifier/register_line.cc",
+ "well_known_classes.cc",
+ "zip_archive.cc",
+
+ "arch/context.cc",
+ "arch/instruction_set.cc",
+ "arch/instruction_set_features.cc",
+ "arch/memcmp16.cc",
+ "arch/arm/instruction_set_features_arm.cc",
+ "arch/arm/registers_arm.cc",
+ "arch/arm64/instruction_set_features_arm64.cc",
+ "arch/arm64/registers_arm64.cc",
+ "arch/mips/instruction_set_features_mips.cc",
+ "arch/mips/registers_mips.cc",
+ "arch/mips64/instruction_set_features_mips64.cc",
+ "arch/mips64/registers_mips64.cc",
+ "arch/x86/instruction_set_features_x86.cc",
+ "arch/x86/registers_x86.cc",
+ "arch/x86_64/registers_x86_64.cc",
+ "entrypoints/entrypoint_utils.cc",
+ "entrypoints/jni/jni_entrypoints.cc",
+ "entrypoints/math_entrypoints.cc",
+ "entrypoints/quick/quick_alloc_entrypoints.cc",
+ "entrypoints/quick/quick_cast_entrypoints.cc",
+ "entrypoints/quick/quick_deoptimization_entrypoints.cc",
+ "entrypoints/quick/quick_dexcache_entrypoints.cc",
+ "entrypoints/quick/quick_field_entrypoints.cc",
+ "entrypoints/quick/quick_fillarray_entrypoints.cc",
+ "entrypoints/quick/quick_instrumentation_entrypoints.cc",
+ "entrypoints/quick/quick_jni_entrypoints.cc",
+ "entrypoints/quick/quick_lock_entrypoints.cc",
+ "entrypoints/quick/quick_math_entrypoints.cc",
+ "entrypoints/quick/quick_thread_entrypoints.cc",
+ "entrypoints/quick/quick_throw_entrypoints.cc",
+ "entrypoints/quick/quick_trampoline_entrypoints.cc",
+ ],
+
+ arch: {
+ arm: {
+ clang_asflags: ["-no-integrated-as"],
+ srcs: [
+ "interpreter/mterp/mterp.cc",
+ "interpreter/mterp/out/mterp_arm.S",
+ "arch/arm/context_arm.cc",
+ "arch/arm/entrypoints_init_arm.cc",
+ "arch/arm/instruction_set_features_assembly_tests.S",
+ "arch/arm/jni_entrypoints_arm.S",
+ "arch/arm/memcmp16_arm.S",
+ "arch/arm/quick_entrypoints_arm.S",
+ "arch/arm/quick_entrypoints_cc_arm.cc",
+ "arch/arm/thread_arm.cc",
+ "arch/arm/fault_handler_arm.cc",
+ ],
+ },
+ arm64: {
+ srcs: [
+ "interpreter/mterp/mterp.cc",
+ "interpreter/mterp/out/mterp_arm64.S",
+ "arch/arm64/context_arm64.cc",
+ "arch/arm64/entrypoints_init_arm64.cc",
+ "arch/arm64/jni_entrypoints_arm64.S",
+ "arch/arm64/memcmp16_arm64.S",
+ "arch/arm64/quick_entrypoints_arm64.S",
+ "arch/arm64/thread_arm64.cc",
+ "monitor_pool.cc",
+ "arch/arm64/fault_handler_arm64.cc",
+ ],
+ },
+ x86: {
+ srcs: [
+ "interpreter/mterp/mterp.cc",
+ "interpreter/mterp/out/mterp_x86.S",
+ "arch/x86/context_x86.cc",
+ "arch/x86/entrypoints_init_x86.cc",
+ "arch/x86/jni_entrypoints_x86.S",
+ "arch/x86/memcmp16_x86.S",
+ "arch/x86/quick_entrypoints_x86.S",
+ "arch/x86/thread_x86.cc",
+ "arch/x86/fault_handler_x86.cc",
+ ],
+ },
+ x86_64: {
+ srcs: [
+ // Note that the fault_handler_x86.cc is not a mistake. This file is
+ // shared between the x86 and x86_64 architectures.
+ "interpreter/mterp/mterp.cc",
+ "interpreter/mterp/out/mterp_x86_64.S",
+ "arch/x86_64/context_x86_64.cc",
+ "arch/x86_64/entrypoints_init_x86_64.cc",
+ "arch/x86_64/jni_entrypoints_x86_64.S",
+ "arch/x86_64/memcmp16_x86_64.S",
+ "arch/x86_64/quick_entrypoints_x86_64.S",
+ "arch/x86_64/thread_x86_64.cc",
+ "monitor_pool.cc",
+ "arch/x86/fault_handler_x86.cc",
+ ],
+ },
+ mips: {
+ srcs: [
+ "interpreter/mterp/mterp.cc",
+ "interpreter/mterp/out/mterp_mips.S",
+ "arch/mips/context_mips.cc",
+ "arch/mips/entrypoints_init_mips.cc",
+ "arch/mips/jni_entrypoints_mips.S",
+ "arch/mips/memcmp16_mips.S",
+ "arch/mips/quick_entrypoints_mips.S",
+ "arch/mips/thread_mips.cc",
+ "arch/mips/fault_handler_mips.cc",
+ ],
+ },
+ mips64: {
+ srcs: [
+ "interpreter/mterp/mterp.cc",
+ "interpreter/mterp/out/mterp_mips64.S",
+ "arch/mips64/context_mips64.cc",
+ "arch/mips64/entrypoints_init_mips64.cc",
+ "arch/mips64/jni_entrypoints_mips64.S",
+ "arch/mips64/memcmp16_mips64.S",
+ "arch/mips64/quick_entrypoints_mips64.S",
+ "arch/mips64/thread_mips64.cc",
+ "monitor_pool.cc",
+ "arch/mips64/fault_handler_mips64.cc",
+ ],
+ },
+ },
+ target: {
+ android: {
+ srcs: [
+ "jdwp/jdwp_adb.cc",
+ "monitor_android.cc",
+ "runtime_android.cc",
+ "thread_android.cc",
+ ],
+ shared_libs: [
+ "libdl",
+ // For android::FileMap used by libziparchive.
+ "libutils",
+ ],
+ static_libs: [
+ // ZipArchive support, the order matters here to get all symbols.
+ "libziparchive",
+ "libz",
+ "libbase",
+ ],
+ },
+ android_arm: {
+ ldflags: JIT_DEBUG_REGISTER_CODE_LDFLAGS,
+ },
+ android_arm64: {
+ ldflags: JIT_DEBUG_REGISTER_CODE_LDFLAGS,
+ },
+ android_x86: {
+ ldflags: JIT_DEBUG_REGISTER_CODE_LDFLAGS,
+ },
+ android_x86_64: {
+ ldflags: JIT_DEBUG_REGISTER_CODE_LDFLAGS,
+ },
+ host: {
+ srcs: [
+ "monitor_linux.cc",
+ "runtime_linux.cc",
+ "thread_linux.cc",
+ ],
+ shared_libs: [
+ "libziparchive",
+ "libz-host",
+ ],
+ },
+ },
+ cflags: ["-DBUILDING_LIBART=1"],
+ generated_sources: ["art_operator_srcs"],
+ clang: true,
+ include_dirs: [
+ "art/cmdline",
+ "art/sigchainlib",
+ "art",
+ ],
+ shared_libs: [
+ "libnativehelper",
+ "libnativebridge",
+ "libnativeloader",
+ "libbacktrace",
+ "liblz4",
+ // For liblog, atrace, properties, ashmem, set_sched_policy and socket_peer_is_trusted.
+ "libcutils",
+ ],
+ static: {
+ static_libs: ["libsigchain_dummy"],
+ },
+ shared: {
+ shared_libs: ["libsigchain"],
+ },
+ export_include_dirs: ["."],
+}
+
+gensrcs {
+ name: "art_operator_srcs",
+ cmd: "art/tools/generate-operator-out.py art/runtime $in > $out",
+ srcs: [
+ "arch/instruction_set.h",
+ "base/allocator.h",
+ "base/enums.h",
+ "base/mutex.h",
+ "debugger.h",
+ "base/unix_file/fd_file.h",
+ "dex_file.h",
+ "dex_instruction.h",
+ "dex_instruction_utils.h",
+ "gc_root.h",
+ "gc/allocator_type.h",
+ "gc/allocator/rosalloc.h",
+ "gc/collector_type.h",
+ "gc/collector/gc_type.h",
+ "gc/heap.h",
+ "gc/space/region_space.h",
+ "gc/space/space.h",
+ "gc/weak_root_state.h",
+ "image.h",
+ "instrumentation.h",
+ "indirect_reference_table.h",
+ "invoke_type.h",
+ "jdwp/jdwp.h",
+ "jdwp/jdwp_constants.h",
+ "lock_word.h",
+ "mirror/class.h",
+ "oat.h",
+ "object_callbacks.h",
+ "process_state.h",
+ "quick/inline_method_analyser.h",
+ "runtime.h",
+ "stack.h",
+ "thread.h",
+ "thread_state.h",
+ "ti/agent.h",
+ "verifier/method_verifier.h",
+ ],
+ output_extension: "operator_out.cc",
+}
+
+// We always build dex2oat and dependencies, even if the host build is otherwise disabled, since
+// they are used to cross compile for the target.
+
+art_cc_library {
+ name: "libart",
+ defaults: ["libart_defaults"],
+}
+
+art_cc_library {
+ name: "libartd",
+ defaults: [
+ "libart_defaults",
+ "art_debug_defaults",
+ ],
+ // Leave the symbols in the shared library so that stack unwinders can
+ // produce meaningful name resolution.
+ strip: {
+ keep_symbols: true,
+ },
+}
+
+subdirs = [
+ "openjdkjvm",
+ "openjdkjvmti",
+ "simulator",
+]
diff --git a/runtime/Android.mk b/runtime/Android.mk
deleted file mode 100644
index 0e50eeb..0000000
--- a/runtime/Android.mk
+++ /dev/null
@@ -1,657 +0,0 @@
-#
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include art/build/Android.common_build.mk
-
-LIBART_COMMON_SRC_FILES := \
- art_field.cc \
- art_method.cc \
- atomic.cc.arm \
- barrier.cc \
- base/allocator.cc \
- base/arena_allocator.cc \
- base/arena_bit_vector.cc \
- base/bit_vector.cc \
- base/file_magic.cc \
- base/hex_dump.cc \
- base/logging.cc \
- base/mutex.cc \
- base/scoped_arena_allocator.cc \
- base/scoped_flock.cc \
- base/stringpiece.cc \
- base/stringprintf.cc \
- base/time_utils.cc \
- base/timing_logger.cc \
- base/unix_file/fd_file.cc \
- base/unix_file/random_access_file_utils.cc \
- check_jni.cc \
- class_linker.cc \
- class_table.cc \
- code_simulator_container.cc \
- common_throws.cc \
- compiler_filter.cc \
- debugger.cc \
- dex_file.cc \
- dex_file_verifier.cc \
- dex_instruction.cc \
- elf_file.cc \
- fault_handler.cc \
- gc/allocation_record.cc \
- gc/allocator/dlmalloc.cc \
- gc/allocator/rosalloc.cc \
- gc/accounting/bitmap.cc \
- gc/accounting/card_table.cc \
- gc/accounting/heap_bitmap.cc \
- gc/accounting/mod_union_table.cc \
- gc/accounting/remembered_set.cc \
- gc/accounting/space_bitmap.cc \
- gc/collector/concurrent_copying.cc \
- gc/collector/garbage_collector.cc \
- gc/collector/immune_region.cc \
- gc/collector/immune_spaces.cc \
- gc/collector/mark_compact.cc \
- gc/collector/mark_sweep.cc \
- gc/collector/partial_mark_sweep.cc \
- gc/collector/semi_space.cc \
- gc/collector/sticky_mark_sweep.cc \
- gc/gc_cause.cc \
- gc/heap.cc \
- gc/reference_processor.cc \
- gc/reference_queue.cc \
- gc/scoped_gc_critical_section.cc \
- gc/space/bump_pointer_space.cc \
- gc/space/dlmalloc_space.cc \
- gc/space/image_space.cc \
- gc/space/large_object_space.cc \
- gc/space/malloc_space.cc \
- gc/space/region_space.cc \
- gc/space/rosalloc_space.cc \
- gc/space/space.cc \
- gc/space/zygote_space.cc \
- gc/task_processor.cc \
- hprof/hprof.cc \
- image.cc \
- indirect_reference_table.cc \
- instrumentation.cc \
- intern_table.cc \
- interpreter/interpreter.cc \
- interpreter/interpreter_common.cc \
- interpreter/interpreter_goto_table_impl.cc \
- interpreter/interpreter_switch_impl.cc \
- interpreter/unstarted_runtime.cc \
- java_vm_ext.cc \
- jdwp/jdwp_event.cc \
- jdwp/jdwp_expand_buf.cc \
- jdwp/jdwp_handler.cc \
- jdwp/jdwp_main.cc \
- jdwp/jdwp_request.cc \
- jdwp/jdwp_socket.cc \
- jdwp/object_registry.cc \
- jni_env_ext.cc \
- jit/debugger_interface.cc \
- jit/jit.cc \
- jit/jit_code_cache.cc \
- jit/offline_profiling_info.cc \
- jit/profiling_info.cc \
- jit/profile_saver.cc \
- jni_internal.cc \
- jobject_comparator.cc \
- linear_alloc.cc \
- mem_map.cc \
- memory_region.cc \
- mirror/abstract_method.cc \
- mirror/array.cc \
- mirror/class.cc \
- mirror/dex_cache.cc \
- mirror/field.cc \
- mirror/method.cc \
- mirror/object.cc \
- mirror/reference.cc \
- mirror/stack_trace_element.cc \
- mirror/string.cc \
- mirror/throwable.cc \
- monitor.cc \
- native_bridge_art_interface.cc \
- native_stack_dump.cc \
- native/dalvik_system_DexFile.cc \
- native/dalvik_system_VMDebug.cc \
- native/dalvik_system_VMRuntime.cc \
- native/dalvik_system_VMStack.cc \
- native/dalvik_system_ZygoteHooks.cc \
- native/java_lang_Class.cc \
- native/java_lang_DexCache.cc \
- native/java_lang_Object.cc \
- native/java_lang_String.cc \
- native/java_lang_StringFactory.cc \
- native/java_lang_System.cc \
- native/java_lang_Thread.cc \
- native/java_lang_Throwable.cc \
- native/java_lang_VMClassLoader.cc \
- native/java_lang_ref_FinalizerReference.cc \
- native/java_lang_ref_Reference.cc \
- native/java_lang_reflect_AbstractMethod.cc \
- native/java_lang_reflect_Array.cc \
- native/java_lang_reflect_Constructor.cc \
- native/java_lang_reflect_Field.cc \
- native/java_lang_reflect_Method.cc \
- native/java_lang_reflect_Proxy.cc \
- native/java_util_concurrent_atomic_AtomicLong.cc \
- native/libcore_util_CharsetUtils.cc \
- native/org_apache_harmony_dalvik_ddmc_DdmServer.cc \
- native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc \
- native/sun_misc_Unsafe.cc \
- oat.cc \
- oat_file.cc \
- oat_file_assistant.cc \
- oat_file_manager.cc \
- oat_quick_method_header.cc \
- object_lock.cc \
- offsets.cc \
- os_linux.cc \
- parsed_options.cc \
- plugin.cc \
- primitive.cc \
- quick_exception_handler.cc \
- quick/inline_method_analyser.cc \
- reference_table.cc \
- reflection.cc \
- runtime.cc \
- runtime_options.cc \
- signal_catcher.cc \
- stack.cc \
- stack_map.cc \
- thread.cc \
- thread_list.cc \
- thread_pool.cc \
- ti/agent.cc \
- trace.cc \
- transaction.cc \
- type_lookup_table.cc \
- utf.cc \
- utils.cc \
- verifier/instruction_flags.cc \
- verifier/method_verifier.cc \
- verifier/reg_type.cc \
- verifier/reg_type_cache.cc \
- verifier/register_line.cc \
- well_known_classes.cc \
- zip_archive.cc
-
-LIBART_COMMON_SRC_FILES += \
- arch/context.cc \
- arch/instruction_set.cc \
- arch/instruction_set_features.cc \
- arch/memcmp16.cc \
- arch/arm/instruction_set_features_arm.cc \
- arch/arm/registers_arm.cc \
- arch/arm64/instruction_set_features_arm64.cc \
- arch/arm64/registers_arm64.cc \
- arch/mips/instruction_set_features_mips.cc \
- arch/mips/registers_mips.cc \
- arch/mips64/instruction_set_features_mips64.cc \
- arch/mips64/registers_mips64.cc \
- arch/x86/instruction_set_features_x86.cc \
- arch/x86/registers_x86.cc \
- arch/x86_64/registers_x86_64.cc \
- entrypoints/entrypoint_utils.cc \
- entrypoints/jni/jni_entrypoints.cc \
- entrypoints/math_entrypoints.cc \
- entrypoints/quick/quick_alloc_entrypoints.cc \
- entrypoints/quick/quick_cast_entrypoints.cc \
- entrypoints/quick/quick_deoptimization_entrypoints.cc \
- entrypoints/quick/quick_dexcache_entrypoints.cc \
- entrypoints/quick/quick_field_entrypoints.cc \
- entrypoints/quick/quick_fillarray_entrypoints.cc \
- entrypoints/quick/quick_instrumentation_entrypoints.cc \
- entrypoints/quick/quick_jni_entrypoints.cc \
- entrypoints/quick/quick_lock_entrypoints.cc \
- entrypoints/quick/quick_math_entrypoints.cc \
- entrypoints/quick/quick_thread_entrypoints.cc \
- entrypoints/quick/quick_throw_entrypoints.cc \
- entrypoints/quick/quick_trampoline_entrypoints.cc
-
-LIBART_TARGET_LDFLAGS :=
-LIBART_HOST_LDFLAGS :=
-
-# Keep the __jit_debug_register_code symbol as a unique symbol during ICF for architectures where
-# we use gold as the linker (arm, x86, x86_64). The symbol is used by the debuggers to detect when
-# new jit code is generated. We don't want it to be called when a different function with the same
-# (empty) body is called.
-JIT_DEBUG_REGISTER_CODE_LDFLAGS := -Wl,--keep-unique,__jit_debug_register_code
-LIBART_TARGET_LDFLAGS_arm := $(JIT_DEBUG_REGISTER_CODE_LDFLAGS)
-LIBART_TARGET_LDFLAGS_arm64 := $(JIT_DEBUG_REGISTER_CODE_LDFLAGS)
-LIBART_TARGET_LDFLAGS_x86 := $(JIT_DEBUG_REGISTER_CODE_LDFLAGS)
-LIBART_TARGET_LDFLAGS_x86_64 := $(JIT_DEBUG_REGISTER_CODE_LDFLAGS)
-JIT_DEBUG_REGISTER_CODE_LDFLAGS :=
-
-LIBART_TARGET_SRC_FILES := \
- $(LIBART_COMMON_SRC_FILES) \
- jdwp/jdwp_adb.cc \
- monitor_android.cc \
- runtime_android.cc \
- thread_android.cc
-
-LIBART_TARGET_SRC_FILES_arm := \
- interpreter/mterp/mterp.cc \
- interpreter/mterp/out/mterp_arm.S \
- arch/arm/context_arm.cc.arm \
- arch/arm/entrypoints_init_arm.cc \
- arch/arm/instruction_set_features_assembly_tests.S \
- arch/arm/jni_entrypoints_arm.S \
- arch/arm/memcmp16_arm.S \
- arch/arm/quick_entrypoints_arm.S \
- arch/arm/quick_entrypoints_cc_arm.cc \
- arch/arm/thread_arm.cc \
- arch/arm/fault_handler_arm.cc
-
-LIBART_TARGET_SRC_FILES_arm64 := \
- interpreter/mterp/mterp.cc \
- interpreter/mterp/out/mterp_arm64.S \
- arch/arm64/context_arm64.cc \
- arch/arm64/entrypoints_init_arm64.cc \
- arch/arm64/jni_entrypoints_arm64.S \
- arch/arm64/memcmp16_arm64.S \
- arch/arm64/quick_entrypoints_arm64.S \
- arch/arm64/thread_arm64.cc \
- monitor_pool.cc \
- arch/arm64/fault_handler_arm64.cc
-
-LIBART_SRC_FILES_x86 := \
- interpreter/mterp/mterp.cc \
- interpreter/mterp/out/mterp_x86.S \
- arch/x86/context_x86.cc \
- arch/x86/entrypoints_init_x86.cc \
- arch/x86/jni_entrypoints_x86.S \
- arch/x86/memcmp16_x86.S \
- arch/x86/quick_entrypoints_x86.S \
- arch/x86/thread_x86.cc \
- arch/x86/fault_handler_x86.cc
-
-LIBART_TARGET_SRC_FILES_x86 := \
- $(LIBART_SRC_FILES_x86)
-
-# Note that the fault_handler_x86.cc is not a mistake. This file is
-# shared between the x86 and x86_64 architectures.
-LIBART_SRC_FILES_x86_64 := \
- interpreter/mterp/mterp.cc \
- interpreter/mterp/out/mterp_x86_64.S \
- arch/x86_64/context_x86_64.cc \
- arch/x86_64/entrypoints_init_x86_64.cc \
- arch/x86_64/jni_entrypoints_x86_64.S \
- arch/x86_64/memcmp16_x86_64.S \
- arch/x86_64/quick_entrypoints_x86_64.S \
- arch/x86_64/thread_x86_64.cc \
- monitor_pool.cc \
- arch/x86/fault_handler_x86.cc
-
-LIBART_TARGET_SRC_FILES_x86_64 := \
- $(LIBART_SRC_FILES_x86_64) \
-
-LIBART_TARGET_SRC_FILES_mips := \
- interpreter/mterp/mterp.cc \
- interpreter/mterp/out/mterp_mips.S \
- arch/mips/context_mips.cc \
- arch/mips/entrypoints_init_mips.cc \
- arch/mips/jni_entrypoints_mips.S \
- arch/mips/memcmp16_mips.S \
- arch/mips/quick_entrypoints_mips.S \
- arch/mips/thread_mips.cc \
- arch/mips/fault_handler_mips.cc
-
-LIBART_TARGET_SRC_FILES_mips64 := \
- interpreter/mterp/mterp.cc \
- interpreter/mterp/out/mterp_mips64.S \
- arch/mips64/context_mips64.cc \
- arch/mips64/entrypoints_init_mips64.cc \
- arch/mips64/jni_entrypoints_mips64.S \
- arch/mips64/memcmp16_mips64.S \
- arch/mips64/quick_entrypoints_mips64.S \
- arch/mips64/thread_mips64.cc \
- monitor_pool.cc \
- arch/mips64/fault_handler_mips64.cc
-
-LIBART_HOST_SRC_FILES := \
- $(LIBART_COMMON_SRC_FILES) \
- monitor_linux.cc \
- runtime_linux.cc \
- thread_linux.cc
-
-LIBART_HOST_SRC_FILES_32 := \
- $(LIBART_SRC_FILES_x86)
-
-LIBART_HOST_SRC_FILES_64 := \
- $(LIBART_SRC_FILES_x86_64)
-
-LIBART_ENUM_OPERATOR_OUT_HEADER_FILES := \
- arch/instruction_set.h \
- base/allocator.h \
- base/enums.h \
- base/mutex.h \
- debugger.h \
- base/unix_file/fd_file.h \
- dex_file.h \
- dex_instruction.h \
- dex_instruction_utils.h \
- gc_root.h \
- gc/allocator_type.h \
- gc/allocator/rosalloc.h \
- gc/collector_type.h \
- gc/collector/gc_type.h \
- gc/heap.h \
- gc/space/region_space.h \
- gc/space/space.h \
- gc/weak_root_state.h \
- image.h \
- instrumentation.h \
- indirect_reference_table.h \
- invoke_type.h \
- jdwp/jdwp.h \
- jdwp/jdwp_constants.h \
- lock_word.h \
- mirror/class.h \
- oat.h \
- object_callbacks.h \
- process_state.h \
- quick/inline_method_analyser.h \
- runtime.h \
- stack.h \
- thread.h \
- thread_state.h \
- ti/agent.h \
- verifier/method_verifier.h
-
-LIBOPENJDKJVM_SRC_FILES := openjdkjvm/OpenjdkJvm.cc
-LIBOPENJDKJVMTI_SRC_FILES := openjdkjvmti/OpenjdkJvmTi.cc
-
-LIBART_CFLAGS := -DBUILDING_LIBART=1
-
-LIBART_TARGET_CFLAGS :=
-LIBART_HOST_CFLAGS :=
-
-# $(1): target or host
-# $(2): ndebug or debug
-# $(3): static or shared (note that static only applies for host)
-# $(4): module name : either libart, libopenjdkjvm, or libopenjdkjvmti
-define build-runtime-library
- ifneq ($(1),target)
- ifneq ($(1),host)
- $$(error expected target or host for argument 1, received $(1))
- endif
- endif
- ifneq ($(2),ndebug)
- ifneq ($(2),debug)
- $$(error expected ndebug or debug for argument 2, received $(2))
- endif
- endif
- ifneq ($(4),libart)
- ifneq ($(4),libopenjdkjvm)
- ifneq ($(4),libopenjdkjvmti)
- $$(error expected libart, libopenjdkjvmti, or libopenjdkjvm for argument 4, received $(4))
- endif
- endif
- endif
-
- art_target_or_host := $(1)
- art_ndebug_or_debug := $(2)
- art_static_or_shared := $(3)
-
- include $$(CLEAR_VARS)
- LOCAL_CPP_EXTENSION := $$(ART_CPP_EXTENSION)
- ifeq ($$(art_ndebug_or_debug),ndebug)
- LOCAL_MODULE := $(4)
- ifeq ($$(art_target_or_host),target)
- LOCAL_FDO_SUPPORT := true
- endif
- else # debug
- LOCAL_MODULE := $(4)d
- endif
-
- LOCAL_MODULE_TAGS := optional
-
- ifeq ($$(art_static_or_shared),static)
- LOCAL_MODULE_CLASS := STATIC_LIBRARIES
- else
- LOCAL_MODULE_CLASS := SHARED_LIBRARIES
- endif
-
- ifeq ($(4),libart)
- ifeq ($$(art_target_or_host),target)
- LOCAL_SRC_FILES := $$(LIBART_TARGET_SRC_FILES)
- $$(foreach arch,$$(ART_TARGET_SUPPORTED_ARCH), \
- $$(eval LOCAL_SRC_FILES_$$(arch) := $$$$(LIBART_TARGET_SRC_FILES_$$(arch))))
- else # host
- LOCAL_SRC_FILES := $$(LIBART_HOST_SRC_FILES)
- LOCAL_SRC_FILES_32 := $$(LIBART_HOST_SRC_FILES_32)
- LOCAL_SRC_FILES_64 := $$(LIBART_HOST_SRC_FILES_64)
- LOCAL_IS_HOST_MODULE := true
- endif
- else
- ifeq ($(4),libopenjdkjvmti)
- LOCAL_SRC_FILES := $$(LIBOPENJDKJVMTI_SRC_FILES)
- else # libopenjdkjvm
- LOCAL_SRC_FILES := $$(LIBOPENJDKJVM_SRC_FILES)
- endif
- ifeq ($$(art_target_or_host),host)
- LOCAL_IS_HOST_MODULE := true
- endif
- endif
-
-ifeq ($(4),libart)
- GENERATED_SRC_DIR := $$(call local-generated-sources-dir)
- ENUM_OPERATOR_OUT_CC_FILES := $$(patsubst %.h,%_operator_out.cc,$$(LIBART_ENUM_OPERATOR_OUT_HEADER_FILES))
- ENUM_OPERATOR_OUT_GEN := $$(addprefix $$(GENERATED_SRC_DIR)/,$$(ENUM_OPERATOR_OUT_CC_FILES))
-
-$$(ENUM_OPERATOR_OUT_GEN): art/tools/generate-operator-out.py
-$$(ENUM_OPERATOR_OUT_GEN): PRIVATE_CUSTOM_TOOL = art/tools/generate-operator-out.py $(LOCAL_PATH) $$< > $$@
-$$(ENUM_OPERATOR_OUT_GEN): $$(GENERATED_SRC_DIR)/%_operator_out.cc : $(LOCAL_PATH)/%.h
- $$(transform-generated-source)
-
- LOCAL_GENERATED_SOURCES += $$(ENUM_OPERATOR_OUT_GEN)
-endif
-
- LOCAL_CFLAGS := $$(LIBART_CFLAGS)
- LOCAL_LDFLAGS := $$(LIBART_LDFLAGS)
- ifeq ($$(art_target_or_host),target)
- LOCAL_CFLAGS += $$(LIBART_TARGET_CFLAGS)
- LOCAL_LDFLAGS += $$(LIBART_TARGET_LDFLAGS)
- $$(foreach arch,$$(ART_TARGET_SUPPORTED_ARCH), \
- $$(eval LOCAL_LDFLAGS_$$(arch) := $$(LIBART_TARGET_LDFLAGS_$$(arch))))
- else #host
- LOCAL_CFLAGS += $$(LIBART_HOST_CFLAGS)
- LOCAL_LDFLAGS += $$(LIBART_HOST_LDFLAGS)
- ifeq ($$(art_static_or_shared),static)
- LOCAL_LDFLAGS += -static
- endif
- endif
-
- # Clang usage
- ifeq ($$(art_target_or_host),target)
- $$(eval LOCAL_CLANG := $$(ART_TARGET_CLANG))
- $$(eval $$(call set-target-local-cflags-vars,$(2)))
- LOCAL_ASFLAGS_arm += -no-integrated-as
- else # host
- LOCAL_CLANG := $$(ART_HOST_CLANG)
- LOCAL_LDLIBS += -ldl -lpthread
- ifeq ($$(HOST_OS),linux)
- LOCAL_LDLIBS += -lrt
- endif
- LOCAL_CFLAGS += $$(ART_HOST_CFLAGS)
- LOCAL_ASFLAGS += $$(ART_HOST_ASFLAGS)
-
- ifeq ($$(art_ndebug_or_debug),debug)
- LOCAL_CFLAGS += $$(ART_HOST_DEBUG_CFLAGS)
- LOCAL_ASFLAGS += $$(ART_HOST_DEBUG_ASFLAGS)
- else
- LOCAL_CFLAGS += $$(ART_HOST_NON_DEBUG_CFLAGS)
- LOCAL_ASFLAGS += $$(ART_HOST_NON_DEBUG_ASFLAGS)
- endif
- LOCAL_MULTILIB := both
- endif
-
- LOCAL_C_INCLUDES += $$(ART_C_INCLUDES)
- LOCAL_C_INCLUDES += art/cmdline
- LOCAL_C_INCLUDES += art/sigchainlib
- LOCAL_C_INCLUDES += art
-
- ifeq ($$(art_static_or_shared),static)
- LOCAL_STATIC_LIBRARIES := libnativehelper
- LOCAL_STATIC_LIBRARIES += libnativebridge
- LOCAL_STATIC_LIBRARIES += libnativeloader
- LOCAL_STATIC_LIBRARIES += libsigchain_dummy
- LOCAL_STATIC_LIBRARIES += libbacktrace
- LOCAL_STATIC_LIBRARIES += liblz4
- else
- LOCAL_SHARED_LIBRARIES := libnativehelper
- LOCAL_SHARED_LIBRARIES += libnativebridge
- LOCAL_SHARED_LIBRARIES += libnativeloader
- LOCAL_SHARED_LIBRARIES += libsigchain
- LOCAL_SHARED_LIBRARIES += libbacktrace
- LOCAL_SHARED_LIBRARIES += liblz4
- endif
-
- ifeq ($$(art_target_or_host),target)
- LOCAL_SHARED_LIBRARIES += libdl
- # ZipArchive support, the order matters here to get all symbols.
- LOCAL_STATIC_LIBRARIES := libziparchive libz libbase
- # For android::FileMap used by libziparchive.
- LOCAL_SHARED_LIBRARIES += libutils
- # For liblog, atrace, properties, ashmem, set_sched_policy and socket_peer_is_trusted.
- LOCAL_SHARED_LIBRARIES += libcutils
- else # host
- ifeq ($$(art_static_or_shared),static)
- LOCAL_STATIC_LIBRARIES += libziparchive-host libz
- # For ashmem_create_region.
- LOCAL_STATIC_LIBRARIES += libcutils
- else
- LOCAL_SHARED_LIBRARIES += libziparchive-host libz-host
- # For ashmem_create_region.
- LOCAL_SHARED_LIBRARIES += libcutils
- endif
- endif
-
- ifeq ($(4),libopenjdkjvm)
- ifeq ($$(art_ndebug_or_debug),ndebug)
- LOCAL_SHARED_LIBRARIES += libart
- else
- LOCAL_SHARED_LIBRARIES += libartd
- endif
- LOCAL_NOTICE_FILE := $(LOCAL_PATH)/openjdkjvm/NOTICE
- else
- ifeq ($(4),libopenjdkjvmti)
- ifeq ($$(art_ndebug_or_debug),ndebug)
- LOCAL_SHARED_LIBRARIES += libart
- else
- LOCAL_SHARED_LIBRARIES += libartd
- endif
- LOCAL_NOTICE_FILE := $(LOCAL_PATH)/openjdkjvmti/NOTICE
- endif
- endif
- LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
- LOCAL_ADDITIONAL_DEPENDENCIES += $$(LOCAL_PATH)/Android.mk
-
- ifeq ($$(art_target_or_host),target)
- LOCAL_MODULE_TARGET_ARCH := $$(ART_TARGET_SUPPORTED_ARCH)
- endif
-
- LOCAL_NATIVE_COVERAGE := $(ART_COVERAGE)
-
- ifeq ($$(art_target_or_host),target)
- ifneq ($$(art_ndebug_or_debug),debug)
- # Leave the symbols in the shared library so that stack unwinders can
- # produce meaningful name resolution.
- LOCAL_STRIP_MODULE := keep_symbols
- endif
- include $$(BUILD_SHARED_LIBRARY)
- else # host
- ifeq ($$(art_static_or_shared),static)
- include $$(BUILD_HOST_STATIC_LIBRARY)
- else
- include $$(BUILD_HOST_SHARED_LIBRARY)
- endif
- endif
-
- # Clear locally defined variables.
- GENERATED_SRC_DIR :=
- ENUM_OPERATOR_OUT_CC_FILES :=
- ENUM_OPERATOR_OUT_GEN :=
- art_target_or_host :=
- art_ndebug_or_debug :=
- art_static_or_shared :=
-endef
-
-# We always build dex2oat and dependencies, even if the host build is otherwise disabled, since
-# they are used to cross compile for the target.
-ifeq ($(ART_BUILD_HOST_NDEBUG),true)
- $(eval $(call build-runtime-library,host,ndebug,shared,libart))
- $(eval $(call build-runtime-library,host,ndebug,shared,libopenjdkjvm))
- $(eval $(call build-runtime-library,host,ndebug,shared,libopenjdkjvmti))
- ifeq ($(ART_BUILD_HOST_STATIC),true)
- $(eval $(call build-runtime-library,host,ndebug,static,libart))
- $(eval $(call build-runtime-library,host,ndebug,static,libopenjdkjvm))
- $(eval $(call build-runtime-library,host,ndebug,static,libopenjdkjvmti))
- endif
-endif
-ifeq ($(ART_BUILD_HOST_DEBUG),true)
- $(eval $(call build-runtime-library,host,debug,shared,libart))
- $(eval $(call build-runtime-library,host,debug,shared,libopenjdkjvm))
- $(eval $(call build-runtime-library,host,debug,shared,libopenjdkjvmti))
- ifeq ($(ART_BUILD_HOST_STATIC),true)
- $(eval $(call build-runtime-library,host,debug,static,libart))
- $(eval $(call build-runtime-library,host,debug,static,libopenjdkjvm))
- $(eval $(call build-runtime-library,host,debug,static,libopenjdkjvmti))
- endif
-endif
-
-ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
-# $(error $(call build-runtime-library,target,ndebug))
- $(eval $(call build-runtime-library,target,ndebug,shared,libart))
- $(eval $(call build-runtime-library,target,ndebug,shared,libopenjdkjvm))
- $(eval $(call build-runtime-library,target,ndebug,shared,libopenjdkjvmti))
-endif
-ifeq ($(ART_BUILD_TARGET_DEBUG),true)
- $(eval $(call build-runtime-library,target,debug,shared,libart))
- $(eval $(call build-runtime-library,target,debug,shared,libopenjdkjvm))
- $(eval $(call build-runtime-library,target,debug,shared,libopenjdkjvmti))
-endif
-
-# Clear locally defined variables.
-LOCAL_PATH :=
-LIBART_COMMON_SRC_FILES :=
-LIBART_HOST_LDFLAGS :=
-LIBART_TARGET_LDFLAGS :=
-LIBART_TARGET_LDFLAGS_arm :=
-LIBART_TARGET_LDFLAGS_arm64 :=
-LIBART_TARGET_LDFLAGS_x86 :=
-LIBART_TARGET_LDFLAGS_x86_64 :=
-LIBART_TARGET_LDFLAGS_mips :=
-LIBART_TARGET_LDFLAGS_mips64 :=
-LIBART_TARGET_SRC_FILES :=
-LIBART_TARGET_SRC_FILES_arm :=
-LIBART_TARGET_SRC_FILES_arm64 :=
-LIBART_TARGET_SRC_FILES_x86 :=
-LIBART_TARGET_SRC_FILES_x86_64 :=
-LIBART_TARGET_SRC_FILES_mips :=
-LIBART_TARGET_SRC_FILES_mips64 :=
-LIBART_HOST_SRC_FILES :=
-LIBART_HOST_SRC_FILES_32 :=
-LIBART_HOST_SRC_FILES_64 :=
-LIBART_ENUM_OPERATOR_OUT_HEADER_FILES :=
-LIBART_CFLAGS :=
-LIBART_TARGET_CFLAGS :=
-LIBART_HOST_CFLAGS :=
-build-runtime-library :=
diff --git a/runtime/base/histogram-inl.h b/runtime/base/histogram-inl.h
index 4af47d1..ca9a694 100644
--- a/runtime/base/histogram-inl.h
+++ b/runtime/base/histogram-inl.h
@@ -228,10 +228,8 @@
DCHECK_LE(std::abs(out_data->perc_.back() - 1.0), 0.001);
}
-#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
-#endif
template <class Value>
inline double Histogram<Value>::Percentile(double per, const CumulativeData& data) const {
@@ -273,9 +271,7 @@
return value;
}
-#if defined(__clang__)
#pragma clang diagnostic pop
-#endif
} // namespace art
#endif // ART_RUNTIME_BASE_HISTOGRAM_INL_H_
diff --git a/runtime/base/macros.h b/runtime/base/macros.h
index 5a50247..0ec6e6d 100644
--- a/runtime/base/macros.h
+++ b/runtime/base/macros.h
@@ -30,16 +30,8 @@
_rc; })
#endif
-#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
-
-// C++11 final and override keywords that were introduced in GCC version 4.7.
-#if defined(__clang__) || GCC_VERSION >= 40700
#define OVERRIDE override
#define FINAL final
-#else
-#define OVERRIDE
-#define FINAL
-#endif
// Declare a friend relationship in a class with a test. Used rather that FRIEND_TEST to avoid
// globally importing gtest/gtest.h into the main ART header files.
@@ -158,12 +150,9 @@
#define ALWAYS_INLINE __attribute__ ((always_inline))
#endif
-#ifdef __clang__
-/* clang doesn't like attributes on lambda functions */
+// clang doesn't like attributes on lambda functions. It would be nice to say:
+// #define ALWAYS_INLINE_LAMBDA ALWAYS_INLINE
#define ALWAYS_INLINE_LAMBDA
-#else
-#define ALWAYS_INLINE_LAMBDA ALWAYS_INLINE
-#endif
#define NO_INLINE __attribute__ ((noinline))
@@ -228,75 +217,46 @@
//
// In either case this macro has no effect on runtime behavior and performance
// of code.
-#if defined(__clang__) && __cplusplus >= 201103L && defined(__has_warning)
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
#define FALLTHROUGH_INTENDED [[clang::fallthrough]] // NOLINT
#endif
-#endif
#ifndef FALLTHROUGH_INTENDED
#define FALLTHROUGH_INTENDED do { } while (0)
#endif
// Annotalysis thread-safety analysis support.
-#if defined(__SUPPORT_TS_ANNOTATION__) || defined(__clang__)
-#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
-#else
-#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
-#endif
-#define ACQUIRED_AFTER(...) THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
-#define ACQUIRED_BEFORE(...) THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
-#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
-#define GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(guarded)
-#define LOCK_RETURNED(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
-#define NO_THREAD_SAFETY_ANALYSIS THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+#define ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
+#define ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
+#define GUARDED_BY(x) __attribute__((guarded_by(x)))
+#define GUARDED_VAR __attribute__((guarded))
+#define LOCK_RETURNED(x) __attribute__((lock_returned(x)))
+#define NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis))
#define PT_GUARDED_BY(x)
// THREAD_ANNOTATION_ATTRIBUTE__(point_to_guarded_by(x))
-#define PT_GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(point_to_guarded)
-#define SCOPED_LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+#define PT_GUARDED_VAR __attribute__((point_to_guarded))
+#define SCOPED_LOCKABLE __attribute__((scoped_lockable))
-#if defined(__clang__)
-#define EXCLUSIVE_LOCK_FUNCTION(...) THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
-#define EXCLUSIVE_TRYLOCK_FUNCTION(...) THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
-#define SHARED_LOCK_FUNCTION(...) THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
-#define SHARED_TRYLOCK_FUNCTION(...) THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
-#define UNLOCK_FUNCTION(...) THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
-#define REQUIRES(...) THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
-#define SHARED_REQUIRES(...) THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
-#define CAPABILITY(...) THREAD_ANNOTATION_ATTRIBUTE__(capability(__VA_ARGS__))
-#define SHARED_CAPABILITY(...) THREAD_ANNOTATION_ATTRIBUTE__(shared_capability(__VA_ARGS__))
-#define ASSERT_CAPABILITY(...) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(__VA_ARGS__))
-#define ASSERT_SHARED_CAPABILITY(...) THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(__VA_ARGS__))
-#define RETURN_CAPABILITY(...) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(__VA_ARGS__))
-#define TRY_ACQUIRE(...) THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
-#define TRY_ACQUIRE_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
-#define ACQUIRE(...) THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
-#define ACQUIRE_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
-#define RELEASE(...) THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
-#define RELEASE_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
-#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
-#else
-#define EXCLUSIVE_LOCK_FUNCTION(...) THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock(__VA_ARGS__))
-#define EXCLUSIVE_TRYLOCK_FUNCTION(...) THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock(__VA_ARGS__))
-#define SHARED_LOCK_FUNCTION(...) THREAD_ANNOTATION_ATTRIBUTE__(shared_lock(__VA_ARGS__))
-#define SHARED_TRYLOCK_FUNCTION(...) THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock(__VA_ARGS__))
-#define UNLOCK_FUNCTION(...) THREAD_ANNOTATION_ATTRIBUTE__(unlock(__VA_ARGS__))
-#define REQUIRES(...)
-#define SHARED_REQUIRES(...)
-#define CAPABILITY(...)
-#define SHARED_CAPABILITY(...)
-#define ASSERT_CAPABILITY(...)
-#define ASSERT_SHARED_CAPABILITY(...)
-#define RETURN_CAPABILITY(...)
-#define TRY_ACQUIRE(...)
-#define TRY_ACQUIRE_SHARED(...)
-#define ACQUIRE(...)
-#define ACQUIRE_SHARED(...)
-#define RELEASE(...)
-#define RELEASE_SHARED(...)
-#define SCOPED_CAPABILITY
-#endif
+#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__((exclusive_lock_function(__VA_ARGS__)))
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__((exclusive_trylock_function(__VA_ARGS__)))
+#define SHARED_LOCK_FUNCTION(...) __attribute__((shared_lock_function(__VA_ARGS__)))
+#define SHARED_TRYLOCK_FUNCTION(...) __attribute__((shared_trylock_function(__VA_ARGS__)))
+#define UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__)))
+#define REQUIRES(...) __attribute__((requires_capability(__VA_ARGS__)))
+#define SHARED_REQUIRES(...) __attribute__((requires_shared_capability(__VA_ARGS__)))
+#define CAPABILITY(...) __attribute__((capability(__VA_ARGS__)))
+#define SHARED_CAPABILITY(...) __attribute__((shared_capability(__VA_ARGS__)))
+#define ASSERT_CAPABILITY(...) __attribute__((assert_capability(__VA_ARGS__)))
+#define ASSERT_SHARED_CAPABILITY(...) __attribute__((assert_shared_capability(__VA_ARGS__)))
+#define RETURN_CAPABILITY(...) __attribute__((lock_returned(__VA_ARGS__)))
+#define TRY_ACQUIRE(...) __attribute__((try_acquire_capability(__VA_ARGS__)))
+#define TRY_ACQUIRE_SHARED(...) __attribute__((try_acquire_shared_capability(__VA_ARGS__)))
+#define ACQUIRE(...) __attribute__((acquire_capability(__VA_ARGS__)))
+#define ACQUIRE_SHARED(...) __attribute__((acquire_shared_capability(__VA_ARGS__)))
+#define RELEASE(...) __attribute__((release_capability(__VA_ARGS__)))
+#define RELEASE_SHARED(...) __attribute__((release_shared_capability(__VA_ARGS__)))
+#define SCOPED_CAPABILITY __attribute__((scoped_lockable))
#define LOCKABLE CAPABILITY("mutex")
#define SHARED_LOCKABLE SHARED_CAPABILITY("mutex")
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 264a530..fec918b 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -98,12 +98,7 @@
}
~ScopedAllMutexesLock() {
-#if !defined(__clang__)
- // TODO: remove this workaround target GCC/libc++/bionic bug "invalid failure memory model".
- while (!gAllMutexData->all_mutexes_guard.CompareExchangeWeakSequentiallyConsistent(mutex_, 0)) {
-#else
while (!gAllMutexData->all_mutexes_guard.CompareExchangeWeakRelease(mutex_, 0)) {
-#endif
NanoSleep(100);
}
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 1a3bba5..f4400c3 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4546,7 +4546,8 @@
}
self->AllowThreadSuspension();
- CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << PrettyClass(klass.Get());
+ CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << PrettyClass(klass.Get())
+ << " self.tid=" << self->GetTid() << " clinit.tid=" << klass->GetClinitThreadId();
// From here out other threads may observe that we're initializing and so changes of state
// require the a notification.
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index cbdf3dc..a5b0689 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -4058,7 +4058,7 @@
// Prepare JDWP ids for the reply.
JDWP::JdwpTag result_tag = BasicTagFromDescriptor(m->GetShorty());
const bool is_object_result = (result_tag == JDWP::JT_OBJECT);
- StackHandleScope<2> hs(soa.Self());
+ StackHandleScope<3> hs(soa.Self());
Handle<mirror::Object> object_result = hs.NewHandle(is_object_result ? result.GetL() : nullptr);
Handle<mirror::Throwable> exception = hs.NewHandle(soa.Self()->GetException());
soa.Self()->ClearException();
@@ -4097,10 +4097,17 @@
// unless we threw, in which case we return null.
DCHECK_EQ(JDWP::JT_VOID, result_tag);
if (exceptionObjectId == 0) {
- // TODO we could keep the receiver ObjectId in the DebugInvokeReq to avoid looking into the
- // object registry.
- result_value = GetObjectRegistry()->Add(pReq->receiver.Read());
- result_tag = TagFromObject(soa, pReq->receiver.Read());
+ if (m->GetDeclaringClass()->IsStringClass()) {
+ // For string constructors, the new string is remapped to the receiver (stored in ref).
+ Handle<mirror::Object> decoded_ref = hs.NewHandle(soa.Self()->DecodeJObject(ref.get()));
+ result_value = gRegistry->Add(decoded_ref);
+ result_tag = TagFromObject(soa, decoded_ref.Get());
+ } else {
+ // TODO we could keep the receiver ObjectId in the DebugInvokeReq to avoid looking into the
+ // object registry.
+ result_value = GetObjectRegistry()->Add(pReq->receiver.Read());
+ result_tag = TagFromObject(soa, pReq->receiver.Read());
+ }
} else {
result_value = 0;
result_tag = JDWP::JT_OBJECT;
diff --git a/runtime/entrypoints/quick/quick_math_entrypoints.cc b/runtime/entrypoints/quick/quick_math_entrypoints.cc
index 1c658b7..51d2784 100644
--- a/runtime/entrypoints/quick/quick_math_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_math_entrypoints.cc
@@ -18,10 +18,8 @@
namespace art {
-#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
-#endif
int CmplFloat(float a, float b) {
if (a == b) {
@@ -67,9 +65,7 @@
return -1;
}
-#if defined(__clang__)
#pragma clang diagnostic pop
-#endif
extern "C" int64_t artLmul(int64_t a, int64_t b) {
return a * b;
diff --git a/runtime/gc/accounting/space_bitmap-inl.h b/runtime/gc/accounting/space_bitmap-inl.h
index 4cf5b4f..9feaf41 100644
--- a/runtime/gc/accounting/space_bitmap-inl.h
+++ b/runtime/gc/accounting/space_bitmap-inl.h
@@ -36,7 +36,7 @@
const uintptr_t offset = addr - heap_begin_;
const size_t index = OffsetToIndex(offset);
const uintptr_t mask = OffsetToMask(offset);
- Atomic<uintptr_t>* atomic_entry = reinterpret_cast<Atomic<uintptr_t>*>(&bitmap_begin_[index]);
+ Atomic<uintptr_t>* atomic_entry = &bitmap_begin_[index];
DCHECK_LT(index, bitmap_size_ / sizeof(intptr_t)) << " bitmap_size_ = " << bitmap_size_;
uintptr_t old_word;
do {
@@ -58,7 +58,7 @@
DCHECK(bitmap_begin_ != nullptr);
DCHECK_GE(addr, heap_begin_);
const uintptr_t offset = addr - heap_begin_;
- return (bitmap_begin_[OffsetToIndex(offset)] & OffsetToMask(offset)) != 0;
+ return (bitmap_begin_[OffsetToIndex(offset)].LoadRelaxed() & OffsetToMask(offset)) != 0;
}
template<size_t kAlignment> template<typename Visitor>
@@ -116,7 +116,7 @@
// Traverse the middle, full part.
for (size_t i = index_start + 1; i < index_end; ++i) {
- uintptr_t w = bitmap_begin_[i];
+ uintptr_t w = bitmap_begin_[i].LoadRelaxed();
if (w != 0) {
const uintptr_t ptr_base = IndexToOffset(i) + heap_begin_;
do {
@@ -164,8 +164,8 @@
const size_t index = OffsetToIndex(offset);
const uintptr_t mask = OffsetToMask(offset);
DCHECK_LT(index, bitmap_size_ / sizeof(intptr_t)) << " bitmap_size_ = " << bitmap_size_;
- uintptr_t* address = &bitmap_begin_[index];
- uintptr_t old_word = *address;
+ Atomic<uintptr_t>* atomic_entry = &bitmap_begin_[index];
+ uintptr_t old_word = atomic_entry->LoadRelaxed();
if (kSetBit) {
// Check the bit before setting the word incase we are trying to mark a read only bitmap
// like an image space bitmap. This bitmap is mapped as read only and will fault if we
@@ -173,10 +173,10 @@
// occur if we check before setting the bit. This also prevents dirty pages that would
// occur if the bitmap was read write and we did not check the bit.
if ((old_word & mask) == 0) {
- *address = old_word | mask;
+ atomic_entry->StoreRelaxed(old_word | mask);
}
} else {
- *address = old_word & ~mask;
+ atomic_entry->StoreRelaxed(old_word & ~mask);
}
DCHECK_EQ(Test(obj), kSetBit);
return (old_word & mask) != 0;
diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc
index b43f77f..3df02ed 100644
--- a/runtime/gc/accounting/space_bitmap.cc
+++ b/runtime/gc/accounting/space_bitmap.cc
@@ -51,7 +51,9 @@
template<size_t kAlignment>
SpaceBitmap<kAlignment>::SpaceBitmap(const std::string& name, MemMap* mem_map, uintptr_t* bitmap_begin,
size_t bitmap_size, const void* heap_begin)
- : mem_map_(mem_map), bitmap_begin_(bitmap_begin), bitmap_size_(bitmap_size),
+ : mem_map_(mem_map),
+ bitmap_begin_(reinterpret_cast<Atomic<uintptr_t>*>(bitmap_begin)),
+ bitmap_size_(bitmap_size),
heap_begin_(reinterpret_cast<uintptr_t>(heap_begin)),
name_(name) {
CHECK(bitmap_begin_ != nullptr);
@@ -104,7 +106,12 @@
template<size_t kAlignment>
void SpaceBitmap<kAlignment>::CopyFrom(SpaceBitmap* source_bitmap) {
DCHECK_EQ(Size(), source_bitmap->Size());
- std::copy(source_bitmap->Begin(), source_bitmap->Begin() + source_bitmap->Size() / sizeof(intptr_t), Begin());
+ const size_t count = source_bitmap->Size() / sizeof(intptr_t);
+ Atomic<uintptr_t>* const src = source_bitmap->Begin();
+ Atomic<uintptr_t>* const dest = Begin();
+ for (size_t i = 0; i < count; ++i) {
+ dest[i].StoreRelaxed(src[i].LoadRelaxed());
+ }
}
template<size_t kAlignment>
@@ -113,9 +120,9 @@
CHECK(callback != nullptr);
uintptr_t end = OffsetToIndex(HeapLimit() - heap_begin_ - 1);
- uintptr_t* bitmap_begin = bitmap_begin_;
+ Atomic<uintptr_t>* bitmap_begin = bitmap_begin_;
for (uintptr_t i = 0; i <= end; ++i) {
- uintptr_t w = bitmap_begin[i];
+ uintptr_t w = bitmap_begin[i].LoadRelaxed();
if (w != 0) {
uintptr_t ptr_base = IndexToOffset(i) + heap_begin_;
do {
@@ -160,10 +167,10 @@
size_t start = OffsetToIndex(sweep_begin - live_bitmap.heap_begin_);
size_t end = OffsetToIndex(sweep_end - live_bitmap.heap_begin_ - 1);
CHECK_LT(end, live_bitmap.Size() / sizeof(intptr_t));
- uintptr_t* live = live_bitmap.bitmap_begin_;
- uintptr_t* mark = mark_bitmap.bitmap_begin_;
+ Atomic<uintptr_t>* live = live_bitmap.bitmap_begin_;
+ Atomic<uintptr_t>* mark = mark_bitmap.bitmap_begin_;
for (size_t i = start; i <= end; i++) {
- uintptr_t garbage = live[i] & ~mark[i];
+ uintptr_t garbage = live[i].LoadRelaxed() & ~mark[i].LoadRelaxed();
if (UNLIKELY(garbage != 0)) {
uintptr_t ptr_base = IndexToOffset(i) + live_bitmap.heap_begin_;
do {
@@ -251,7 +258,7 @@
uintptr_t end = Size() / sizeof(intptr_t);
for (uintptr_t i = 0; i < end; ++i) {
// Need uint for unsigned shift.
- uintptr_t w = bitmap_begin_[i];
+ uintptr_t w = bitmap_begin_[i].LoadRelaxed();
if (UNLIKELY(w != 0)) {
uintptr_t ptr_base = IndexToOffset(i) + heap_begin_;
while (w != 0) {
diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h
index b8ff471..829b1b1 100644
--- a/runtime/gc/accounting/space_bitmap.h
+++ b/runtime/gc/accounting/space_bitmap.h
@@ -147,7 +147,7 @@
void CopyFrom(SpaceBitmap* source_bitmap);
// Starting address of our internal storage.
- uintptr_t* Begin() {
+ Atomic<uintptr_t>* Begin() {
return bitmap_begin_;
}
@@ -215,7 +215,7 @@
std::unique_ptr<MemMap> mem_map_;
// This bitmap itself, word sized for efficiency in scanning.
- uintptr_t* const bitmap_begin_;
+ Atomic<uintptr_t>* const bitmap_begin_;
// Size of this bitmap.
size_t bitmap_size_;
diff --git a/runtime/gc/collector/concurrent_copying-inl.h b/runtime/gc/collector/concurrent_copying-inl.h
index fb774a4..76f500c 100644
--- a/runtime/gc/collector/concurrent_copying-inl.h
+++ b/runtime/gc/collector/concurrent_copying-inl.h
@@ -34,32 +34,27 @@
// to gray even though the object has already been marked through. This happens if a mutator
// thread gets preempted before the AtomicSetReadBarrierPointer below, GC marks through the
// object (changes it from white to gray and back to white), and the thread runs and
- // incorrectly changes it from white to gray. We need to detect such "false gray" cases and
- // change the objects back to white at the end of marking.
+ // incorrectly changes it from white to gray. If this happens, the object will get added to the
+ // mark stack again and get changed back to white after it is processed.
if (kUseBakerReadBarrier) {
- // Test the bitmap first to reduce the chance of false gray cases.
+ // Test the bitmap first to avoid graying an object that has already been marked through most
+ // of the time.
if (bitmap->Test(ref)) {
return ref;
}
}
// This may or may not succeed, which is ok because the object may already be gray.
- bool cas_success = false;
+ bool success = false;
if (kUseBakerReadBarrier) {
- cas_success = ref->AtomicSetReadBarrierPointer(ReadBarrier::WhitePtr(),
- ReadBarrier::GrayPtr());
- }
- if (bitmap->AtomicTestAndSet(ref)) {
- // Already marked.
- if (kUseBakerReadBarrier &&
- cas_success &&
- // The object could be white here if a thread gets preempted after a success at the
- // above AtomicSetReadBarrierPointer, GC has marked through it, and the thread runs up
- // to this point.
- ref->GetReadBarrierPointer() == ReadBarrier::GrayPtr()) {
- // Register a "false-gray" object to change it from gray to white at the end of marking.
- PushOntoFalseGrayStack(ref);
- }
+ // GC will mark the bitmap when popping from mark stack. If only the GC is touching the bitmap
+ // we can avoid an expensive CAS.
+ // For the baker case, an object is marked if either the mark bit marked or the bitmap bit is
+ // set.
+ success = ref->AtomicSetReadBarrierPointer(ReadBarrier::WhitePtr(), ReadBarrier::GrayPtr());
} else {
+ success = !bitmap->AtomicTestAndSet(ref);
+ }
+ if (success) {
// Newly marked.
if (kUseBakerReadBarrier) {
DCHECK_EQ(ref->GetReadBarrierPointer(), ReadBarrier::GrayPtr());
@@ -99,13 +94,16 @@
return ref;
}
-template<bool kGrayImmuneObject>
+template<bool kGrayImmuneObject, bool kFromGCThread>
inline mirror::Object* ConcurrentCopying::Mark(mirror::Object* from_ref) {
if (from_ref == nullptr) {
return nullptr;
}
DCHECK(heap_->collector_type_ == kCollectorTypeCC);
- if (UNLIKELY(kUseBakerReadBarrier && !is_active_)) {
+ if (kFromGCThread) {
+ DCHECK(is_active_);
+ DCHECK_EQ(Thread::Current(), thread_running_gc_);
+ } else if (UNLIKELY(kUseBakerReadBarrier && !is_active_)) {
// In the lock word forward address state, the read barrier bits
// in the lock word are part of the stored forwarding address and
// invalid. This is usually OK as the from-space copy of objects
@@ -192,6 +190,16 @@
}
}
+inline bool ConcurrentCopying::IsMarkedInUnevacFromSpace(mirror::Object* from_ref) {
+ // Use load acquire on the read barrier pointer to ensure that we never see a white read barrier
+ // pointer with an unmarked bit due to reordering.
+ DCHECK(region_space_->IsInUnevacFromSpace(from_ref));
+ if (kUseBakerReadBarrier && from_ref->GetReadBarrierPointerAcquire() == ReadBarrier::GrayPtr()) {
+ return true;
+ }
+ return region_space_bitmap_->Test(from_ref);
+}
+
} // namespace collector
} // namespace gc
} // namespace art
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 42816a0..85d307b 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -202,8 +202,10 @@
immune_spaces_.Reset();
bytes_moved_.StoreRelaxed(0);
objects_moved_.StoreRelaxed(0);
- if (GetCurrentIteration()->GetGcCause() == kGcCauseExplicit ||
- GetCurrentIteration()->GetGcCause() == kGcCauseForNativeAlloc ||
+ GcCause gc_cause = GetCurrentIteration()->GetGcCause();
+ if (gc_cause == kGcCauseExplicit ||
+ gc_cause == kGcCauseForNativeAlloc ||
+ gc_cause == kGcCauseCollectorTransition ||
GetCurrentIteration()->GetClearSoftReferences()) {
force_evacuate_all_ = true;
} else {
@@ -1302,8 +1304,19 @@
<< " " << to_ref << " " << to_ref->GetReadBarrierPointer()
<< " is_marked=" << IsMarked(to_ref);
}
- // Scan ref fields.
- Scan(to_ref);
+ bool add_to_live_bytes = false;
+ if (region_space_->IsInUnevacFromSpace(to_ref)) {
+ // Mark the bitmap only in the GC thread here so that we don't need a CAS.
+ if (!kUseBakerReadBarrier || !region_space_bitmap_->Set(to_ref)) {
+ // It may be already marked if we accidentally pushed the same object twice due to the racy
+ // bitmap read in MarkUnevacFromSpaceRegion.
+ Scan(to_ref);
+ // Only add to the live bytes if the object was not already marked.
+ add_to_live_bytes = true;
+ }
+ } else {
+ Scan(to_ref);
+ }
if (kUseBakerReadBarrier) {
DCHECK(to_ref->GetReadBarrierPointer() == ReadBarrier::GrayPtr())
<< " " << to_ref << " " << to_ref->GetReadBarrierPointer()
@@ -1332,7 +1345,7 @@
DCHECK(!kUseBakerReadBarrier);
#endif
- if (region_space_->IsInUnevacFromSpace(to_ref)) {
+ if (add_to_live_bytes) {
// Add to the live bytes per unevacuated from space. Note this code is always run by the
// GC-running thread (no synchronization required).
DCHECK(region_space_bitmap_->Test(to_ref));
@@ -1567,7 +1580,7 @@
// OK.
return;
} else if (region_space_->IsInUnevacFromSpace(ref)) {
- CHECK(region_space_bitmap_->Test(ref)) << ref;
+ CHECK(IsMarkedInUnevacFromSpace(ref)) << ref;
} else if (region_space_->IsInFromSpace(ref)) {
// Not OK. Do extra logging.
if (obj != nullptr) {
@@ -1614,7 +1627,7 @@
// OK.
return;
} else if (region_space_->IsInUnevacFromSpace(ref)) {
- CHECK(region_space_bitmap_->Test(ref)) << ref;
+ CHECK(IsMarkedInUnevacFromSpace(ref)) << ref;
} else if (region_space_->IsInFromSpace(ref)) {
// Not OK. Do extra logging.
if (gc_root_source == nullptr) {
@@ -1654,7 +1667,7 @@
LOG(INFO) << "holder is in the to-space.";
} else if (region_space_->IsInUnevacFromSpace(obj)) {
LOG(INFO) << "holder is in the unevac from-space.";
- if (region_space_bitmap_->Test(obj)) {
+ if (IsMarkedInUnevacFromSpace(obj)) {
LOG(INFO) << "holder is marked in the region space bitmap.";
} else {
LOG(INFO) << "holder is not marked in the region space bitmap.";
@@ -1783,7 +1796,7 @@
DCHECK_EQ(Thread::Current(), thread_running_gc_);
mirror::Object* ref = obj->GetFieldObject<
mirror::Object, kVerifyNone, kWithoutReadBarrier, false>(offset);
- mirror::Object* to_ref = Mark</*kGrayImmuneObject*/false>(ref);
+ mirror::Object* to_ref = Mark</*kGrayImmuneObject*/false, /*kFromGCThread*/true>(ref);
if (to_ref == ref) {
return;
}
@@ -2126,7 +2139,7 @@
heap_->non_moving_space_->HasAddress(to_ref))
<< "from_ref=" << from_ref << " to_ref=" << to_ref;
} else if (rtype == space::RegionSpace::RegionType::kRegionTypeUnevacFromSpace) {
- if (region_space_bitmap_->Test(from_ref)) {
+ if (IsMarkedInUnevacFromSpace(from_ref)) {
to_ref = from_ref;
} else {
to_ref = nullptr;
diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h
index 5b0e2d6..97f4555 100644
--- a/runtime/gc/collector/concurrent_copying.h
+++ b/runtime/gc/collector/concurrent_copying.h
@@ -104,7 +104,7 @@
DCHECK(ref != nullptr);
return IsMarked(ref) == ref;
}
- template<bool kGrayImmuneObject = true>
+ template<bool kGrayImmuneObject = true, bool kFromGCThread = false>
ALWAYS_INLINE mirror::Object* Mark(mirror::Object* from_ref)
SHARED_REQUIRES(Locks::mutator_lock_)
REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_);
@@ -179,6 +179,8 @@
REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_);
virtual mirror::Object* IsMarked(mirror::Object* from_ref) OVERRIDE
SHARED_REQUIRES(Locks::mutator_lock_);
+ bool IsMarkedInUnevacFromSpace(mirror::Object* from_ref)
+ SHARED_REQUIRES(Locks::mutator_lock_);
virtual bool IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* field) OVERRIDE
SHARED_REQUIRES(Locks::mutator_lock_);
void SweepSystemWeaks(Thread* self)
diff --git a/runtime/gc/collector_type.h b/runtime/gc/collector_type.h
index 7899a7c..b342cc7 100644
--- a/runtime/gc/collector_type.h
+++ b/runtime/gc/collector_type.h
@@ -40,6 +40,8 @@
kCollectorTypeHeapTrim,
// A (mostly) concurrent copying collector.
kCollectorTypeCC,
+ // The background compaction of the concurrent copying collector.
+ kCollectorTypeCCBackground,
// Instrumentation critical section fake collector.
kCollectorTypeInstrumentation,
// Fake collector for adding or removing application image spaces.
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 638c1d8..9e454ca 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -731,6 +731,7 @@
}
void Heap::DisableMovingGc() {
+ CHECK(!kUseReadBarrier);
if (IsMovingGc(foreground_collector_type_)) {
foreground_collector_type_ = kCollectorTypeCMS;
}
@@ -970,7 +971,8 @@
// Don't delay for debug builds since we may want to stress test the GC.
// If background_collector_type_ is kCollectorTypeHomogeneousSpaceCompact then we have
// special handling which does a homogenous space compaction once but then doesn't transition
- // the collector.
+ // the collector. Similarly, we invoke a full compaction for kCollectorTypeCC but don't
+ // transition the collector.
RequestCollectorTransition(background_collector_type_,
kIsDebugBuild ? 0 : kCollectorTransitionWait);
}
@@ -1384,6 +1386,16 @@
} else {
VLOG(gc) << "Homogeneous compaction ignored due to jank perceptible process state";
}
+ } else if (desired_collector_type == kCollectorTypeCCBackground) {
+ DCHECK(kUseReadBarrier);
+ if (!CareAboutPauseTimes()) {
+ // Invoke CC full compaction.
+ CollectGarbageInternal(collector::kGcTypeFull,
+ kGcCauseCollectorTransition,
+ /*clear_soft_references*/false);
+ } else {
+ VLOG(gc) << "CC background compaction ignored due to jank perceptible process state";
+ }
} else {
TransitionCollector(desired_collector_type);
}
@@ -1841,6 +1853,10 @@
break;
}
case kAllocatorTypeNonMoving: {
+ if (kUseReadBarrier) {
+ // DisableMovingGc() isn't compatible with CC.
+ break;
+ }
// Try to transition the heap if the allocation failure was due to the space being full.
if (!IsOutOfMemoryOnAllocation<false>(allocator, alloc_size)) {
// If we aren't out of memory then the OOM was probably from the non moving space being
@@ -2109,6 +2125,8 @@
}
void Heap::TransitionCollector(CollectorType collector_type) {
+ // Collector transition must not happen with CC
+ CHECK(!kUseReadBarrier);
if (collector_type == collector_type_) {
return;
}
@@ -3798,6 +3816,12 @@
if (desired_collector_type_ == collector_type_ || !CanAddHeapTask(self)) {
return;
}
+ if (collector_type_ == kCollectorTypeCC) {
+ // For CC, we invoke a full compaction when going to the background, but the collector type
+ // doesn't change.
+ DCHECK_EQ(desired_collector_type_, kCollectorTypeCCBackground);
+ }
+ DCHECK_NE(collector_type_, kCollectorTypeCCBackground);
CollectorTransitionTask* added_task = nullptr;
const uint64_t target_time = NanoTime() + delta_time;
{
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index be8ed40..b357b87 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -537,7 +537,7 @@
void DumpForSigQuit(std::ostream& os) REQUIRES(!*gc_complete_lock_, !native_histogram_lock_);
// Do a pending collector transition.
- void DoPendingCollectorTransition() REQUIRES(!*gc_complete_lock_);
+ void DoPendingCollectorTransition() REQUIRES(!*gc_complete_lock_, !*pending_task_lock_);
// Deflate monitors, ... and trim the spaces.
void Trim(Thread* self) REQUIRES(!*gc_complete_lock_);
@@ -708,8 +708,6 @@
if (IsGcConcurrent() && IsMovingGc(collector_type_)) {
// Assume no transition when a concurrent moving collector is used.
DCHECK_EQ(collector_type_, foreground_collector_type_);
- DCHECK_EQ(foreground_collector_type_, background_collector_type_)
- << "Assume no transition such that collector_type_ won't change";
return true;
}
return false;
@@ -828,6 +826,7 @@
collector_type == kCollectorTypeSS ||
collector_type == kCollectorTypeGSS ||
collector_type == kCollectorTypeCC ||
+ collector_type == kCollectorTypeCCBackground ||
collector_type == kCollectorTypeMC ||
collector_type == kCollectorTypeHomogeneousSpaceCompact;
}
@@ -997,7 +996,9 @@
// What kind of concurrency behavior is the runtime after? Currently true for concurrent mark
// sweep GC, false for other GC types.
bool IsGcConcurrent() const ALWAYS_INLINE {
- return collector_type_ == kCollectorTypeCMS || collector_type_ == kCollectorTypeCC;
+ return collector_type_ == kCollectorTypeCMS ||
+ collector_type_ == kCollectorTypeCC ||
+ collector_type_ == kCollectorTypeCCBackground;
}
// Trim the managed and native spaces by releasing unused memory back to the OS.
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index fd37737..227130e 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -623,10 +623,8 @@
break;
}
-#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
-#endif
case Instruction::CMPL_FLOAT: {
PREAMBLE();
@@ -694,9 +692,7 @@
break;
}
-#if defined(__clang__)
#pragma clang diagnostic pop
-#endif
case Instruction::CMP_LONG: {
PREAMBLE();
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index b35c958..927681c 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -63,19 +63,6 @@
options_(options) {
DCHECK(options_.IsEnabled());
AddTrackedLocations(output_filename, app_data_dir, code_paths);
- if (!app_data_dir.empty()) {
- // The application directory is used to determine which dex files are owned by app.
- // Since it could be a symlink (e.g. /data/data instead of /data/user/0), and we
- // don't have control over how the dex files are actually loaded (symlink or canonical path),
- // store it's canonical form to be sure we use the same base when comparing.
- UniqueCPtr<const char[]> app_data_dir_real_path(realpath(app_data_dir.c_str(), nullptr));
- if (app_data_dir_real_path != nullptr) {
- app_data_dirs_.emplace(app_data_dir_real_path.get());
- } else {
- LOG(WARNING) << "Failed to get the real path for app dir: " << app_data_dir
- << ". The app dir will not be used to determine which dex files belong to the app";
- }
- }
}
void ProfileSaver::Run() {
@@ -498,12 +485,18 @@
if (it == tracked_dex_base_locations_.end()) {
tracked_dex_base_locations_.Put(output_filename,
std::set<std::string>(code_paths.begin(), code_paths.end()));
- app_data_dirs_.insert(app_data_dir);
+ if (!app_data_dir.empty()) {
+ app_data_dirs_.insert(app_data_dir);
+ }
} else {
it->second.insert(code_paths.begin(), code_paths.end());
}
}
+// TODO(calin): This may lead to several calls to realpath.
+// Consider moving the logic to the saver thread (i.e. when notified,
+// only cache the location, and then wake up the saver thread to do the
+// comparisons with the real file paths and to create the markers).
void ProfileSaver::NotifyDexUse(const std::string& dex_location) {
if (!ShouldProfileLocation(dex_location)) {
return;
@@ -536,63 +529,32 @@
}
}
-bool ProfileSaver::MaybeRecordDexUseInternal(
- const std::string& dex_location,
- const std::set<std::string>& app_code_paths,
- const std::string& foreign_dex_profile_path,
- const std::set<std::string>& app_data_dirs) {
- if (dex_location.empty()) {
- LOG(WARNING) << "Asked to record foreign dex use with an empty dex location.";
- return false;
- }
- if (foreign_dex_profile_path.empty()) {
- LOG(WARNING) << "Asked to record foreign dex use without a valid profile path ";
- return false;
- }
-
- UniqueCPtr<const char[]> dex_location_real_path(realpath(dex_location.c_str(), nullptr));
- if (dex_location_real_path == nullptr) {
- PLOG(WARNING) << "Could not get realpath for " << dex_location;
- }
- std::string dex_location_real_path_str((dex_location_real_path == nullptr)
- ? dex_location.c_str()
- : dex_location_real_path.get());
-
- if (app_data_dirs.find(dex_location_real_path_str) != app_data_dirs.end()) {
- // The dex location is under the application folder. Nothing to record.
- return false;
- }
-
- if (app_code_paths.find(dex_location) != app_code_paths.end()) {
- // The dex location belongs to the application code paths. Nothing to record.
- return false;
- }
- // Do another round of checks with the real paths.
- // Note that we could cache all the real locations in the saver (since it's an expensive
- // operation). However we expect that app_code_paths is small (usually 1 element), and
- // NotifyDexUse is called just a few times in the app lifetime. So we make the compromise
- // to save some bytes of memory usage.
- for (const auto& app_code_location : app_code_paths) {
- UniqueCPtr<const char[]> real_app_code_location(realpath(app_code_location.c_str(), nullptr));
- if (real_app_code_location == nullptr) {
- PLOG(WARNING) << "Could not get realpath for " << app_code_location;
+static bool CheckContainsWithRealPath(const std::set<std::string>& paths_set,
+ const std::string& path_to_check) {
+ for (const auto& path : paths_set) {
+ UniqueCPtr<const char[]> real_path(realpath(path.c_str(), nullptr));
+ if (real_path == nullptr) {
+ PLOG(WARNING) << "Could not get realpath for " << path;
+ continue;
}
- std::string real_app_code_location_str((real_app_code_location == nullptr)
- ? app_code_location.c_str()
- : real_app_code_location.get());
- if (real_app_code_location_str == dex_location_real_path_str) {
- // The dex location belongs to the application code paths. Nothing to record.
- return false;
+ std::string real_path_str(real_path.get());
+ if (real_path_str == path_to_check) {
+ return true;
}
}
+ return false;
+}
+// After the call, dex_location_real_path will contain the marker's name.
+static bool CreateForeignDexMarker(const std::string& foreign_dex_profile_path,
+ /*in-out*/ std::string* dex_location_real_path) {
// For foreign dex files we record a flag on disk. PackageManager will (potentially) take this
// into account when deciding how to optimize the loaded dex file.
// The expected flag name is the canonical path of the apk where '/' is substituted to '@'.
// (it needs to be kept in sync with
// frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java)
- std::replace(dex_location_real_path_str.begin(), dex_location_real_path_str.end(), '/', '@');
- std::string flag_path = foreign_dex_profile_path + "/" + dex_location_real_path_str;
+ std::replace(dex_location_real_path->begin(), dex_location_real_path->end(), '/', '@');
+ std::string flag_path = foreign_dex_profile_path + "/" + *dex_location_real_path;
// We use O_RDONLY as the access mode because we must supply some access
// mode, and there is no access mode that means 'create but do not read' the
// file. We will not not actually read from the file.
@@ -614,6 +576,57 @@
}
}
+bool ProfileSaver::MaybeRecordDexUseInternal(
+ const std::string& dex_location,
+ const std::set<std::string>& app_code_paths,
+ const std::string& foreign_dex_profile_path,
+ const std::set<std::string>& app_data_dirs) {
+ if (dex_location.empty()) {
+ LOG(WARNING) << "Asked to record foreign dex use with an empty dex location.";
+ return false;
+ }
+ if (foreign_dex_profile_path.empty()) {
+ LOG(WARNING) << "Asked to record foreign dex use without a valid profile path ";
+ return false;
+ }
+
+ if (app_code_paths.find(dex_location) != app_code_paths.end()) {
+ // The dex location belongs to the application code paths. Nothing to record.
+ return false;
+ }
+
+ if (app_data_dirs.find(dex_location) != app_data_dirs.end()) {
+ // The dex location is under the application folder. Nothing to record.
+ return false;
+ }
+
+ // Do another round of checks with the real paths.
+ // Application directory could be a symlink (e.g. /data/data instead of /data/user/0), and we
+ // don't have control over how the dex files are actually loaded (symlink or canonical path),
+
+ // Note that we could cache all the real locations in the saver (since it's an expensive
+ // operation). However we expect that app_code_paths is small (usually 1 element), and
+ // NotifyDexUse is called just a few times in the app lifetime. So we make the compromise
+ // to save some bytes of memory usage.
+
+ UniqueCPtr<const char[]> dex_location_real_path(realpath(dex_location.c_str(), nullptr));
+ if (dex_location_real_path == nullptr) {
+ PLOG(WARNING) << "Could not get realpath for " << dex_location;
+ return false;
+ }
+ std::string dex_location_real_path_str(dex_location_real_path.get());
+
+ if (CheckContainsWithRealPath(app_code_paths, dex_location_real_path_str)) {
+ return false;
+ }
+
+ if (CheckContainsWithRealPath(app_data_dirs, dex_location_real_path_str)) {
+ return false;
+ }
+
+ return CreateForeignDexMarker(foreign_dex_profile_path, &dex_location_real_path_str);
+}
+
void ProfileSaver::DumpInstanceInfo(std::ostream& os) {
MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
if (instance_ != nullptr) {
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 0495c95..27f8bd7 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -147,6 +147,18 @@
#endif
}
+inline Object* Object::GetReadBarrierPointerAcquire() {
+#ifdef USE_BAKER_READ_BARRIER
+ DCHECK(kUseBakerReadBarrier);
+ LockWord lw(GetFieldAcquire<uint32_t>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_)));
+ return reinterpret_cast<Object*>(lw.ReadBarrierState());
+#else
+ LOG(FATAL) << "Unreachable";
+ UNREACHABLE();
+#endif
+}
+
+
inline uint32_t Object::GetMarkBit() {
#ifdef USE_READ_BARRIER
return GetLockWord(false).MarkBitState();
@@ -814,6 +826,13 @@
}
}
+template<typename kSize>
+inline kSize Object::GetFieldAcquire(MemberOffset field_offset) {
+ const uint8_t* raw_addr = reinterpret_cast<const uint8_t*>(this) + field_offset.Int32Value();
+ const kSize* addr = reinterpret_cast<const kSize*>(raw_addr);
+ return reinterpret_cast<const Atomic<kSize>*>(addr)->LoadAcquire();
+}
+
template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
inline bool Object::CasFieldWeakSequentiallyConsistent64(MemberOffset field_offset,
int64_t old_value, int64_t new_value) {
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 5b129bf..8649294 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -93,9 +93,12 @@
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
void SetClass(Class* new_klass) SHARED_REQUIRES(Locks::mutator_lock_);
- // TODO: Clean this up and change to return int32_t
+ // TODO: Clean these up and change to return int32_t
Object* GetReadBarrierPointer() SHARED_REQUIRES(Locks::mutator_lock_);
+ // Get the read barrier pointer with release semantics, only supported for baker.
+ Object* GetReadBarrierPointerAcquire() SHARED_REQUIRES(Locks::mutator_lock_);
+
#ifndef USE_BAKER_OR_BROOKS_READ_BARRIER
NO_RETURN
#endif
@@ -574,6 +577,10 @@
template<typename kSize, bool kIsVolatile>
ALWAYS_INLINE kSize GetField(MemberOffset field_offset)
SHARED_REQUIRES(Locks::mutator_lock_);
+ // Get a field with acquire semantics.
+ template<typename kSize>
+ ALWAYS_INLINE kSize GetFieldAcquire(MemberOffset field_offset)
+ SHARED_REQUIRES(Locks::mutator_lock_);
// Verify the type correctness of stores to fields.
// TODO: This can cause thread suspension and isn't moving GC safe.
diff --git a/runtime/openjdkjvm/Android.bp b/runtime/openjdkjvm/Android.bp
new file mode 100644
index 0000000..3e8dc8c
--- /dev/null
+++ b/runtime/openjdkjvm/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+ name: "libopenjdkjvm_defaults",
+ defaults: ["art_defaults"],
+ host_supported: true,
+ srcs: ["OpenjdkJvm.cc"],
+ include_dirs: ["art/runtime"],
+ shared_libs: ["libnativehelper"],
+}
+
+art_cc_library {
+ name: "libopenjdkjvm",
+ defaults: ["libopenjdkjvm_defaults"],
+ shared_libs: ["libart"],
+}
+
+art_cc_library {
+ name: "libopenjdkjvmd",
+ defaults: [
+ "libopenjdkjvm_defaults",
+ "art_debug_defaults",
+ ],
+ shared_libs: ["libartd"],
+}
diff --git a/runtime/openjdkjvm/Android.mk b/runtime/openjdkjvm/Android.mk
deleted file mode 100644
index 9b7404e..0000000
--- a/runtime/openjdkjvm/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := openjdkjvm-phony
-include $(BUILD_PHONY_PACKAGE)
diff --git a/runtime/openjdkjvmti/Android.bp b/runtime/openjdkjvmti/Android.bp
new file mode 100644
index 0000000..4430248
--- /dev/null
+++ b/runtime/openjdkjvmti/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+ name: "libopenjdkjvmti_defaults",
+ defaults: ["art_defaults"],
+ host_supported: true,
+ srcs: ["OpenjdkJvmTi.cc"],
+ include_dirs: ["art/runtime"],
+ shared_libs: ["libnativehelper"],
+}
+
+art_cc_library {
+ name: "libopenjdkjvmti",
+ defaults: ["libopenjdkjvmti_defaults"],
+ shared_libs: ["libart"],
+}
+
+art_cc_library {
+ name: "libopenjdkjvmtid",
+ defaults: [
+ "libopenjdkjvmti_defaults",
+ "art_debug_defaults",
+ ],
+ shared_libs: ["libartd"],
+}
diff --git a/runtime/openjdkjvmti/Android.mk b/runtime/openjdkjvmti/Android.mk
deleted file mode 100644
index 1de20e8..0000000
--- a/runtime/openjdkjvmti/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := openjdkjvmti-phony
-include $(BUILD_PHONY_PACKAGE)
diff --git a/runtime/simulator/Android.bp b/runtime/simulator/Android.bp
new file mode 100644
index 0000000..05f44e3
--- /dev/null
+++ b/runtime/simulator/Android.bp
@@ -0,0 +1,51 @@
+//
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_defaults {
+ name: "libart_simulator_defaults",
+ defaults: ["art_defaults"],
+ srcs: [
+ "code_simulator.cc",
+ "code_simulator_arm64.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ cflags: ["-DVIXL_INCLUDE_SIMULATOR_AARCH64"],
+ export_include_dirs: ["."],
+ include_dirs: ["art/runtime"],
+}
+
+cc_library_host_shared {
+ name: "libart-simulator",
+ defaults: ["libart_simulator_defaults"],
+ shared_libs: [
+ "libart",
+ "libvixl-arm64",
+ ],
+}
+
+cc_library_host_shared {
+ name: "libart-simulatord",
+ defaults: [
+ "libart_simulator_defaults",
+ "art_debug_defaults",
+ ],
+ shared_libs: [
+ "libartd",
+ "libvixld-arm64",
+ ],
+}
diff --git a/runtime/simulator/Android.mk b/runtime/simulator/Android.mk
deleted file mode 100644
index e39af2d..0000000
--- a/runtime/simulator/Android.mk
+++ /dev/null
@@ -1,111 +0,0 @@
-#
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include art/build/Android.common_build.mk
-
-LIBART_SIMULATOR_SRC_FILES := \
- code_simulator.cc \
- code_simulator_arm64.cc
-
-LIBART_SIMULATOR_CFLAGS := \
- -DVIXL_INCLUDE_SIMULATOR_AARCH64
-
-# $(1): target or host
-# $(2): ndebug or debug
-define build-libart-simulator
- ifneq ($(1),target)
- ifneq ($(1),host)
- $$(error expected target or host for argument 1, received $(1))
- endif
- endif
- ifneq ($(2),ndebug)
- ifneq ($(2),debug)
- $$(error expected ndebug or debug for argument 2, received $(2))
- endif
- endif
-
- art_target_or_host := $(1)
- art_ndebug_or_debug := $(2)
-
- include $(CLEAR_VARS)
- ifeq ($$(art_target_or_host),host)
- LOCAL_IS_HOST_MODULE := true
- endif
- LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
- ifeq ($$(art_ndebug_or_debug),ndebug)
- LOCAL_MODULE := libart-simulator
- else # debug
- LOCAL_MODULE := libartd-simulator
- endif
-
- LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-
- LOCAL_SRC_FILES := $$(LIBART_SIMULATOR_SRC_FILES)
- LOCAL_CFLAGS := $$(LIBART_SIMULATOR_CFLAGS)
-
- ifeq ($$(art_target_or_host),target)
- $(call set-target-local-clang-vars)
- $(call set-target-local-cflags-vars,$(2))
- else # host
- LOCAL_CLANG := $(ART_HOST_CLANG)
- LOCAL_LDLIBS := $(ART_HOST_LDLIBS)
- LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
- LOCAL_ASFLAGS += $(ART_HOST_ASFLAGS)
- ifeq ($$(art_ndebug_or_debug),debug)
- LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS)
- LOCAL_ASFLAGS += $(ART_HOST_DEBUG_ASFLAGS)
- else
- LOCAL_CFLAGS += $(ART_HOST_NON_DEBUG_CFLAGS)
- LOCAL_ASFLAGS += $(ART_HOST_NON_DEBUG_ASFLAGS)
- endif
- endif
-
- LOCAL_SHARED_LIBRARIES += liblog
- ifeq ($$(art_ndebug_or_debug),debug)
- LOCAL_SHARED_LIBRARIES += libartd
- else
- LOCAL_SHARED_LIBRARIES += libart
- endif
-
- LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime
- LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
- LOCAL_MULTILIB := both
-
- LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
- LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
- LOCAL_NATIVE_COVERAGE := $(ART_COVERAGE)
- # For simulator_arm64.
- ifeq ($$(art_ndebug_or_debug),debug)
- LOCAL_SHARED_LIBRARIES += libvixld-arm64
- else
- LOCAL_SHARED_LIBRARIES += libvixl-arm64
- endif
- ifeq ($$(art_target_or_host),target)
- include $(BUILD_SHARED_LIBRARY)
- else # host
- include $(BUILD_HOST_SHARED_LIBRARY)
- endif
-endef
-
-ifeq ($(ART_BUILD_HOST_NDEBUG),true)
- $(eval $(call build-libart-simulator,host,ndebug))
-endif
-ifeq ($(ART_BUILD_HOST_DEBUG),true)
- $(eval $(call build-libart-simulator,host,debug))
-endif
diff --git a/runtime/stack.h b/runtime/stack.h
index cf33ae1..850d2a4 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -224,7 +224,6 @@
int64_t GetVRegLong(size_t i) const {
DCHECK_LT(i, NumberOfVRegs());
const uint32_t* vreg = &vregs_[i];
- // Alignment attribute required for GCC 4.8
typedef const int64_t unaligned_int64 __attribute__ ((aligned (4)));
return *reinterpret_cast<unaligned_int64*>(vreg);
}
@@ -232,7 +231,6 @@
double GetVRegDouble(size_t i) const {
DCHECK_LT(i, NumberOfVRegs());
const uint32_t* vreg = &vregs_[i];
- // Alignment attribute required for GCC 4.8
typedef const double unaligned_double __attribute__ ((aligned (4)));
return *reinterpret_cast<unaligned_double*>(vreg);
}
@@ -289,7 +287,6 @@
void SetVRegLong(size_t i, int64_t val) {
DCHECK_LT(i, NumberOfVRegs());
uint32_t* vreg = &vregs_[i];
- // Alignment attribute required for GCC 4.8
typedef int64_t unaligned_int64 __attribute__ ((aligned (4)));
*reinterpret_cast<unaligned_int64*>(vreg) = val;
// This is needed for moving collectors since these can update the vreg references if they
@@ -303,7 +300,6 @@
void SetVRegDouble(size_t i, double val) {
DCHECK_LT(i, NumberOfVRegs());
uint32_t* vreg = &vregs_[i];
- // Alignment attribute required for GCC 4.8
typedef double unaligned_double __attribute__ ((aligned (4)));
*reinterpret_cast<unaligned_double*>(vreg) = val;
// This is needed for moving collectors since these can update the vreg references if they
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 688514c..ab1f198 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -60,7 +60,8 @@
// Whether we should try to dump the native stack of unattached threads. See commit ed8b723 for
// some history.
-static constexpr bool kDumpUnattachedThreadNativeStack = true;
+// Turned off again. b/29248079
+static constexpr bool kDumpUnattachedThreadNativeStack = false;
ThreadList::ThreadList()
: suspend_all_count_(0),
diff --git a/runtime/utils.h b/runtime/utils.h
index 84079e2..693e0b8 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -380,21 +380,7 @@
NO_RETURN void SleepForever();
inline void FlushInstructionCache(char* begin, char* end) {
- // Only use __builtin___clear_cache with Clang or with GCC >= 4.3.0
- // (__builtin___clear_cache was introduced in GCC 4.3.0).
-#if defined(__clang__) || GCC_VERSION >= 40300
__builtin___clear_cache(begin, end);
-#else
- // Only warn on non-Intel platforms, as x86 and x86-64 do not need
- // cache flush instructions, as long as the "code uses the same
- // linear address for modifying and fetching the instruction". See
- // "Intel(R) 64 and IA-32 Architectures Software Developer's Manual
- // Volume 3A: System Programming Guide, Part 1", section 11.6
- // "Self-Modifying Code".
-#if !defined(__i386__) && !defined(__x86_64__)
- UNIMPLEMENTED(WARNING) << "cache flush";
-#endif
-#endif
}
} // namespace art
diff --git a/sigchainlib/Android.bp b/sigchainlib/Android.bp
new file mode 100644
index 0000000..08af254
--- /dev/null
+++ b/sigchainlib/Android.bp
@@ -0,0 +1,53 @@
+//
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library {
+ name: "libsigchain",
+ host_supported: true,
+ defaults: ["art_defaults"],
+ shared: {
+ srcs: ["sigchain_dummy.cc"],
+ },
+ static: {
+ srcs: ["sigchain.cc"],
+ },
+ target: {
+ host: {
+ host_ldlibs: ["-ldl"],
+ },
+ android: {
+ shared_libs: ["liblog"],
+ },
+ },
+}
+
+// Create a dummy version of libsigchain which expose the necessary symbols
+// but throws when called. This can be used to get static binaries which don't
+// need the real functionality of the sig chain but need to please the linker.
+cc_library_static {
+ name: "libsigchain_dummy",
+ host_supported: true,
+ defaults: ["art_defaults"],
+ srcs: ["sigchain_dummy.cc"],
+ target: {
+ host: {
+ host_ldlibs: ["-ldl"],
+ },
+ android: {
+ shared_libs: ["liblog"],
+ },
+ },
+}
diff --git a/sigchainlib/Android.mk b/sigchainlib/Android.mk
deleted file mode 100644
index e1120e4..0000000
--- a/sigchainlib/Android.mk
+++ /dev/null
@@ -1,94 +0,0 @@
-#
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include art/build/Android.common_build.mk
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
-LOCAL_ASFLAGS += $(ART_TARGET_ASFLAGS)
-LOCAL_SRC_FILES := sigchain_dummy.cc
-LOCAL_CLANG := $(ART_TARGET_CLANG)
-LOCAL_MODULE:= libsigchain
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common_build.mk
-LOCAL_NATIVE_COVERAGE := $(ART_COVERAGE)
-$(eval $(call set-target-local-clang-vars))
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
-LOCAL_ASFLAGS += $(ART_TARGET_ASFLAGS)
-LOCAL_SRC_FILES := sigchain.cc
-LOCAL_CLANG := $(ART_TARGET_CLANG)
-LOCAL_MODULE:= libsigchain
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common_build.mk
-$(eval $(call set-target-local-clang-vars))
-include $(BUILD_STATIC_LIBRARY)
-
-# Build host library.
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
-LOCAL_MODULE_TAGS := optional
-LOCAL_IS_HOST_MODULE := true
-LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
-LOCAL_ASFLAGS += $(ART_HOST_ASFLAGS)
-LOCAL_CLANG := $(ART_HOST_CLANG)
-LOCAL_SRC_FILES := sigchain_dummy.cc
-LOCAL_MODULE:= libsigchain
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-LOCAL_LDLIBS := -ldl
-LOCAL_MULTILIB := both
-LOCAL_NATIVE_COVERAGE := $(ART_COVERAGE)
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
-LOCAL_MODULE_TAGS := optional
-LOCAL_IS_HOST_MODULE := true
-LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
-LOCAL_ASFLAGS += $(ART_HOST_ASFLAGS)
-LOCAL_CLANG := $(ART_HOST_CLANG)
-LOCAL_SRC_FILES := sigchain.cc
-LOCAL_MODULE:= libsigchain
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-LOCAL_LDLIBS := -ldl
-LOCAL_MULTILIB := both
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-# Create a dummy version of libsigchain which expose the necessary symbols
-# but throws when called. This can be used to get static binaries which don't
-# need the real functionality of the sig chain but need to please the linker.
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
-LOCAL_MODULE_TAGS := optional
-LOCAL_IS_HOST_MODULE := true
-LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
-LOCAL_CLANG := $(ART_HOST_CLANG)
-LOCAL_SRC_FILES := sigchain_dummy.cc
-LOCAL_MODULE:= libsigchain_dummy
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-LOCAL_LDLIBS := -ldl
-LOCAL_MULTILIB := both
-include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/test/551-implicit-null-checks/expected.txt b/test/551-implicit-null-checks/expected.txt
index e69de29..49b3771 100644
--- a/test/551-implicit-null-checks/expected.txt
+++ b/test/551-implicit-null-checks/expected.txt
@@ -0,0 +1,4 @@
+NPE from GetLong
+NPE from PutLong
+NPE from GetDouble
+NPE from PutDouble
diff --git a/test/551-implicit-null-checks/info.txt b/test/551-implicit-null-checks/info.txt
index bdd066b..bd3ecfd 100644
--- a/test/551-implicit-null-checks/info.txt
+++ b/test/551-implicit-null-checks/info.txt
@@ -1 +1 @@
-Test that implicit null checks are recorded correctly for longs.
\ No newline at end of file
+Test that implicit null checks are recorded correctly for longs and doubles.
diff --git a/test/551-implicit-null-checks/src/Main.java b/test/551-implicit-null-checks/src/Main.java
index 677e8d3..3586a29 100644
--- a/test/551-implicit-null-checks/src/Main.java
+++ b/test/551-implicit-null-checks/src/Main.java
@@ -18,6 +18,7 @@
private class Inner {
private long i1;
+ private double i2;
}
private Inner inst;
@@ -26,12 +27,22 @@
try {
m.$opt$noinline$testGetLong();
} catch (NullPointerException ex) {
- // good
+ System.out.println("NPE from GetLong");
}
try {
m.$opt$noinline$testPutLong(778899112233L);
} catch (NullPointerException ex) {
- // good
+ System.out.println("NPE from PutLong");
+ }
+ try {
+ m.$opt$noinline$testGetDouble();
+ } catch (NullPointerException ex) {
+ System.out.println("NPE from GetDouble");
+ }
+ try {
+ m.$opt$noinline$testPutDouble(1.0);
+ } catch (NullPointerException ex) {
+ System.out.println("NPE from PutDouble");
}
}
@@ -44,4 +55,14 @@
inst.i1 = a;
throw new Exception(); // prevent inline
}
+
+ public void $opt$noinline$testGetDouble() throws Exception {
+ double result = inst.i2;
+ throw new Exception(); // prevent inline
+ }
+
+ public void $opt$noinline$testPutDouble(double a) throws Exception {
+ inst.i2 = a;
+ throw new Exception(); // prevent inline
+ }
}
diff --git a/test/615-checker-arm64-zr-parallel-move/expected.txt b/test/615-checker-arm64-store-zero/expected.txt
similarity index 100%
rename from test/615-checker-arm64-zr-parallel-move/expected.txt
rename to test/615-checker-arm64-store-zero/expected.txt
diff --git a/test/615-checker-arm64-store-zero/info.txt b/test/615-checker-arm64-store-zero/info.txt
new file mode 100644
index 0000000..ac88eee
--- /dev/null
+++ b/test/615-checker-arm64-store-zero/info.txt
@@ -0,0 +1 @@
+Checker test to verify we correctly use wzr and xzr to store zero constants.
diff --git a/test/615-checker-arm64-store-zero/src/Main.java b/test/615-checker-arm64-store-zero/src/Main.java
new file mode 100644
index 0000000..c8ceb94
--- /dev/null
+++ b/test/615-checker-arm64-store-zero/src/Main.java
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+
+ public static boolean doThrow = false;
+
+ public void $noinline$foo(int in_w1,
+ int in_w2,
+ int in_w3,
+ int in_w4,
+ int in_w5,
+ int in_w6,
+ int in_w7,
+ int on_stack_int,
+ long on_stack_long,
+ float in_s0,
+ float in_s1,
+ float in_s2,
+ float in_s3,
+ float in_s4,
+ float in_s5,
+ float in_s6,
+ float in_s7,
+ float on_stack_float,
+ double on_stack_double) {
+ if (doThrow) throw new Error();
+ }
+
+ // We expect a parallel move that moves four times the zero constant to stack locations.
+ /// CHECK-START-ARM64: void Main.bar() register (after)
+ /// CHECK: ParallelMove {{.*#0->[0-9x]+\(sp\).*#0->[0-9x]+\(sp\).*#0->[0-9x]+\(sp\).*#0->[0-9x]+\(sp\).*}}
+
+ // Those four moves should generate four 'store' instructions using directly the zero register.
+ /// CHECK-START-ARM64: void Main.bar() disassembly (after)
+ /// CHECK-DAG: {{(str|stur)}} wzr, [sp, #{{[0-9]+}}]
+ /// CHECK-DAG: {{(str|stur)}} xzr, [sp, #{{[0-9]+}}]
+ /// CHECK-DAG: {{(str|stur)}} wzr, [sp, #{{[0-9]+}}]
+ /// CHECK-DAG: {{(str|stur)}} xzr, [sp, #{{[0-9]+}}]
+
+ public void bar() {
+ $noinline$foo(1, 2, 3, 4, 5, 6, 7, // Integral values in registers.
+ 0, 0L, // Integral values on the stack.
+ 1, 2, 3, 4, 5, 6, 7, 8, // Floating-point values in registers.
+ 0.0f, 0.0); // Floating-point values on the stack.
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_static_byte_field() disassembly (after)
+ /// CHECK: StaticFieldSet
+ /// CHECK-NEXT: strb wzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ public static byte static_byte_field;
+
+ public void store_zero_to_static_byte_field() {
+ static_byte_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_static_char_field() disassembly (after)
+ /// CHECK: StaticFieldSet
+ /// CHECK-NEXT: strh wzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ public static char static_char_field;
+
+ public void store_zero_to_static_char_field() {
+ static_char_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_static_short_field() disassembly (after)
+ /// CHECK: StaticFieldSet
+ /// CHECK-NEXT: strh wzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ public static short static_short_field;
+
+ public void store_zero_to_static_short_field() {
+ static_short_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_static_int_field() disassembly (after)
+ /// CHECK: StaticFieldSet
+ /// CHECK-NEXT: str wzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ public static int static_int_field;
+
+ public void store_zero_to_static_int_field() {
+ static_int_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_static_long_field() disassembly (after)
+ /// CHECK: StaticFieldSet
+ /// CHECK-NEXT: str xzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ public static long static_long_field;
+
+ public void store_zero_to_static_long_field() {
+ static_long_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_static_float_field() disassembly (after)
+ /// CHECK: StaticFieldSet
+ /// CHECK-NEXT: str wzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ public static float static_float_field;
+
+ public void store_zero_to_static_float_field() {
+ static_float_field = 0.0f;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_static_double_field() disassembly (after)
+ /// CHECK: StaticFieldSet
+ /// CHECK-NEXT: str xzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ public static double static_double_field;
+
+ public void store_zero_to_static_double_field() {
+ static_double_field = 0.0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_volatile_static_byte_field() disassembly (after)
+ /// CHECK: StaticFieldSet
+ /// CHECK-NEXT: add <<temp:x[0-9]+>>, x{{[0-9]+}}, #0x{{[0-9a-fA-F]+}}
+ /// CHECK-NEXT: stlrb wzr, [<<temp>>]
+
+ public static volatile byte volatile_static_byte_field;
+
+ public void store_zero_to_volatile_static_byte_field() {
+ volatile_static_byte_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_volatile_static_char_field() disassembly (after)
+ /// CHECK: StaticFieldSet
+ /// CHECK-NEXT: add <<temp:x[0-9]+>>, x{{[0-9]+}}, #0x{{[0-9a-fA-F]+}}
+ /// CHECK-NEXT: stlrh wzr, [<<temp>>]
+
+ public static volatile char volatile_static_char_field;
+
+ public void store_zero_to_volatile_static_char_field() {
+ volatile_static_char_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_volatile_static_short_field() disassembly (after)
+ /// CHECK: StaticFieldSet
+ /// CHECK-NEXT: add <<temp:x[0-9]+>>, x{{[0-9]+}}, #0x{{[0-9a-fA-F]+}}
+ /// CHECK-NEXT: stlrh wzr, [<<temp>>]
+
+ public static volatile short volatile_static_short_field;
+
+ public void store_zero_to_volatile_static_short_field() {
+ volatile_static_short_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_volatile_static_int_field() disassembly (after)
+ /// CHECK: StaticFieldSet
+ /// CHECK-NEXT: add <<temp:x[0-9]+>>, x{{[0-9]+}}, #0x{{[0-9a-fA-F]+}}
+ /// CHECK-NEXT: stlr wzr, [<<temp>>]
+
+ public static volatile int volatile_static_int_field;
+
+ public void store_zero_to_volatile_static_int_field() {
+ volatile_static_int_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_volatile_static_long_field() disassembly (after)
+ /// CHECK: StaticFieldSet
+ /// CHECK-NEXT: add <<temp:x[0-9]+>>, x{{[0-9]+}}, #0x{{[0-9a-fA-F]+}}
+ /// CHECK-NEXT: stlr xzr, [<<temp>>]
+
+ public static volatile long volatile_static_long_field;
+
+ public void store_zero_to_volatile_static_long_field() {
+ volatile_static_long_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_volatile_static_float_field() disassembly (after)
+ /// CHECK: StaticFieldSet
+ /// CHECK-NEXT: add <<temp:x[0-9]+>>, x{{[0-9]+}}, #0x{{[0-9a-fA-F]+}}
+ /// CHECK-NEXT: stlr wzr, [<<temp>>]
+
+ public static volatile float volatile_static_float_field;
+
+ public void store_zero_to_volatile_static_float_field() {
+ volatile_static_float_field = 0.0f;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_volatile_static_double_field() disassembly (after)
+ /// CHECK: StaticFieldSet
+ /// CHECK-NEXT: add <<temp:x[0-9]+>>, x{{[0-9]+}}, #0x{{[0-9a-fA-F]+}}
+ /// CHECK-NEXT: stlr xzr, [<<temp>>]
+
+ public static volatile double volatile_static_double_field;
+
+ public void store_zero_to_volatile_static_double_field() {
+ volatile_static_double_field = 0.0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_instance_byte_field() disassembly (after)
+ /// CHECK: InstanceFieldSet
+ /// CHECK-NEXT: strb wzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ public byte instance_byte_field;
+
+ public void store_zero_to_instance_byte_field() {
+ instance_byte_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_instance_char_field() disassembly (after)
+ /// CHECK: InstanceFieldSet
+ /// CHECK-NEXT: strh wzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ public char instance_char_field;
+
+ public void store_zero_to_instance_char_field() {
+ instance_char_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_instance_short_field() disassembly (after)
+ /// CHECK: InstanceFieldSet
+ /// CHECK-NEXT: strh wzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ public short instance_short_field;
+
+ public void store_zero_to_instance_short_field() {
+ instance_short_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_instance_int_field() disassembly (after)
+ /// CHECK: InstanceFieldSet
+ /// CHECK-NEXT: str wzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ public int instance_int_field;
+
+ public void store_zero_to_instance_int_field() {
+ instance_int_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_instance_long_field() disassembly (after)
+ /// CHECK: InstanceFieldSet
+ /// CHECK-NEXT: str xzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ public long instance_long_field;
+
+ public void store_zero_to_instance_long_field() {
+ instance_long_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_instance_float_field() disassembly (after)
+ /// CHECK: InstanceFieldSet
+ /// CHECK-NEXT: str wzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ public float instance_float_field;
+
+ public void store_zero_to_instance_float_field() {
+ instance_float_field = 0.0f;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_instance_double_field() disassembly (after)
+ /// CHECK: InstanceFieldSet
+ /// CHECK-NEXT: str xzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ public double instance_double_field;
+
+ public void store_zero_to_instance_double_field() {
+ instance_double_field = 0.0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_volatile_instance_byte_field() disassembly (after)
+ /// CHECK: InstanceFieldSet
+ /// CHECK-NEXT: add <<temp:x[0-9]+>>, x{{[0-9]+}}, #0x{{[0-9a-fA-F]+}}
+ /// CHECK-NEXT: stlrb wzr, [<<temp>>]
+
+ public volatile byte volatile_instance_byte_field;
+
+ public void store_zero_to_volatile_instance_byte_field() {
+ volatile_instance_byte_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_volatile_instance_char_field() disassembly (after)
+ /// CHECK: InstanceFieldSet
+ /// CHECK-NEXT: add <<temp:x[0-9]+>>, x{{[0-9]+}}, #0x{{[0-9a-fA-F]+}}
+ /// CHECK-NEXT: stlrh wzr, [<<temp>>]
+
+ public volatile char volatile_instance_char_field;
+
+ public void store_zero_to_volatile_instance_char_field() {
+ volatile_instance_char_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_volatile_instance_short_field() disassembly (after)
+ /// CHECK: InstanceFieldSet
+ /// CHECK-NEXT: add <<temp:x[0-9]+>>, x{{[0-9]+}}, #0x{{[0-9a-fA-F]+}}
+ /// CHECK-NEXT: stlrh wzr, [<<temp>>]
+
+ public volatile short volatile_instance_short_field;
+
+ public void store_zero_to_volatile_instance_short_field() {
+ volatile_instance_short_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_volatile_instance_int_field() disassembly (after)
+ /// CHECK: InstanceFieldSet
+ /// CHECK-NEXT: add <<temp:x[0-9]+>>, x{{[0-9]+}}, #0x{{[0-9a-fA-F]+}}
+ /// CHECK-NEXT: stlr wzr, [<<temp>>]
+
+ public volatile int volatile_instance_int_field;
+
+ public void store_zero_to_volatile_instance_int_field() {
+ volatile_instance_int_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_volatile_instance_long_field() disassembly (after)
+ /// CHECK: InstanceFieldSet
+ /// CHECK-NEXT: add <<temp:x[0-9]+>>, x{{[0-9]+}}, #0x{{[0-9a-fA-F]+}}
+ /// CHECK-NEXT: stlr xzr, [<<temp>>]
+
+ public volatile long volatile_instance_long_field;
+
+ public void store_zero_to_volatile_instance_long_field() {
+ volatile_instance_long_field = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_volatile_instance_float_field() disassembly (after)
+ /// CHECK: InstanceFieldSet
+ /// CHECK-NEXT: add <<temp:x[0-9]+>>, x{{[0-9]+}}, #0x{{[0-9a-fA-F]+}}
+ /// CHECK-NEXT: stlr wzr, [<<temp>>]
+
+ public volatile float volatile_instance_float_field;
+
+ public void store_zero_to_volatile_instance_float_field() {
+ volatile_instance_float_field = 0.0f;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_volatile_instance_double_field() disassembly (after)
+ /// CHECK: InstanceFieldSet
+ /// CHECK-NEXT: add <<temp:x[0-9]+>>, x{{[0-9]+}}, #0x{{[0-9a-fA-F]+}}
+ /// CHECK-NEXT: stlr xzr, [<<temp>>]
+
+ public volatile double volatile_instance_double_field;
+
+ public void store_zero_to_volatile_instance_double_field() {
+ volatile_instance_double_field = 0.0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_array_byte() disassembly (after)
+ /// CHECK: ArraySet
+ /// CHECK-NEXT: strb wzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ byte array_byte[];
+
+ public void store_zero_to_array_byte() {
+ array_byte[0] = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_array_char() disassembly (after)
+ /// CHECK: ArraySet
+ /// CHECK-NEXT: strh wzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ char array_char[];
+
+ public void store_zero_to_array_char() {
+ array_char[0] = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_array_short() disassembly (after)
+ /// CHECK: ArraySet
+ /// CHECK-NEXT: strh wzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ short array_short[];
+
+ public void store_zero_to_array_short() {
+ array_short[0] = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_array_int() disassembly (after)
+ /// CHECK: ArraySet
+ /// CHECK-NEXT: str wzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ int array_int[];
+
+ public void store_zero_to_array_int() {
+ array_int[0] = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_array_long() disassembly (after)
+ /// CHECK: ArraySet
+ /// CHECK-NEXT: str xzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ long array_long[];
+
+ public void store_zero_to_array_long() {
+ array_long[0] = 0;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_array_float() disassembly (after)
+ /// CHECK: ArraySet
+ /// CHECK-NEXT: str wzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ float array_float[];
+
+ public void store_zero_to_array_float() {
+ array_float[0] = 0.0f;
+ }
+
+ /// CHECK-START-ARM64: void Main.store_zero_to_array_double() disassembly (after)
+ /// CHECK: ArraySet
+ /// CHECK-NEXT: str xzr, [x{{[0-9]+}}, #{{[0-9]+}}]
+
+ double array_double[];
+
+ public void store_zero_to_array_double() {
+ array_double[0] = 0.0;
+ }
+
+ public static void main(String args[]) {
+ Main obj = new Main();
+ obj.array_byte = new byte[1];
+ obj.array_char = new char[1];
+ obj.array_short = new short[1];
+ obj.array_int = new int[1];
+ obj.array_long = new long[1];
+ obj.array_float = new float[1];
+ obj.array_double = new double[1];
+
+ obj.bar();
+ obj.store_zero_to_static_byte_field();
+ obj.store_zero_to_static_char_field();
+ obj.store_zero_to_static_short_field();
+ obj.store_zero_to_static_int_field();
+ obj.store_zero_to_static_long_field();
+ obj.store_zero_to_static_float_field();
+ obj.store_zero_to_static_double_field();
+ obj.store_zero_to_volatile_static_byte_field();
+ obj.store_zero_to_volatile_static_char_field();
+ obj.store_zero_to_volatile_static_short_field();
+ obj.store_zero_to_volatile_static_int_field();
+ obj.store_zero_to_volatile_static_long_field();
+ obj.store_zero_to_volatile_static_float_field();
+ obj.store_zero_to_volatile_static_double_field();
+ obj.store_zero_to_instance_byte_field();
+ obj.store_zero_to_instance_char_field();
+ obj.store_zero_to_instance_short_field();
+ obj.store_zero_to_instance_int_field();
+ obj.store_zero_to_instance_long_field();
+ obj.store_zero_to_instance_float_field();
+ obj.store_zero_to_instance_double_field();
+ obj.store_zero_to_volatile_instance_byte_field();
+ obj.store_zero_to_volatile_instance_char_field();
+ obj.store_zero_to_volatile_instance_short_field();
+ obj.store_zero_to_volatile_instance_int_field();
+ obj.store_zero_to_volatile_instance_long_field();
+ obj.store_zero_to_volatile_instance_float_field();
+ obj.store_zero_to_volatile_instance_double_field();
+ obj.store_zero_to_array_byte();
+ obj.store_zero_to_array_char();
+ obj.store_zero_to_array_short();
+ obj.store_zero_to_array_int();
+ obj.store_zero_to_array_long();
+ obj.store_zero_to_array_float();
+ obj.store_zero_to_array_double();
+ }
+}
diff --git a/test/615-checker-arm64-zr-parallel-move/info.txt b/test/615-checker-arm64-zr-parallel-move/info.txt
deleted file mode 100644
index 199755d..0000000
--- a/test/615-checker-arm64-zr-parallel-move/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-Checker test to verify we correctly use wzr and xzr to synthesize zero constants.
diff --git a/test/615-checker-arm64-zr-parallel-move/src/Main.java b/test/615-checker-arm64-zr-parallel-move/src/Main.java
deleted file mode 100644
index 5024f28..0000000
--- a/test/615-checker-arm64-zr-parallel-move/src/Main.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class Main {
-
- public static boolean doThrow = false;
-
- public void $noinline$foo(int in_w1,
- int in_w2,
- int in_w3,
- int in_w4,
- int in_w5,
- int in_w6,
- int in_w7,
- int on_stack_int,
- long on_stack_long,
- float in_s0,
- float in_s1,
- float in_s2,
- float in_s3,
- float in_s4,
- float in_s5,
- float in_s6,
- float in_s7,
- float on_stack_float,
- double on_stack_double) {
- if (doThrow) throw new Error();
- }
-
- // We expect a parallel move that moves four times the zero constant to stack locations.
- /// CHECK-START-ARM64: void Main.bar() register (after)
- /// CHECK: ParallelMove {{.*#0->[0-9x]+\(sp\).*#0->[0-9x]+\(sp\).*#0->[0-9x]+\(sp\).*#0->[0-9x]+\(sp\).*}}
-
- // Those four moves should generate four 'store' instructions using directly the zero register.
- /// CHECK-START-ARM64: void Main.bar() disassembly (after)
- /// CHECK-DAG: {{(str|stur)}} wzr, [sp, #{{[0-9]+}}]
- /// CHECK-DAG: {{(str|stur)}} xzr, [sp, #{{[0-9]+}}]
- /// CHECK-DAG: {{(str|stur)}} wzr, [sp, #{{[0-9]+}}]
- /// CHECK-DAG: {{(str|stur)}} xzr, [sp, #{{[0-9]+}}]
-
- public void bar() {
- $noinline$foo(1, 2, 3, 4, 5, 6, 7, // Integral values in registers.
- 0, 0L, // Integral values on the stack.
- 1, 2, 3, 4, 5, 6, 7, 8, // Floating-point values in registers.
- 0.0f, 0.0); // Floating-point values on the stack.
- }
-
- public static void main(String args[]) {}
-}
diff --git a/tools/bisection-search/README.md b/tools/bisection-search/README.md
new file mode 100644
index 0000000..857c930
--- /dev/null
+++ b/tools/bisection-search/README.md
@@ -0,0 +1,43 @@
+Bisection Bug Search
+====================
+
+Bisection Bug Search is a tool for finding compiler optimizations bugs. It
+accepts a program which exposes a bug by producing incorrect output and expected
+output for the program. It then attempts to narrow down the issue to a single
+method and optimization pass under the assumption that interpreter is correct.
+
+Given methods in order M0..Mn finds smallest i such that compiling Mi and
+interpreting all other methods produces incorrect output. Then, given ordered
+optimization passes P0..Pl, finds smallest j such that compiling Mi with passes
+P0..Pj-1 produces expected output and compiling Mi with passes P0..Pj produces
+incorrect output. Prints Mi and Pj.
+
+How to run Bisection Bug Search
+===============================
+
+ bisection_search.py [-h] -cp CLASSPATH
+ [--expected-output EXPECTED_OUTPUT] [--device]
+ [--lib LIB] [--64]
+ [--dalvikvm-option [OPTION [OPTION ...]]]
+ [--arg [TEST_ARGS [TEST_ARGS ...]]] [--image IMAGE]
+ [--verbose]
+ classname
+
+ positional arguments:
+ classname name of class to run
+
+ optional arguments:
+ -h, --help show this help message and exit
+ -cp CLASSPATH, --classpath CLASSPATH
+ classpath
+ --expected-output EXPECTED_OUTPUT
+ file containing expected output
+ --device run on device
+ --lib LIB lib to use, default: libart.so
+ --64 x64 mode
+ --dalvikvm-option [OPTION [OPTION ...]]
+ additional dalvikvm option
+ --arg [TEST_ARGS [TEST_ARGS ...]]
+ argument to pass to program
+ --image IMAGE path to image
+ --verbose enable verbose output
diff --git a/tools/bisection-search/bisection_search.py b/tools/bisection-search/bisection_search.py
new file mode 100755
index 0000000..d6c1749
--- /dev/null
+++ b/tools/bisection-search/bisection_search.py
@@ -0,0 +1,300 @@
+#!/usr/bin/env python3.4
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Performs bisection bug search on methods and optimizations.
+
+See README.md.
+
+Example usage:
+./bisection-search.py -cp classes.dex --expected-output output Test
+"""
+
+import argparse
+import re
+import sys
+
+from common import DeviceTestEnv
+from common import FatalError
+from common import GetEnvVariableOrError
+from common import HostTestEnv
+
+# Passes that are never disabled during search process because disabling them
+# would compromise correctness.
+MANDATORY_PASSES = ['dex_cache_array_fixups_arm',
+ 'dex_cache_array_fixups_mips',
+ 'instruction_simplifier$before_codegen',
+ 'pc_relative_fixups_x86',
+ 'pc_relative_fixups_mips',
+ 'x86_memory_operand_generation']
+
+# Passes that show up as optimizations in compiler verbose output but aren't
+# driven by run-passes mechanism. They are mandatory and will always run, we
+# never pass them to --run-passes.
+NON_PASSES = ['builder', 'prepare_for_register_allocation',
+ 'liveness', 'register']
+
+
+class Dex2OatWrapperTestable(object):
+ """Class representing a testable compilation.
+
+ Accepts filters on compiled methods and optimization passes.
+ """
+
+ def __init__(self, base_cmd, test_env, class_name, args,
+ expected_output=None, verbose=False):
+ """Constructor.
+
+ Args:
+ base_cmd: list of strings, base command to run.
+ test_env: ITestEnv.
+ class_name: string, name of class to run.
+ args: list of strings, program arguments to pass.
+ expected_output: string, expected output to compare against or None.
+ verbose: bool, enable verbose output.
+ """
+ self._base_cmd = base_cmd
+ self._test_env = test_env
+ self._class_name = class_name
+ self._args = args
+ self._expected_output = expected_output
+ self._compiled_methods_path = self._test_env.CreateFile('compiled_methods')
+ self._passes_to_run_path = self._test_env.CreateFile('run_passes')
+ self._verbose = verbose
+
+ def Test(self, compiled_methods, passes_to_run=None):
+ """Tests compilation with compiled_methods and run_passes switches active.
+
+ If compiled_methods is None then compiles all methods.
+ If passes_to_run is None then runs default passes.
+
+ Args:
+ compiled_methods: list of strings representing methods to compile or None.
+ passes_to_run: list of strings representing passes to run or None.
+
+ Returns:
+ True if test passes with given settings. False otherwise.
+ """
+ if self._verbose:
+ print('Testing methods: {0} passes:{1}.'.format(
+ compiled_methods, passes_to_run))
+ cmd = self._PrepareCmd(compiled_methods=compiled_methods,
+ passes_to_run=passes_to_run,
+ verbose_compiler=True)
+ (output, _, ret_code) = self._test_env.RunCommand(cmd)
+ res = ret_code == 0 and (self._expected_output is None
+ or output == self._expected_output)
+ if self._verbose:
+ print('Test passed: {0}.'.format(res))
+ return res
+
+ def GetAllMethods(self):
+ """Get methods compiled during the test.
+
+ Returns:
+ List of strings representing methods compiled during the test.
+
+ Raises:
+ FatalError: An error occurred when retrieving methods list.
+ """
+ cmd = self._PrepareCmd(verbose_compiler=True)
+ (_, err_output, _) = self._test_env.RunCommand(cmd)
+ match_methods = re.findall(r'Building ([^\n]+)\n', err_output)
+ if not match_methods:
+ raise FatalError('Failed to retrieve methods list. '
+ 'Not recognized output format.')
+ return match_methods
+
+ def GetAllPassesForMethod(self, compiled_method):
+ """Get all optimization passes ran for a method during the test.
+
+ Args:
+ compiled_method: string representing method to compile.
+
+ Returns:
+ List of strings representing passes ran for compiled_method during test.
+
+ Raises:
+ FatalError: An error occurred when retrieving passes list.
+ """
+ cmd = self._PrepareCmd(compiled_methods=[compiled_method],
+ verbose_compiler=True)
+ (_, err_output, _) = self._test_env.RunCommand(cmd)
+ match_passes = re.findall(r'Starting pass: ([^\n]+)\n', err_output)
+ if not match_passes:
+ raise FatalError('Failed to retrieve passes list. '
+ 'Not recognized output format.')
+ return [p for p in match_passes if p not in NON_PASSES]
+
+ def _PrepareCmd(self, compiled_methods=None, passes_to_run=None,
+ verbose_compiler=False):
+ """Prepare command to run."""
+ cmd = list(self._base_cmd)
+ if compiled_methods is not None:
+ self._test_env.WriteLines(self._compiled_methods_path, compiled_methods)
+ cmd += ['-Xcompiler-option', '--compiled-methods={0}'.format(
+ self._compiled_methods_path)]
+ if passes_to_run is not None:
+ self._test_env.WriteLines(self._passes_to_run_path, passes_to_run)
+ cmd += ['-Xcompiler-option', '--run-passes={0}'.format(
+ self._passes_to_run_path)]
+ if verbose_compiler:
+ cmd += ['-Xcompiler-option', '--runtime-arg', '-Xcompiler-option',
+ '-verbose:compiler']
+ cmd += ['-classpath', self._test_env.classpath, self._class_name]
+ cmd += self._args
+ return cmd
+
+
+def BinarySearch(start, end, test):
+ """Binary search integers using test function to guide the process."""
+ while start < end:
+ mid = (start + end) // 2
+ if test(mid):
+ start = mid + 1
+ else:
+ end = mid
+ return start
+
+
+def FilterPasses(passes, cutoff_idx):
+ """Filters passes list according to cutoff_idx but keeps mandatory passes."""
+ return [opt_pass for idx, opt_pass in enumerate(passes)
+ if opt_pass in MANDATORY_PASSES or idx < cutoff_idx]
+
+
+def BugSearch(testable):
+ """Find buggy (method, optimization pass) pair for a given testable.
+
+ Args:
+ testable: Dex2OatWrapperTestable.
+
+ Returns:
+ (string, string) tuple. First element is name of method which when compiled
+ exposes test failure. Second element is name of optimization pass such that
+ for aforementioned method running all passes up to and excluding the pass
+ results in test passing but running all passes up to and including the pass
+ results in test failing.
+
+ (None, None) if test passes when compiling all methods.
+ (string, None) if a method is found which exposes the failure, but the
+ failure happens even when running just mandatory passes.
+
+ Raises:
+ FatalError: Testable fails with no methods compiled.
+ AssertionError: Method failed for all passes when bisecting methods, but
+ passed when bisecting passes. Possible sporadic failure.
+ """
+ all_methods = testable.GetAllMethods()
+ faulty_method_idx = BinarySearch(
+ 0,
+ len(all_methods),
+ lambda mid: testable.Test(all_methods[0:mid]))
+ if faulty_method_idx == len(all_methods):
+ return (None, None)
+ if faulty_method_idx == 0:
+ raise FatalError('Testable fails with no methods compiled. '
+ 'Perhaps issue lies outside of compiler.')
+ faulty_method = all_methods[faulty_method_idx - 1]
+ all_passes = testable.GetAllPassesForMethod(faulty_method)
+ faulty_pass_idx = BinarySearch(
+ 0,
+ len(all_passes),
+ lambda mid: testable.Test([faulty_method],
+ FilterPasses(all_passes, mid)))
+ if faulty_pass_idx == 0:
+ return (faulty_method, None)
+ assert faulty_pass_idx != len(all_passes), 'Method must fail for some passes.'
+ faulty_pass = all_passes[faulty_pass_idx - 1]
+ return (faulty_method, faulty_pass)
+
+
+def PrepareParser():
+ """Prepares argument parser."""
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '-cp', '--classpath', required=True, type=str, help='classpath')
+ parser.add_argument('--expected-output', type=str,
+ help='file containing expected output')
+ parser.add_argument(
+ '--device', action='store_true', default=False, help='run on device')
+ parser.add_argument('classname', type=str, help='name of class to run')
+ parser.add_argument('--lib', dest='lib', type=str, default='libart.so',
+ help='lib to use, default: libart.so')
+ parser.add_argument('--64', dest='x64', action='store_true',
+ default=False, help='x64 mode')
+ parser.add_argument('--dalvikvm-option', dest='dalvikvm_opts',
+ metavar='OPTION', nargs='*', default=[],
+ help='additional dalvikvm option')
+ parser.add_argument('--arg', dest='test_args', nargs='*', default=[],
+ help='argument to pass to program')
+ parser.add_argument('--image', type=str, help='path to image')
+ parser.add_argument('--verbose', action='store_true',
+ default=False, help='enable verbose output')
+ return parser
+
+
+def main():
+ # Parse arguments
+ parser = PrepareParser()
+ args = parser.parse_args()
+
+ # Prepare environment
+ if args.expected_output is not None:
+ with open(args.expected_output, 'r') as f:
+ expected_output = f.read()
+ else:
+ expected_output = None
+ if args.device:
+ run_cmd = ['dalvikvm64'] if args.x64 else ['dalvikvm32']
+ test_env = DeviceTestEnv(args.classpath)
+ else:
+ run_cmd = ['dalvikvm64'] if args.x64 else ['dalvikvm32']
+ run_cmd += ['-XXlib:{0}'.format(args.lib)]
+ if not args.image:
+ image_path = '{0}/framework/core-optimizing-pic.art'.format(
+ GetEnvVariableOrError('ANDROID_HOST_OUT'))
+ else:
+ image_path = args.image
+ run_cmd += ['-Ximage:{0}'.format(image_path)]
+ if args.dalvikvm_opts:
+ run_cmd += args.dalvikvm_opts
+ test_env = HostTestEnv(args.classpath, args.x64)
+
+ # Perform the search
+ try:
+ testable = Dex2OatWrapperTestable(run_cmd, test_env, args.classname,
+ args.test_args, expected_output,
+ args.verbose)
+ (method, opt_pass) = BugSearch(testable)
+ except Exception as e:
+ print('Error. Refer to logfile: {0}'.format(test_env.logfile.name))
+ test_env.logfile.write('Exception: {0}\n'.format(e))
+ raise
+
+ # Report results
+ if method is None:
+ print('Couldn\'t find any bugs.')
+ elif opt_pass is None:
+ print('Faulty method: {0}. Fails with just mandatory passes.'.format(
+ method))
+ else:
+ print('Faulty method and pass: {0}, {1}.'.format(method, opt_pass))
+ print('Logfile: {0}'.format(test_env.logfile.name))
+ sys.exit(0)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/bisection-search/bisection_test.py b/tools/bisection-search/bisection_test.py
new file mode 100755
index 0000000..9aa08fb
--- /dev/null
+++ b/tools/bisection-search/bisection_test.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python3.4
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Tests for bisection-search module."""
+
+import unittest
+
+from unittest.mock import Mock
+
+from bisection_search import BugSearch
+from bisection_search import Dex2OatWrapperTestable
+from bisection_search import FatalError
+from bisection_search import MANDATORY_PASSES
+
+
+class BisectionTestCase(unittest.TestCase):
+ """BugSearch method test case.
+
+ Integer constants were chosen arbitrarily. They should be large enough and
+ random enough to ensure binary search does nontrivial work.
+
+ Attributes:
+ _METHODS: list of strings, methods compiled by testable
+ _PASSES: list of strings, passes run by testable
+ _FAILING_METHOD: string, name of method which fails in some tests
+ _FAILING_PASS: string, name of pass which fails in some tests
+ _MANDATORY_PASS: string, name of a mandatory pass
+ """
+ _METHODS_COUNT = 1293
+ _PASSES_COUNT = 573
+ _FAILING_METHOD_IDX = 237
+ _FAILING_PASS_IDX = 444
+ _METHODS = ['method_{0}'.format(i) for i in range(_METHODS_COUNT)]
+ _PASSES = ['pass_{0}'.format(i) for i in range(_PASSES_COUNT)]
+ _FAILING_METHOD = _METHODS[_FAILING_METHOD_IDX]
+ _FAILING_PASS = _PASSES[_FAILING_PASS_IDX]
+ _MANDATORY_PASS = MANDATORY_PASSES[0]
+
+ def setUp(self):
+ self.testable_mock = Mock(spec=Dex2OatWrapperTestable)
+ self.testable_mock.GetAllMethods.return_value = self._METHODS
+ self.testable_mock.GetAllPassesForMethod.return_value = self._PASSES
+
+ def MethodFailsForAllPasses(self, compiled_methods, run_passes=None):
+ return self._FAILING_METHOD not in compiled_methods
+
+ def MethodFailsForAPass(self, compiled_methods, run_passes=None):
+ return (self._FAILING_METHOD not in compiled_methods or
+ (run_passes is not None and self._FAILING_PASS not in run_passes))
+
+ def testNeverFails(self):
+ self.testable_mock.Test.return_value = True
+ res = BugSearch(self.testable_mock)
+ self.assertEqual(res, (None, None))
+
+ def testAlwaysFails(self):
+ self.testable_mock.Test.return_value = False
+ with self.assertRaises(FatalError):
+ BugSearch(self.testable_mock)
+
+ def testAMethodFailsForAllPasses(self):
+ self.testable_mock.Test.side_effect = self.MethodFailsForAllPasses
+ res = BugSearch(self.testable_mock)
+ self.assertEqual(res, (self._FAILING_METHOD, None))
+
+ def testAMethodFailsForAPass(self):
+ self.testable_mock.Test.side_effect = self.MethodFailsForAPass
+ res = BugSearch(self.testable_mock)
+ self.assertEqual(res, (self._FAILING_METHOD, self._FAILING_PASS))
+
+ def testMandatoryPassPresent(self):
+ self.testable_mock.GetAllPassesForMethod.return_value += (
+ [self._MANDATORY_PASS])
+ self.testable_mock.Test.side_effect = self.MethodFailsForAPass
+ BugSearch(self.testable_mock)
+ for (ordered_args, keyword_args) in self.testable_mock.Test.call_args_list:
+ passes = None
+ if 'run_passes' in keyword_args:
+ passes = keyword_args['run_passes']
+ if len(ordered_args) > 1: # run_passes passed as ordered argument
+ passes = ordered_args[1]
+ if passes is not None:
+ self.assertIn(self._MANDATORY_PASS, passes)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tools/bisection-search/common.py b/tools/bisection-search/common.py
new file mode 100755
index 0000000..8361fc9
--- /dev/null
+++ b/tools/bisection-search/common.py
@@ -0,0 +1,318 @@
+#!/usr/bin/env python3.4
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Module containing common logic from python testing tools."""
+
+import abc
+import os
+import shlex
+
+from subprocess import check_call
+from subprocess import PIPE
+from subprocess import Popen
+from subprocess import TimeoutExpired
+
+from tempfile import mkdtemp
+from tempfile import NamedTemporaryFile
+
+# Temporary directory path on device.
+DEVICE_TMP_PATH = '/data/local/tmp'
+
+# Architectures supported in dalvik cache.
+DALVIK_CACHE_ARCHS = ['arm', 'arm64', 'x86', 'x86_64']
+
+
+def GetEnvVariableOrError(variable_name):
+ """Gets value of an environmental variable.
+
+ If the variable is not set raises FatalError.
+
+ Args:
+ variable_name: string, name of variable to get.
+
+ Returns:
+ string, value of requested variable.
+
+ Raises:
+ FatalError: Requested variable is not set.
+ """
+ top = os.environ.get(variable_name)
+ if top is None:
+ raise FatalError('{0} environmental variable not set.'.format(
+ variable_name))
+ return top
+
+
+def _DexArchCachePaths(android_data_path):
+ """Returns paths to architecture specific caches.
+
+ Args:
+ android_data_path: string, path dalvik-cache resides in.
+
+ Returns:
+ Iterable paths to architecture specific caches.
+ """
+ return ('{0}/dalvik-cache/{1}'.format(android_data_path, arch)
+ for arch in DALVIK_CACHE_ARCHS)
+
+
+def _RunCommandForOutputAndLog(cmd, env, logfile, timeout=60):
+ """Runs command and logs its output. Returns the output.
+
+ Args:
+ cmd: list of strings, command to run.
+ env: shell environment to run the command with.
+ logfile: file handle to logfile.
+ timeout: int, timeout in seconds
+
+ Returns:
+ tuple (string, string, int) stdout output, stderr output, return code.
+ """
+ proc = Popen(cmd, stderr=PIPE, stdout=PIPE, env=env, universal_newlines=True)
+ timeouted = False
+ try:
+ (output, err_output) = proc.communicate(timeout=timeout)
+ except TimeoutExpired:
+ timeouted = True
+ proc.kill()
+ (output, err_output) = proc.communicate()
+ logfile.write('Command:\n{0}\n{1}{2}\nReturn code: {3}\n'.format(
+ _CommandListToCommandString(cmd), err_output, output,
+ 'TIMEOUT' if timeouted else proc.returncode))
+ ret_code = 1 if timeouted else proc.returncode
+ return (output, err_output, ret_code)
+
+
+def _CommandListToCommandString(cmd):
+ """Converts shell command represented as list of strings to a single string.
+
+ Each element of the list is wrapped in double quotes.
+
+ Args:
+ cmd: list of strings, shell command.
+
+ Returns:
+ string, shell command.
+ """
+ return ' '.join(['"{0}"'.format(segment) for segment in cmd])
+
+
+class FatalError(Exception):
+ """Fatal error in script."""
+
+
+class ITestEnv(object):
+ """Test environment abstraction.
+
+ Provides unified interface for interacting with host and device test
+ environments. Creates a test directory and expose methods to modify test files
+ and run commands.
+ """
+ __meta_class__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def CreateFile(self, name=None):
+ """Creates a file in test directory.
+
+ Returned path to file can be used in commands run in the environment.
+
+ Args:
+ name: string, file name. If None file is named arbitrarily.
+
+ Returns:
+ string, environment specific path to file.
+ """
+
+ @abc.abstractmethod
+ def WriteLines(self, file_path, lines):
+ """Writes lines to a file in test directory.
+
+ If file exists it gets overwritten. If file doest not exist it is created.
+
+ Args:
+ file_path: string, environment specific path to file.
+ lines: list of strings to write.
+ """
+
+ @abc.abstractmethod
+ def RunCommand(self, cmd):
+ """Runs command in environment.
+
+ Args:
+ cmd: string, command to run.
+
+ Returns:
+ tuple (string, string, int) stdout output, stderr output, return code.
+ """
+
+ @abc.abstractproperty
+ def classpath(self):
+ """Gets environment specific classpath with test class."""
+
+ @abc.abstractproperty
+ def logfile(self):
+ """Gets file handle to logfile residing on host."""
+
+
+class HostTestEnv(ITestEnv):
+ """Host test environment. Concrete implementation of ITestEnv.
+
+ Maintains a test directory in /tmp/. Runs commands on the host in modified
+ shell environment. Mimics art script behavior.
+
+ For methods documentation see base class.
+ """
+
+ def __init__(self, classpath, x64):
+ """Constructor.
+
+ Args:
+ classpath: string, classpath with test class.
+ x64: boolean, whether to setup in x64 mode.
+ """
+ self._classpath = classpath
+ self._env_path = mkdtemp(dir='/tmp/', prefix='bisection_search_')
+ self._logfile = open('{0}/log'.format(self._env_path), 'w+')
+ os.mkdir('{0}/dalvik-cache'.format(self._env_path))
+ for arch_cache_path in _DexArchCachePaths(self._env_path):
+ os.mkdir(arch_cache_path)
+ lib = 'lib64' if x64 else 'lib'
+ android_root = GetEnvVariableOrError('ANDROID_HOST_OUT')
+ library_path = android_root + '/' + lib
+ path = android_root + '/bin'
+ self._shell_env = os.environ.copy()
+ self._shell_env['ANDROID_DATA'] = self._env_path
+ self._shell_env['ANDROID_ROOT'] = android_root
+ self._shell_env['LD_LIBRARY_PATH'] = library_path
+ self._shell_env['PATH'] = (path + ':' + self._shell_env['PATH'])
+ # Using dlopen requires load bias on the host.
+ self._shell_env['LD_USE_LOAD_BIAS'] = '1'
+
+ def CreateFile(self, name=None):
+ if name is None:
+ f = NamedTemporaryFile(dir=self._env_path, delete=False)
+ else:
+ f = open('{0}/{1}'.format(self._env_path, name), 'w+')
+ return f.name
+
+ def WriteLines(self, file_path, lines):
+ with open(file_path, 'w') as f:
+ f.writelines('{0}\n'.format(line) for line in lines)
+ return
+
+ def RunCommand(self, cmd):
+ self._EmptyDexCache()
+ return _RunCommandForOutputAndLog(cmd, self._shell_env, self._logfile)
+
+ @property
+ def classpath(self):
+ return self._classpath
+
+ @property
+ def logfile(self):
+ return self._logfile
+
+ def _EmptyDexCache(self):
+ """Empties dex cache.
+
+ Iterate over files in architecture specific cache directories and remove
+ them.
+ """
+ for arch_cache_path in _DexArchCachePaths(self._env_path):
+ for file_path in os.listdir(arch_cache_path):
+ file_path = '{0}/{1}'.format(arch_cache_path, file_path)
+ if os.path.isfile(file_path):
+ os.unlink(file_path)
+
+
+class DeviceTestEnv(ITestEnv):
+ """Device test environment. Concrete implementation of ITestEnv.
+
+ Makes use of HostTestEnv to maintain a test directory on host. Creates an
+ on device test directory which is kept in sync with the host one.
+
+ For methods documentation see base class.
+ """
+
+ def __init__(self, classpath):
+ """Constructor.
+
+ Args:
+ classpath: string, classpath with test class.
+ """
+ self._host_env_path = mkdtemp(dir='/tmp/', prefix='bisection_search_')
+ self._logfile = open('{0}/log'.format(self._host_env_path), 'w+')
+ self._device_env_path = '{0}/{1}'.format(
+ DEVICE_TMP_PATH, os.path.basename(self._host_env_path))
+ self._classpath = os.path.join(
+ self._device_env_path, os.path.basename(classpath))
+ self._shell_env = os.environ
+
+ self._AdbMkdir('{0}/dalvik-cache'.format(self._device_env_path))
+ for arch_cache_path in _DexArchCachePaths(self._device_env_path):
+ self._AdbMkdir(arch_cache_path)
+
+ paths = classpath.split(':')
+ device_paths = []
+ for path in paths:
+ device_paths.append('{0}/{1}'.format(
+ self._device_env_path, os.path.basename(path)))
+ self._AdbPush(path, self._device_env_path)
+ self._classpath = ':'.join(device_paths)
+
+ def CreateFile(self, name=None):
+ with NamedTemporaryFile(mode='w') as temp_file:
+ self._AdbPush(temp_file.name, self._device_env_path)
+ if name is None:
+ name = os.path.basename(temp_file.name)
+ return '{0}/{1}'.format(self._device_env_path, name)
+
+ def WriteLines(self, file_path, lines):
+ with NamedTemporaryFile(mode='w') as temp_file:
+ temp_file.writelines('{0}\n'.format(line) for line in lines)
+ self._AdbPush(temp_file.name, file_path)
+ return
+
+ def RunCommand(self, cmd):
+ self._EmptyDexCache()
+ cmd = _CommandListToCommandString(cmd)
+ cmd = ('adb shell "logcat -c && ANDROID_DATA={0} {1} && '
+ 'logcat -d dex2oat:* *:S 1>&2"').format(self._device_env_path, cmd)
+ return _RunCommandForOutputAndLog(shlex.split(cmd), self._shell_env,
+ self._logfile)
+
+ @property
+ def classpath(self):
+ return self._classpath
+
+ @property
+ def logfile(self):
+ return self._logfile
+
+ def _AdbPush(self, what, where):
+ check_call(shlex.split('adb push "{0}" "{1}"'.format(what, where)),
+ stdout=self._logfile, stderr=self._logfile)
+
+ def _AdbMkdir(self, path):
+ check_call(shlex.split('adb shell mkdir "{0}" -p'.format(path)),
+ stdout=self._logfile, stderr=self._logfile)
+
+ def _EmptyDexCache(self):
+ """Empties dex cache."""
+ for arch_cache_path in _DexArchCachePaths(self._device_env_path):
+ cmd = 'adb shell if [ -d "{0}" ]; then rm -f "{0}"/*; fi'.format(
+ arch_cache_path)
+ check_call(shlex.split(cmd), stdout=self._logfile, stderr=self._logfile)
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index cbb6e1d..6472c8d 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -220,13 +220,6 @@
names: [ "libcore.java.io.FileTest#testJavaIoTmpdirMutable" ]
},
{
- description: "Made for extending, shouldn't be run",
- result: EXEC_FAILED,
- names: ["jsr166.CollectionTest#testEmptyMeansEmpty",
- "jsr166.Collection8Test#testForEach",
- "jsr166.Collection8Test#testForEachConcurrentStressTest"]
-},
-{
description: "Flaky test",
result: EXEC_FAILED,
bug: 30107038,