Merge "ARM64: Use macros for increasing and decreasing frame size."
diff --git a/Android.bp b/Android.bp
index 835048d..77b9ac3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,6 +1,34 @@
+// TODO: These should be handled with transitive static library dependencies
+art_static_dependencies = [
+ // Note: the order is important because of static linking resolution.
+ "libziparchive",
+ "libnativehelper",
+ "libnativebridge",
+ "libnativeloader",
+ "libsigchain_dummy",
+ "liblog",
+ "libz",
+ "libbacktrace",
+ "libcutils",
+ "libunwindbacktrace",
+ "libutils",
+ "libbase",
+ "liblz4",
+ "liblzma",
+]
+
subdirs = [
+ "benchmark",
"build",
"compiler",
+ "dalvikvm",
+ "dexdump",
+ "dexlayout",
+ "dexlist",
+ "disassembler",
+ "oatdump",
"runtime",
"sigchainlib",
+ "tools/cpp-define-generator",
+ "tools/dmtracedump",
]
diff --git a/Android.mk b/Android.mk
index 4ea169a..0ed5d87 100644
--- a/Android.mk
+++ b/Android.mk
@@ -76,20 +76,13 @@
########################################################################
# product rules
-include $(art_path)/dexdump/Android.mk
-include $(art_path)/dexlayout/Android.mk
-include $(art_path)/dexlist/Android.mk
include $(art_path)/dex2oat/Android.mk
-include $(art_path)/disassembler/Android.mk
-include $(art_path)/oatdump/Android.mk
include $(art_path)/imgdiag/Android.mk
include $(art_path)/patchoat/Android.mk
include $(art_path)/profman/Android.mk
-include $(art_path)/dalvikvm/Android.mk
include $(art_path)/tools/Android.mk
include $(art_path)/tools/ahat/Android.mk
include $(art_path)/tools/dexfuzz/Android.mk
-include $(art_path)/tools/dmtracedump/Android.mk
include $(art_path)/libart_fake/Android.mk
@@ -114,7 +107,6 @@
include $(art_path)/build/Android.common_test.mk
include $(art_path)/build/Android.gtest.mk
include $(art_path)/test/Android.run-test.mk
-include $(art_path)/benchmark/Android.mk
TEST_ART_ADB_ROOT_AND_REMOUNT := \
(adb root && \
diff --git a/benchmark/Android.bp b/benchmark/Android.bp
new file mode 100644
index 0000000..617f5b0
--- /dev/null
+++ b/benchmark/Android.bp
@@ -0,0 +1,43 @@
+//
+// 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.
+//
+
+art_cc_library {
+ name: "libartbenchmark",
+ host_supported: true,
+ defaults: ["art_defaults", "art_debug_defaults"],
+ srcs: [
+ "jobject-benchmark/jobject_benchmark.cc",
+ "jni-perf/perf_jni.cc",
+ "scoped-primitive-array/scoped_primitive_array.cc",
+ ],
+ shared_libs: [
+ "libart",
+ "libbacktrace",
+ "libnativehelper",
+ ],
+ clang: true,
+ target: {
+ android: {
+ shared_libs: ["libdl"],
+ },
+ host: {
+ host_ldlibs: ["-ldl", "-lpthread"],
+ },
+ },
+ cflags: [
+ "-Wno-frame-larger-than=",
+ ],
+}
diff --git a/benchmark/Android.mk b/benchmark/Android.mk
deleted file mode 100644
index 2360bcc..0000000
--- a/benchmark/Android.mk
+++ /dev/null
@@ -1,79 +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
-
-LIBARTBENCHMARK_COMMON_SRC_FILES := \
- jobject-benchmark/jobject_benchmark.cc \
- jni-perf/perf_jni.cc \
- scoped-primitive-array/scoped_primitive_array.cc
-
-# $(1): target or host
-define build-libartbenchmark
- ifneq ($(1),target)
- ifneq ($(1),host)
- $$(error expected target or host for argument 1, received $(1))
- endif
- endif
-
- art_target_or_host := $(1)
-
- include $(CLEAR_VARS)
- LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
- LOCAL_MODULE := libartbenchmark
- ifeq ($$(art_target_or_host),target)
- LOCAL_MODULE_TAGS := tests
- endif
- LOCAL_SRC_FILES := $(LIBARTBENCHMARK_COMMON_SRC_FILES)
- LOCAL_SHARED_LIBRARIES += libart libbacktrace libnativehelper
- LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime
- LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
- LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
- ifeq ($$(art_target_or_host),target)
- LOCAL_CLANG := $(ART_TARGET_CLANG)
- $(call set-target-local-cflags-vars,debug)
- LOCAL_SHARED_LIBRARIES += libdl
- LOCAL_MULTILIB := both
- # LOCAL_MODULE_PATH_32 := $(ART_TARGET_OUT)/$(ART_TARGET_ARCH_32)
- # LOCAL_MODULE_PATH_64 := $(ART_TARGET_OUT)/$(ART_TARGET_ARCH_64)
- LOCAL_MODULE_TARGET_ARCH := $(ART_SUPPORTED_ARCH)
- include $(BUILD_SHARED_LIBRARY)
- else # host
- LOCAL_CLANG := $(ART_HOST_CLANG)
- LOCAL_CFLAGS := $(ART_HOST_CFLAGS) $(ART_HOST_DEBUG_CFLAGS)
- LOCAL_ASFLAGS := $(ART_HOST_ASFLAGS) $(ART_HOST_DEBUG_ASFLAGS)
- LOCAL_LDLIBS := -ldl -lpthread
- LOCAL_IS_HOST_MODULE := true
- LOCAL_MULTILIB := both
- include $(BUILD_HOST_SHARED_LIBRARY)
- endif
-
- # Clear locally used variables.
- art_target_or_host :=
-endef
-
-ifeq ($(ART_BUILD_TARGET),true)
- $(eval $(call build-libartbenchmark,target))
-endif
-ifeq ($(ART_BUILD_HOST),true)
- $(eval $(call build-libartbenchmark,host))
-endif
-
-# Clear locally used variables.
-LOCAL_PATH :=
-LIBARTBENCHMARK_COMMON_SRC_FILES :=
diff --git a/build/Android.bp b/build/Android.bp
index ed9f308..630cf3c 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -101,6 +101,9 @@
// Apple, it's a pain.
"-Wmissing-noreturn",
],
+ host_ldlibs: [
+ "-lrt",
+ ],
},
host: {
cflags: [
@@ -108,6 +111,10 @@
// clang/libunwind bugs that cause SEGVs in run-test-004-ThreadStress.
"-fno-omit-frame-pointer",
],
+ host_ldlibs: [
+ "-ldl",
+ "-lpthread",
+ ],
},
},
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
index 3f25ae1..e88d027 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -123,7 +123,7 @@
# Depend on the -target or -host phony targets generated by the build system
# for each module
-ART_TARGET_EXECUTABLES :=
+ART_TARGET_EXECUTABLES := dalvikvm-target
ifneq ($(ART_BUILD_TARGET_NDEBUG),false)
ART_TARGET_EXECUTABLES += $(foreach name,$(ART_CORE_EXECUTABLES),$(name)-target)
endif
@@ -131,7 +131,7 @@
ART_TARGET_EXECUTABLES += $(foreach name,$(ART_CORE_EXECUTABLES),$(name)d-target)
endif
-ART_HOST_EXECUTABLES :=
+ART_HOST_EXECUTABLES := dalvikvm-host
ifneq ($(ART_BUILD_HOST_NDEBUG),false)
ART_HOST_EXECUTABLES += $(foreach name,$(ART_CORE_EXECUTABLES),$(name)-host)
endif
diff --git a/build/art.go b/build/art.go
index d41b407..9cab3b9 100644
--- a/build/art.go
+++ b/build/art.go
@@ -137,7 +137,26 @@
p.Target.Android.Cflags = deviceFlags(ctx)
p.Target.Host.Cflags = hostFlags(ctx)
ctx.AppendProperties(p)
+}
+type artGlobalDefaults struct{}
+
+func (a *artCustomLinkerCustomizer) CustomizeProperties(ctx android.CustomizePropertiesContext) {
+ linker := envDefault(ctx, "CUSTOM_TARGET_LINKER", "")
+ if linker != "" {
+ type props struct {
+ DynamicLinker string
+ }
+
+ p := &props{}
+ p.DynamicLinker = linker
+ ctx.AppendProperties(p)
+ }
+}
+
+type artCustomLinkerCustomizer struct{}
+
+func (a *artPrefer32BitCustomizer) CustomizeProperties(ctx android.CustomizePropertiesContext) {
if envTrue(ctx, "HOST_PREFER_32_BIT") {
type props struct {
Target struct {
@@ -153,22 +172,7 @@
}
}
-type artGlobalDefaults struct{}
-
-func (a *artLinkerCustomizer) CustomizeProperties(ctx android.CustomizePropertiesContext) {
- linker := envDefault(ctx, "CUSTOM_TARGET_LINKER", "")
- if linker != "" {
- type props struct {
- DynamicLinker string
- }
-
- p := &props{}
- p.DynamicLinker = linker
- ctx.AppendProperties(p)
- }
-}
-
-type artLinkerCustomizer struct{}
+type artPrefer32BitCustomizer struct{}
func init() {
soong.RegisterModuleType("art_cc_library", artLibrary)
@@ -200,6 +204,7 @@
c := &codegenCustomizer{}
android.AddCustomizer(library, c)
props = append(props, &c.codegenProperties)
+
return module, props
}
@@ -207,7 +212,8 @@
binary, _ := cc.NewBinary(android.HostAndDeviceSupported)
module, props := binary.Init()
- android.AddCustomizer(binary, &artLinkerCustomizer{})
+ android.AddCustomizer(binary, &artCustomLinkerCustomizer{})
+ android.AddCustomizer(binary, &artPrefer32BitCustomizer{})
return module, props
}
diff --git a/compiler/Android.bp b/compiler/Android.bp
index 0143268..595a824 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -188,6 +188,7 @@
"liblzma",
],
include_dirs: ["art/disassembler"],
+ export_include_dirs: ["."],
}
gensrcs {
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 5301a6b..3c4a3e8 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -4598,7 +4598,6 @@
}
if (needs_write_barrier) {
// Temporary registers for the write barrier.
- // These registers may be used for Baker read barriers too.
locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
locations->AddTemp(Location::RequiresRegister());
}
@@ -4716,127 +4715,42 @@
__ Bind(&non_zero);
}
- if (kEmitCompilerReadBarrier) {
- if (!kUseBakerReadBarrier) {
- // When (non-Baker) read barriers are enabled, the type
- // checking instrumentation requires two read barriers
- // generated by CodeGeneratorARM::GenerateReadBarrierSlow:
- //
- // __ Mov(temp2, temp1);
- // // /* HeapReference<Class> */ temp1 = temp1->component_type_
- // __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
- // codegen_->GenerateReadBarrierSlow(
- // instruction, temp1_loc, temp1_loc, temp2_loc, component_offset);
- //
- // // /* HeapReference<Class> */ temp2 = value->klass_
- // __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
- // codegen_->GenerateReadBarrierSlow(
- // instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp1_loc);
- //
- // __ cmp(temp1, ShifterOperand(temp2));
- //
- // However, the second read barrier may trash `temp`, as it
- // is a temporary register, and as such would not be saved
- // along with live registers before calling the runtime (nor
- // restored afterwards). So in this case, we bail out and
- // delegate the work to the array set slow path.
- //
- // TODO: Extend the register allocator to support a new
- // "(locally) live temp" location so as to avoid always
- // going into the slow path when read barriers are enabled?
- //
- // There is no such problem with Baker read barriers (see below).
- __ b(slow_path->GetEntryLabel());
- } else {
- Register temp3 = IP;
- Location temp3_loc = Location::RegisterLocation(temp3);
+ // Note that when read barriers are enabled, the type checks
+ // are performed without read barriers. This is fine, even in
+ // the case where a class object is in the from-space after
+ // the flip, as a comparison involving such a type would not
+ // produce a false positive; it may of course produce a false
+ // negative, in which case we would take the ArraySet slow
+ // path.
- // Note: `temp3` (scratch register IP) cannot be used as
- // `ref` argument of GenerateFieldLoadWithBakerReadBarrier
- // calls below (see ReadBarrierMarkSlowPathARM for more
- // details).
+ // /* HeapReference<Class> */ temp1 = array->klass_
+ __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ __ MaybeUnpoisonHeapReference(temp1);
- // /* HeapReference<Class> */ temp1 = array->klass_
- codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
- temp1_loc,
- array,
- class_offset,
- temp3_loc,
- /* needs_null_check */ true);
+ // /* HeapReference<Class> */ temp1 = temp1->component_type_
+ __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
+ // /* HeapReference<Class> */ temp2 = value->klass_
+ __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
+ // If heap poisoning is enabled, no need to unpoison `temp1`
+ // nor `temp2`, as we are comparing two poisoned references.
+ __ cmp(temp1, ShifterOperand(temp2));
- // /* HeapReference<Class> */ temp1 = temp1->component_type_
- codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
- temp1_loc,
- temp1,
- component_offset,
- temp3_loc,
- /* needs_null_check */ false);
- // Register `temp1` is not trashed by the read barrier
- // emitted by GenerateFieldLoadWithBakerReadBarrier below,
- // as that method produces a call to a ReadBarrierMarkRegX
- // entry point, which saves all potentially live registers,
- // including temporaries such a `temp1`.
- // /* HeapReference<Class> */ temp2 = value->klass_
- codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
- temp2_loc,
- value,
- class_offset,
- temp3_loc,
- /* needs_null_check */ false);
- // If heap poisoning is enabled, `temp1` and `temp2` have
- // been unpoisoned by the the previous calls to
- // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
- __ cmp(temp1, ShifterOperand(temp2));
-
- if (instruction->StaticTypeOfArrayIsObjectArray()) {
- Label do_put;
- __ b(&do_put, EQ);
- // We do not need to emit a read barrier for the
- // following heap reference load, as `temp1` is only used
- // in a comparison with null below, and this reference
- // is not kept afterwards.
- // /* HeapReference<Class> */ temp1 = temp1->super_class_
- __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
- // If heap poisoning is enabled, no need to unpoison
- // `temp`, as we are comparing against null below.
- __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
- __ Bind(&do_put);
- } else {
- __ b(slow_path->GetEntryLabel(), NE);
- }
- }
- } else {
- // Non read barrier code.
-
- // /* HeapReference<Class> */ temp1 = array->klass_
- __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
- codegen_->MaybeRecordImplicitNullCheck(instruction);
+ if (instruction->StaticTypeOfArrayIsObjectArray()) {
+ Label do_put;
+ __ b(&do_put, EQ);
+ // If heap poisoning is enabled, the `temp1` reference has
+ // not been unpoisoned yet; unpoison it now.
__ MaybeUnpoisonHeapReference(temp1);
- // /* HeapReference<Class> */ temp1 = temp1->component_type_
- __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
- // /* HeapReference<Class> */ temp2 = value->klass_
- __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
- // If heap poisoning is enabled, no need to unpoison `temp1`
- // nor `temp2`, as we are comparing two poisoned references.
- __ cmp(temp1, ShifterOperand(temp2));
-
- if (instruction->StaticTypeOfArrayIsObjectArray()) {
- Label do_put;
- __ b(&do_put, EQ);
- // If heap poisoning is enabled, the `temp1` reference has
- // not been unpoisoned yet; unpoison it now.
- __ MaybeUnpoisonHeapReference(temp1);
-
- // /* HeapReference<Class> */ temp1 = temp1->super_class_
- __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
- // If heap poisoning is enabled, no need to unpoison
- // `temp1`, as we are comparing against null below.
- __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
- __ Bind(&do_put);
- } else {
- __ b(slow_path->GetEntryLabel(), NE);
- }
+ // /* HeapReference<Class> */ temp1 = temp1->super_class_
+ __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
+ // If heap poisoning is enabled, no need to unpoison
+ // `temp1`, as we are comparing against null below.
+ __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
+ __ Bind(&do_put);
+ } else {
+ __ b(slow_path->GetEntryLabel(), NE);
}
}
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 36f7b4d..1d2f334 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -336,36 +336,6 @@
DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM64);
};
-class LoadStringSlowPathARM64 : public SlowPathCodeARM64 {
- public:
- explicit LoadStringSlowPathARM64(HLoadString* instruction) : SlowPathCodeARM64(instruction) {}
-
- void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
- LocationSummary* locations = instruction_->GetLocations();
- DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
- CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
-
- __ Bind(GetEntryLabel());
- SaveLiveRegisters(codegen, locations);
-
- InvokeRuntimeCallingConvention calling_convention;
- const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex();
- __ Mov(calling_convention.GetRegisterAt(0).W(), string_index);
- 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);
-
- RestoreLiveRegisters(codegen, locations);
- __ B(GetExitLabel());
- }
-
- const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM64"; }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM64);
-};
-
class NullCheckSlowPathARM64 : public SlowPathCodeARM64 {
public:
explicit NullCheckSlowPathARM64(HNullCheck* instr) : SlowPathCodeARM64(instr) {}
@@ -2178,11 +2148,6 @@
} else {
locations->SetInAt(2, Location::RequiresRegister());
}
- if (kEmitCompilerReadBarrier && kUseBakerReadBarrier && (value_type == Primitive::kPrimNot)) {
- // Additional temporary registers for a Baker read barrier.
- locations->AddTemp(Location::RequiresRegister());
- locations->AddTemp(Location::RequiresRegister());
- }
}
void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) {
@@ -2269,144 +2234,44 @@
__ Bind(&non_zero);
}
- if (kEmitCompilerReadBarrier) {
- if (!kUseBakerReadBarrier) {
- // When (non-Baker) read barriers are enabled, the type
- // checking instrumentation requires two read barriers
- // generated by CodeGeneratorARM64::GenerateReadBarrierSlow:
- //
- // __ Mov(temp2, temp);
- // // /* HeapReference<Class> */ temp = temp->component_type_
- // __ Ldr(temp, HeapOperand(temp, component_offset));
- // codegen_->GenerateReadBarrierSlow(
- // instruction, temp_loc, temp_loc, temp2_loc, component_offset);
- //
- // // /* HeapReference<Class> */ temp2 = value->klass_
- // __ Ldr(temp2, HeapOperand(Register(value), class_offset));
- // codegen_->GenerateReadBarrierSlow(
- // instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp_loc);
- //
- // __ Cmp(temp, temp2);
- //
- // However, the second read barrier may trash `temp`, as it
- // is a temporary register, and as such would not be saved
- // along with live registers before calling the runtime (nor
- // restored afterwards). So in this case, we bail out and
- // delegate the work to the array set slow path.
- //
- // TODO: Extend the register allocator to support a new
- // "(locally) live temp" location so as to avoid always
- // going into the slow path when read barriers are enabled?
- //
- // There is no such problem with Baker read barriers (see below).
- __ B(slow_path->GetEntryLabel());
- } else {
- // Note that we cannot use `temps` (instance of VIXL's
- // UseScratchRegisterScope) to allocate `temp2` because
- // the Baker read barriers generated by
- // GenerateFieldLoadWithBakerReadBarrier below also use
- // that facility to allocate a temporary register, thus
- // making VIXL's scratch register pool empty.
- Location temp2_loc = locations->GetTemp(0);
- Register temp2 = WRegisterFrom(temp2_loc);
+ // Note that when Baker read barriers are enabled, the type
+ // checks are performed without read barriers. This is fine,
+ // even in the case where a class object is in the from-space
+ // after the flip, as a comparison involving such a type would
+ // not produce a false positive; it may of course produce a
+ // false negative, in which case we would take the ArraySet
+ // slow path.
- // Note: Because it is acquired from VIXL's scratch register
- // pool, `temp` might be IP0, and thus cannot be used as
- // `ref` argument of GenerateFieldLoadWithBakerReadBarrier
- // calls below (see ReadBarrierMarkSlowPathARM64 for more
- // details).
+ Register temp2 = temps.AcquireSameSizeAs(array);
+ // /* HeapReference<Class> */ temp = array->klass_
+ __ Ldr(temp, HeapOperand(array, class_offset));
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ GetAssembler()->MaybeUnpoisonHeapReference(temp);
- // /* HeapReference<Class> */ temp2 = array->klass_
- codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
- temp2_loc,
- array,
- class_offset,
- temp,
- /* needs_null_check */ true,
- /* use_load_acquire */ false);
+ // /* HeapReference<Class> */ temp = temp->component_type_
+ __ Ldr(temp, HeapOperand(temp, component_offset));
+ // /* HeapReference<Class> */ temp2 = value->klass_
+ __ Ldr(temp2, HeapOperand(Register(value), class_offset));
+ // If heap poisoning is enabled, no need to unpoison `temp`
+ // nor `temp2`, as we are comparing two poisoned references.
+ __ Cmp(temp, temp2);
+ temps.Release(temp2);
- // /* HeapReference<Class> */ temp2 = temp2->component_type_
- codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
- temp2_loc,
- temp2,
- component_offset,
- temp,
- /* needs_null_check */ false,
- /* use_load_acquire */ false);
- // For the same reason that we request `temp2` from the
- // register allocator above, we cannot get `temp3` from
- // VIXL's scratch register pool.
- Location temp3_loc = locations->GetTemp(1);
- Register temp3 = WRegisterFrom(temp3_loc);
- // Register `temp2` is not trashed by the read barrier
- // emitted by GenerateFieldLoadWithBakerReadBarrier below,
- // as that method produces a call to a ReadBarrierMarkRegX
- // entry point, which saves all potentially live registers,
- // including temporaries such a `temp2`.
- // /* HeapReference<Class> */ temp3 = register_value->klass_
- codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
- temp3_loc,
- value.W(),
- class_offset,
- temp,
- /* needs_null_check */ false,
- /* use_load_acquire */ false);
- // If heap poisoning is enabled, `temp2` and `temp3` have
- // been unpoisoned by the the previous calls to
- // CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier.
- __ Cmp(temp2, temp3);
-
- if (instruction->StaticTypeOfArrayIsObjectArray()) {
- vixl::aarch64::Label do_put;
- __ B(eq, &do_put);
- // We do not need to emit a read barrier for the
- // following heap reference load, as `temp2` is only used
- // in a comparison with null below, and this reference
- // is not kept afterwards.
- // /* HeapReference<Class> */ temp = temp2->super_class_
- __ Ldr(temp, HeapOperand(temp2, super_offset));
- // If heap poisoning is enabled, no need to unpoison
- // `temp`, as we are comparing against null below.
- __ Cbnz(temp, slow_path->GetEntryLabel());
- __ Bind(&do_put);
- } else {
- __ B(ne, slow_path->GetEntryLabel());
- }
- }
- } else {
- // Non read barrier code.
-
- Register temp2 = temps.AcquireSameSizeAs(array);
- // /* HeapReference<Class> */ temp = array->klass_
- __ Ldr(temp, HeapOperand(array, class_offset));
- codegen_->MaybeRecordImplicitNullCheck(instruction);
+ if (instruction->StaticTypeOfArrayIsObjectArray()) {
+ vixl::aarch64::Label do_put;
+ __ B(eq, &do_put);
+ // If heap poisoning is enabled, the `temp` reference has
+ // not been unpoisoned yet; unpoison it now.
GetAssembler()->MaybeUnpoisonHeapReference(temp);
- // /* HeapReference<Class> */ temp = temp->component_type_
- __ Ldr(temp, HeapOperand(temp, component_offset));
- // /* HeapReference<Class> */ temp2 = value->klass_
- __ Ldr(temp2, HeapOperand(Register(value), class_offset));
- // If heap poisoning is enabled, no need to unpoison `temp`
- // nor `temp2`, as we are comparing two poisoned references.
- __ Cmp(temp, temp2);
- temps.Release(temp2);
-
- if (instruction->StaticTypeOfArrayIsObjectArray()) {
- vixl::aarch64::Label do_put;
- __ B(eq, &do_put);
- // If heap poisoning is enabled, the `temp` reference has
- // not been unpoisoned yet; unpoison it now.
- GetAssembler()->MaybeUnpoisonHeapReference(temp);
-
- // /* HeapReference<Class> */ temp = temp->super_class_
- __ Ldr(temp, HeapOperand(temp, super_offset));
- // If heap poisoning is enabled, no need to unpoison
- // `temp`, as we are comparing against null below.
- __ Cbnz(temp, slow_path->GetEntryLabel());
- __ Bind(&do_put);
- } else {
- __ B(ne, slow_path->GetEntryLabel());
- }
+ // /* HeapReference<Class> */ temp = temp->super_class_
+ __ Ldr(temp, HeapOperand(temp, super_offset));
+ // If heap poisoning is enabled, no need to unpoison
+ // `temp`, as we are comparing against null below.
+ __ Cbnz(temp, slow_path->GetEntryLabel());
+ __ Bind(&do_put);
+ } else {
+ __ B(ne, slow_path->GetEntryLabel());
}
}
@@ -4292,18 +4157,17 @@
}
void LocationsBuilderARM64::VisitLoadString(HLoadString* load) {
- LocationSummary::CallKind call_kind = (load->NeedsEnvironment() || kEmitCompilerReadBarrier)
- ? LocationSummary::kCallOnSlowPath
+ LocationSummary::CallKind call_kind = load->NeedsEnvironment()
+ ? LocationSummary::kCallOnMainOnly
: LocationSummary::kNoCall;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
- if (kUseBakerReadBarrier && !load->NeedsEnvironment()) {
- locations->SetCustomSlowPathCallerSaves(RegisterSet()); // No caller-save registers.
- }
-
if (load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod) {
locations->SetInAt(0, Location::RequiresRegister());
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetOut(calling_convention.GetReturnLocation(load->GetType()));
+ } else {
+ locations->SetOut(Location::RequiresRegister());
}
- locations->SetOut(Location::RequiresRegister());
}
void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) {
@@ -4347,10 +4211,10 @@
}
// TODO: Re-add the compiler code to do string dex cache lookup again.
- SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load);
- codegen_->AddSlowPath(slow_path);
- __ B(slow_path->GetEntryLabel());
- __ Bind(slow_path->GetExitLabel());
+ InvokeRuntimeCallingConvention calling_convention;
+ __ Mov(calling_convention.GetRegisterAt(0).W(), load->GetStringIndex());
+ codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
+ CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
}
void LocationsBuilderARM64::VisitLongConstant(HLongConstant* constant) {
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 92e9cd9..f07f8a0 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -2378,13 +2378,8 @@
case Primitive::kPrimFloat:
case Primitive::kPrimDouble:
- // TODO: don't use branches.
- GenerateFpCompareAndBranch(instruction->GetCondition(),
- instruction->IsGtBias(),
- type,
- locations,
- &true_label);
- break;
+ GenerateFpCompare(instruction->GetCondition(), instruction->IsGtBias(), type, locations);
+ return;
}
// Convert the branches into the result.
@@ -3177,6 +3172,230 @@
}
}
+void InstructionCodeGeneratorMIPS::GenerateFpCompare(IfCondition cond,
+ bool gt_bias,
+ Primitive::Type type,
+ LocationSummary* locations) {
+ Register dst = locations->Out().AsRegister<Register>();
+ FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
+ FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
+ bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
+ if (type == Primitive::kPrimFloat) {
+ if (isR6) {
+ switch (cond) {
+ case kCondEQ:
+ __ CmpEqS(FTMP, lhs, rhs);
+ __ Mfc1(dst, FTMP);
+ __ Andi(dst, dst, 1);
+ break;
+ case kCondNE:
+ __ CmpEqS(FTMP, lhs, rhs);
+ __ Mfc1(dst, FTMP);
+ __ Addiu(dst, dst, 1);
+ break;
+ case kCondLT:
+ if (gt_bias) {
+ __ CmpLtS(FTMP, lhs, rhs);
+ } else {
+ __ CmpUltS(FTMP, lhs, rhs);
+ }
+ __ Mfc1(dst, FTMP);
+ __ Andi(dst, dst, 1);
+ break;
+ case kCondLE:
+ if (gt_bias) {
+ __ CmpLeS(FTMP, lhs, rhs);
+ } else {
+ __ CmpUleS(FTMP, lhs, rhs);
+ }
+ __ Mfc1(dst, FTMP);
+ __ Andi(dst, dst, 1);
+ break;
+ case kCondGT:
+ if (gt_bias) {
+ __ CmpUltS(FTMP, rhs, lhs);
+ } else {
+ __ CmpLtS(FTMP, rhs, lhs);
+ }
+ __ Mfc1(dst, FTMP);
+ __ Andi(dst, dst, 1);
+ break;
+ case kCondGE:
+ if (gt_bias) {
+ __ CmpUleS(FTMP, rhs, lhs);
+ } else {
+ __ CmpLeS(FTMP, rhs, lhs);
+ }
+ __ Mfc1(dst, FTMP);
+ __ Andi(dst, dst, 1);
+ break;
+ default:
+ LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
+ UNREACHABLE();
+ }
+ } else {
+ switch (cond) {
+ case kCondEQ:
+ __ CeqS(0, lhs, rhs);
+ __ LoadConst32(dst, 1);
+ __ Movf(dst, ZERO, 0);
+ break;
+ case kCondNE:
+ __ CeqS(0, lhs, rhs);
+ __ LoadConst32(dst, 1);
+ __ Movt(dst, ZERO, 0);
+ break;
+ case kCondLT:
+ if (gt_bias) {
+ __ ColtS(0, lhs, rhs);
+ } else {
+ __ CultS(0, lhs, rhs);
+ }
+ __ LoadConst32(dst, 1);
+ __ Movf(dst, ZERO, 0);
+ break;
+ case kCondLE:
+ if (gt_bias) {
+ __ ColeS(0, lhs, rhs);
+ } else {
+ __ CuleS(0, lhs, rhs);
+ }
+ __ LoadConst32(dst, 1);
+ __ Movf(dst, ZERO, 0);
+ break;
+ case kCondGT:
+ if (gt_bias) {
+ __ CultS(0, rhs, lhs);
+ } else {
+ __ ColtS(0, rhs, lhs);
+ }
+ __ LoadConst32(dst, 1);
+ __ Movf(dst, ZERO, 0);
+ break;
+ case kCondGE:
+ if (gt_bias) {
+ __ CuleS(0, rhs, lhs);
+ } else {
+ __ ColeS(0, rhs, lhs);
+ }
+ __ LoadConst32(dst, 1);
+ __ Movf(dst, ZERO, 0);
+ break;
+ default:
+ LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
+ UNREACHABLE();
+ }
+ }
+ } else {
+ DCHECK_EQ(type, Primitive::kPrimDouble);
+ if (isR6) {
+ switch (cond) {
+ case kCondEQ:
+ __ CmpEqD(FTMP, lhs, rhs);
+ __ Mfc1(dst, FTMP);
+ __ Andi(dst, dst, 1);
+ break;
+ case kCondNE:
+ __ CmpEqD(FTMP, lhs, rhs);
+ __ Mfc1(dst, FTMP);
+ __ Addiu(dst, dst, 1);
+ break;
+ case kCondLT:
+ if (gt_bias) {
+ __ CmpLtD(FTMP, lhs, rhs);
+ } else {
+ __ CmpUltD(FTMP, lhs, rhs);
+ }
+ __ Mfc1(dst, FTMP);
+ __ Andi(dst, dst, 1);
+ break;
+ case kCondLE:
+ if (gt_bias) {
+ __ CmpLeD(FTMP, lhs, rhs);
+ } else {
+ __ CmpUleD(FTMP, lhs, rhs);
+ }
+ __ Mfc1(dst, FTMP);
+ __ Andi(dst, dst, 1);
+ break;
+ case kCondGT:
+ if (gt_bias) {
+ __ CmpUltD(FTMP, rhs, lhs);
+ } else {
+ __ CmpLtD(FTMP, rhs, lhs);
+ }
+ __ Mfc1(dst, FTMP);
+ __ Andi(dst, dst, 1);
+ break;
+ case kCondGE:
+ if (gt_bias) {
+ __ CmpUleD(FTMP, rhs, lhs);
+ } else {
+ __ CmpLeD(FTMP, rhs, lhs);
+ }
+ __ Mfc1(dst, FTMP);
+ __ Andi(dst, dst, 1);
+ break;
+ default:
+ LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
+ UNREACHABLE();
+ }
+ } else {
+ switch (cond) {
+ case kCondEQ:
+ __ CeqD(0, lhs, rhs);
+ __ LoadConst32(dst, 1);
+ __ Movf(dst, ZERO, 0);
+ break;
+ case kCondNE:
+ __ CeqD(0, lhs, rhs);
+ __ LoadConst32(dst, 1);
+ __ Movt(dst, ZERO, 0);
+ break;
+ case kCondLT:
+ if (gt_bias) {
+ __ ColtD(0, lhs, rhs);
+ } else {
+ __ CultD(0, lhs, rhs);
+ }
+ __ LoadConst32(dst, 1);
+ __ Movf(dst, ZERO, 0);
+ break;
+ case kCondLE:
+ if (gt_bias) {
+ __ ColeD(0, lhs, rhs);
+ } else {
+ __ CuleD(0, lhs, rhs);
+ }
+ __ LoadConst32(dst, 1);
+ __ Movf(dst, ZERO, 0);
+ break;
+ case kCondGT:
+ if (gt_bias) {
+ __ CultD(0, rhs, lhs);
+ } else {
+ __ ColtD(0, rhs, lhs);
+ }
+ __ LoadConst32(dst, 1);
+ __ Movf(dst, ZERO, 0);
+ break;
+ case kCondGE:
+ if (gt_bias) {
+ __ CuleD(0, rhs, lhs);
+ } else {
+ __ ColeD(0, rhs, lhs);
+ }
+ __ LoadConst32(dst, 1);
+ __ Movf(dst, ZERO, 0);
+ break;
+ default:
+ LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
+ UNREACHABLE();
+ }
+ }
+ }
+}
+
void InstructionCodeGeneratorMIPS::GenerateFpCompareAndBranch(IfCondition cond,
bool gt_bias,
Primitive::Type type,
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index 7ba6c0d..0039981 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -243,6 +243,10 @@
void GenerateLongCompareAndBranch(IfCondition cond,
LocationSummary* locations,
MipsLabel* label);
+ void GenerateFpCompare(IfCondition cond,
+ bool gt_bias,
+ Primitive::Type type,
+ LocationSummary* locations);
void GenerateFpCompareAndBranch(IfCondition cond,
bool gt_bias,
Primitive::Type type,
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 4689ccb..b3b648f 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -5238,7 +5238,6 @@
}
if (needs_write_barrier) {
// Temporary registers for the write barrier.
- // These registers may be used for Baker read barriers too.
locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
// Ensure the card is in a byte register.
locations->AddTemp(Location::RegisterLocation(ECX));
@@ -5328,105 +5327,40 @@
__ Bind(¬_null);
}
- if (kEmitCompilerReadBarrier) {
- if (!kUseBakerReadBarrier) {
- // When (non-Baker) read barriers are enabled, the type
- // checking instrumentation requires two read barriers
- // generated by CodeGeneratorX86::GenerateReadBarrierSlow:
- //
- // __ movl(temp2, temp);
- // // /* HeapReference<Class> */ temp = temp->component_type_
- // __ movl(temp, Address(temp, component_offset));
- // codegen_->GenerateReadBarrierSlow(
- // instruction, temp_loc, temp_loc, temp2_loc, component_offset);
- //
- // // /* HeapReference<Class> */ temp2 = register_value->klass_
- // __ movl(temp2, Address(register_value, class_offset));
- // codegen_->GenerateReadBarrierSlow(
- // instruction, temp2_loc, temp2_loc, value, class_offset, temp_loc);
- //
- // __ cmpl(temp, temp2);
- //
- // However, the second read barrier may trash `temp`, as it
- // is a temporary register, and as such would not be saved
- // along with live registers before calling the runtime (nor
- // restored afterwards). So in this case, we bail out and
- // delegate the work to the array set slow path.
- //
- // TODO: Extend the register allocator to support a new
- // "(locally) live temp" location so as to avoid always
- // going into the slow path when read barriers are enabled?
- //
- // There is no such problem with Baker read barriers (see below).
- __ jmp(slow_path->GetEntryLabel());
- } else {
- Location temp2_loc = locations->GetTemp(1);
- Register temp2 = temp2_loc.AsRegister<Register>();
- // /* HeapReference<Class> */ temp = array->klass_
- codegen_->GenerateFieldLoadWithBakerReadBarrier(
- instruction, temp_loc, array, class_offset, /* needs_null_check */ true);
+ // Note that when Baker read barriers are enabled, the type
+ // checks are performed without read barriers. This is fine,
+ // even in the case where a class object is in the from-space
+ // after the flip, as a comparison involving such a type would
+ // not produce a false positive; it may of course produce a
+ // false negative, in which case we would take the ArraySet
+ // slow path.
- // /* HeapReference<Class> */ temp = temp->component_type_
- codegen_->GenerateFieldLoadWithBakerReadBarrier(
- instruction, temp_loc, temp, component_offset, /* needs_null_check */ false);
- // Register `temp` is not trashed by the read barrier
- // emitted by GenerateFieldLoadWithBakerReadBarrier below,
- // as that method produces a call to a ReadBarrierMarkRegX
- // entry point, which saves all potentially live registers,
- // including temporaries such a `temp`.
- // /* HeapReference<Class> */ temp2 = register_value->klass_
- codegen_->GenerateFieldLoadWithBakerReadBarrier(
- instruction, temp2_loc, register_value, class_offset, /* needs_null_check */ false);
- // If heap poisoning is enabled, `temp` and `temp2` have
- // been unpoisoned by the the previous calls to
- // CodeGeneratorX86::GenerateFieldLoadWithBakerReadBarrier.
- __ cmpl(temp, temp2);
+ // /* HeapReference<Class> */ temp = array->klass_
+ __ movl(temp, Address(array, class_offset));
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ __ MaybeUnpoisonHeapReference(temp);
- if (instruction->StaticTypeOfArrayIsObjectArray()) {
- __ j(kEqual, &do_put);
- // We do not need to emit a read barrier for the
- // following heap reference load, as `temp` is only used
- // in a comparison with null below, and this reference
- // is not kept afterwards. Also, if heap poisoning is
- // enabled, there is no need to unpoison that heap
- // reference for the same reason (comparison with null).
- __ cmpl(Address(temp, super_offset), Immediate(0));
- __ j(kNotEqual, slow_path->GetEntryLabel());
- __ Bind(&do_put);
- } else {
- __ j(kNotEqual, slow_path->GetEntryLabel());
- }
- }
- } else {
- // Non read barrier code.
+ // /* HeapReference<Class> */ temp = temp->component_type_
+ __ movl(temp, Address(temp, component_offset));
+ // If heap poisoning is enabled, no need to unpoison `temp`
+ // nor the object reference in `register_value->klass`, as
+ // we are comparing two poisoned references.
+ __ cmpl(temp, Address(register_value, class_offset));
- // /* HeapReference<Class> */ temp = array->klass_
- __ movl(temp, Address(array, class_offset));
- codegen_->MaybeRecordImplicitNullCheck(instruction);
+ if (instruction->StaticTypeOfArrayIsObjectArray()) {
+ __ j(kEqual, &do_put);
+ // If heap poisoning is enabled, the `temp` reference has
+ // not been unpoisoned yet; unpoison it now.
__ MaybeUnpoisonHeapReference(temp);
- // /* HeapReference<Class> */ temp = temp->component_type_
- __ movl(temp, Address(temp, component_offset));
- // If heap poisoning is enabled, no need to unpoison `temp`
- // nor the object reference in `register_value->klass`, as
- // we are comparing two poisoned references.
- __ cmpl(temp, Address(register_value, class_offset));
-
- if (instruction->StaticTypeOfArrayIsObjectArray()) {
- __ j(kEqual, &do_put);
- // If heap poisoning is enabled, the `temp` reference has
- // not been unpoisoned yet; unpoison it now.
- __ MaybeUnpoisonHeapReference(temp);
-
- // If heap poisoning is enabled, no need to unpoison the
- // heap reference loaded below, as it is only used for a
- // comparison with null.
- __ cmpl(Address(temp, super_offset), Immediate(0));
- __ j(kNotEqual, slow_path->GetEntryLabel());
- __ Bind(&do_put);
- } else {
- __ j(kNotEqual, slow_path->GetEntryLabel());
- }
+ // If heap poisoning is enabled, no need to unpoison the
+ // heap reference loaded below, as it is only used for a
+ // comparison with null.
+ __ cmpl(Address(temp, super_offset), Immediate(0));
+ __ j(kNotEqual, slow_path->GetEntryLabel());
+ __ Bind(&do_put);
+ } else {
+ __ j(kNotEqual, slow_path->GetEntryLabel());
}
}
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index a21a09e..b3228f8 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -4732,7 +4732,6 @@
if (needs_write_barrier) {
// Temporary registers for the write barrier.
- // These registers may be used for Baker read barriers too.
locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
locations->AddTemp(Location::RequiresRegister());
}
@@ -4822,105 +4821,40 @@
__ Bind(¬_null);
}
- if (kEmitCompilerReadBarrier) {
- if (!kUseBakerReadBarrier) {
- // When (non-Baker) read barriers are enabled, the type
- // checking instrumentation requires two read barriers
- // generated by CodeGeneratorX86_64::GenerateReadBarrierSlow:
- //
- // __ movl(temp2, temp);
- // // /* HeapReference<Class> */ temp = temp->component_type_
- // __ movl(temp, Address(temp, component_offset));
- // codegen_->GenerateReadBarrierSlow(
- // instruction, temp_loc, temp_loc, temp2_loc, component_offset);
- //
- // // /* HeapReference<Class> */ temp2 = register_value->klass_
- // __ movl(temp2, Address(register_value, class_offset));
- // codegen_->GenerateReadBarrierSlow(
- // instruction, temp2_loc, temp2_loc, value, class_offset, temp_loc);
- //
- // __ cmpl(temp, temp2);
- //
- // However, the second read barrier may trash `temp`, as it
- // is a temporary register, and as such would not be saved
- // along with live registers before calling the runtime (nor
- // restored afterwards). So in this case, we bail out and
- // delegate the work to the array set slow path.
- //
- // TODO: Extend the register allocator to support a new
- // "(locally) live temp" location so as to avoid always
- // going into the slow path when read barriers are enabled?
- //
- // There is no such problem with Baker read barriers (see below).
- __ jmp(slow_path->GetEntryLabel());
- } else {
- Location temp2_loc = locations->GetTemp(1);
- CpuRegister temp2 = temp2_loc.AsRegister<CpuRegister>();
- // /* HeapReference<Class> */ temp = array->klass_
- codegen_->GenerateFieldLoadWithBakerReadBarrier(
- instruction, temp_loc, array, class_offset, /* needs_null_check */ true);
+ // Note that when Baker read barriers are enabled, the type
+ // checks are performed without read barriers. This is fine,
+ // even in the case where a class object is in the from-space
+ // after the flip, as a comparison involving such a type would
+ // not produce a false positive; it may of course produce a
+ // false negative, in which case we would take the ArraySet
+ // slow path.
- // /* HeapReference<Class> */ temp = temp->component_type_
- codegen_->GenerateFieldLoadWithBakerReadBarrier(
- instruction, temp_loc, temp, component_offset, /* needs_null_check */ false);
- // Register `temp` is not trashed by the read barrier
- // emitted by GenerateFieldLoadWithBakerReadBarrier below,
- // as that method produces a call to a ReadBarrierMarkRegX
- // entry point, which saves all potentially live registers,
- // including temporaries such a `temp`.
- // /* HeapReference<Class> */ temp2 = register_value->klass_
- codegen_->GenerateFieldLoadWithBakerReadBarrier(
- instruction, temp2_loc, register_value, class_offset, /* needs_null_check */ false);
- // If heap poisoning is enabled, `temp` and `temp2` have
- // been unpoisoned by the the previous calls to
- // CodeGeneratorX86_64::GenerateFieldLoadWithBakerReadBarrier.
- __ cmpl(temp, temp2);
+ // /* HeapReference<Class> */ temp = array->klass_
+ __ movl(temp, Address(array, class_offset));
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ __ MaybeUnpoisonHeapReference(temp);
- if (instruction->StaticTypeOfArrayIsObjectArray()) {
- __ j(kEqual, &do_put);
- // We do not need to emit a read barrier for the
- // following heap reference load, as `temp` is only used
- // in a comparison with null below, and this reference
- // is not kept afterwards. Also, if heap poisoning is
- // enabled, there is no need to unpoison that heap
- // reference for the same reason (comparison with null).
- __ cmpl(Address(temp, super_offset), Immediate(0));
- __ j(kNotEqual, slow_path->GetEntryLabel());
- __ Bind(&do_put);
- } else {
- __ j(kNotEqual, slow_path->GetEntryLabel());
- }
- }
- } else {
- // Non read barrier code.
+ // /* HeapReference<Class> */ temp = temp->component_type_
+ __ movl(temp, Address(temp, component_offset));
+ // If heap poisoning is enabled, no need to unpoison `temp`
+ // nor the object reference in `register_value->klass`, as
+ // we are comparing two poisoned references.
+ __ cmpl(temp, Address(register_value, class_offset));
- // /* HeapReference<Class> */ temp = array->klass_
- __ movl(temp, Address(array, class_offset));
- codegen_->MaybeRecordImplicitNullCheck(instruction);
+ if (instruction->StaticTypeOfArrayIsObjectArray()) {
+ __ j(kEqual, &do_put);
+ // If heap poisoning is enabled, the `temp` reference has
+ // not been unpoisoned yet; unpoison it now.
__ MaybeUnpoisonHeapReference(temp);
- // /* HeapReference<Class> */ temp = temp->component_type_
- __ movl(temp, Address(temp, component_offset));
- // If heap poisoning is enabled, no need to unpoison `temp`
- // nor the object reference in `register_value->klass`, as
- // we are comparing two poisoned references.
- __ cmpl(temp, Address(register_value, class_offset));
-
- if (instruction->StaticTypeOfArrayIsObjectArray()) {
- __ j(kEqual, &do_put);
- // If heap poisoning is enabled, the `temp` reference has
- // not been unpoisoned yet; unpoison it now.
- __ MaybeUnpoisonHeapReference(temp);
-
- // If heap poisoning is enabled, no need to unpoison the
- // heap reference loaded below, as it is only used for a
- // comparison with null.
- __ cmpl(Address(temp, super_offset), Immediate(0));
- __ j(kNotEqual, slow_path->GetEntryLabel());
- __ Bind(&do_put);
- } else {
- __ j(kNotEqual, slow_path->GetEntryLabel());
- }
+ // If heap poisoning is enabled, no need to unpoison the
+ // heap reference loaded below, as it is only used for a
+ // comparison with null.
+ __ cmpl(Address(temp, super_offset), Immediate(0));
+ __ j(kNotEqual, slow_path->GetEntryLabel());
+ __ Bind(&do_put);
+ } else {
+ __ j(kNotEqual, slow_path->GetEntryLabel());
}
}
diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h
index cea4a7e..eda0971 100644
--- a/compiler/optimizing/common_arm64.h
+++ b/compiler/optimizing/common_arm64.h
@@ -38,7 +38,7 @@
static_assert((SP == 31) && (WSP == 31) && (XZR == 32) && (WZR == 32),
"Unexpected values for register codes.");
-static inline int VIXLRegCodeFromART(int code) {
+inline int VIXLRegCodeFromART(int code) {
if (code == SP) {
return vixl::aarch64::kSPRegInternalCode;
}
@@ -48,7 +48,7 @@
return code;
}
-static inline int ARTRegCodeFromVIXL(int code) {
+inline int ARTRegCodeFromVIXL(int code) {
if (code == vixl::aarch64::kSPRegInternalCode) {
return SP;
}
@@ -58,85 +58,85 @@
return code;
}
-static inline vixl::aarch64::Register XRegisterFrom(Location location) {
+inline vixl::aarch64::Register XRegisterFrom(Location location) {
DCHECK(location.IsRegister()) << location;
return vixl::aarch64::Register::GetXRegFromCode(VIXLRegCodeFromART(location.reg()));
}
-static inline vixl::aarch64::Register WRegisterFrom(Location location) {
+inline vixl::aarch64::Register WRegisterFrom(Location location) {
DCHECK(location.IsRegister()) << location;
return vixl::aarch64::Register::GetWRegFromCode(VIXLRegCodeFromART(location.reg()));
}
-static inline vixl::aarch64::Register RegisterFrom(Location location, Primitive::Type type) {
+inline vixl::aarch64::Register RegisterFrom(Location location, Primitive::Type type) {
DCHECK(type != Primitive::kPrimVoid && !Primitive::IsFloatingPointType(type)) << type;
return type == Primitive::kPrimLong ? XRegisterFrom(location) : WRegisterFrom(location);
}
-static inline vixl::aarch64::Register OutputRegister(HInstruction* instr) {
+inline vixl::aarch64::Register OutputRegister(HInstruction* instr) {
return RegisterFrom(instr->GetLocations()->Out(), instr->GetType());
}
-static inline vixl::aarch64::Register InputRegisterAt(HInstruction* instr, int input_index) {
+inline vixl::aarch64::Register InputRegisterAt(HInstruction* instr, int input_index) {
return RegisterFrom(instr->GetLocations()->InAt(input_index),
instr->InputAt(input_index)->GetType());
}
-static inline vixl::aarch64::FPRegister DRegisterFrom(Location location) {
+inline vixl::aarch64::FPRegister DRegisterFrom(Location location) {
DCHECK(location.IsFpuRegister()) << location;
return vixl::aarch64::FPRegister::GetDRegFromCode(location.reg());
}
-static inline vixl::aarch64::FPRegister SRegisterFrom(Location location) {
+inline vixl::aarch64::FPRegister SRegisterFrom(Location location) {
DCHECK(location.IsFpuRegister()) << location;
return vixl::aarch64::FPRegister::GetSRegFromCode(location.reg());
}
-static inline vixl::aarch64::FPRegister FPRegisterFrom(Location location, Primitive::Type type) {
+inline vixl::aarch64::FPRegister FPRegisterFrom(Location location, Primitive::Type type) {
DCHECK(Primitive::IsFloatingPointType(type)) << type;
return type == Primitive::kPrimDouble ? DRegisterFrom(location) : SRegisterFrom(location);
}
-static inline vixl::aarch64::FPRegister OutputFPRegister(HInstruction* instr) {
+inline vixl::aarch64::FPRegister OutputFPRegister(HInstruction* instr) {
return FPRegisterFrom(instr->GetLocations()->Out(), instr->GetType());
}
-static inline vixl::aarch64::FPRegister InputFPRegisterAt(HInstruction* instr, int input_index) {
+inline vixl::aarch64::FPRegister InputFPRegisterAt(HInstruction* instr, int input_index) {
return FPRegisterFrom(instr->GetLocations()->InAt(input_index),
instr->InputAt(input_index)->GetType());
}
-static inline vixl::aarch64::CPURegister CPURegisterFrom(Location location, Primitive::Type type) {
+inline vixl::aarch64::CPURegister CPURegisterFrom(Location location, Primitive::Type type) {
return Primitive::IsFloatingPointType(type)
? vixl::aarch64::CPURegister(FPRegisterFrom(location, type))
: vixl::aarch64::CPURegister(RegisterFrom(location, type));
}
-static inline vixl::aarch64::CPURegister OutputCPURegister(HInstruction* instr) {
+inline vixl::aarch64::CPURegister OutputCPURegister(HInstruction* instr) {
return Primitive::IsFloatingPointType(instr->GetType())
? static_cast<vixl::aarch64::CPURegister>(OutputFPRegister(instr))
: static_cast<vixl::aarch64::CPURegister>(OutputRegister(instr));
}
-static inline vixl::aarch64::CPURegister InputCPURegisterAt(HInstruction* instr, int index) {
+inline vixl::aarch64::CPURegister InputCPURegisterAt(HInstruction* instr, int index) {
return Primitive::IsFloatingPointType(instr->InputAt(index)->GetType())
? static_cast<vixl::aarch64::CPURegister>(InputFPRegisterAt(instr, index))
: static_cast<vixl::aarch64::CPURegister>(InputRegisterAt(instr, index));
}
-static inline vixl::aarch64::CPURegister InputCPURegisterOrZeroRegAt(HInstruction* instr,
+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::xzr
: vixl::aarch64::wzr;
}
return InputCPURegisterAt(instr, index);
}
-static inline int64_t Int64ConstantFrom(Location location) {
+inline int64_t Int64ConstantFrom(Location location) {
HConstant* instr = location.GetConstant();
if (instr->IsIntConstant()) {
return instr->AsIntConstant()->GetValue();
@@ -148,7 +148,7 @@
}
}
-static inline vixl::aarch64::Operand OperandFrom(Location location, Primitive::Type type) {
+inline vixl::aarch64::Operand OperandFrom(Location location, Primitive::Type type) {
if (location.IsRegister()) {
return vixl::aarch64::Operand(RegisterFrom(location, type));
} else {
@@ -156,23 +156,23 @@
}
}
-static inline vixl::aarch64::Operand InputOperandAt(HInstruction* instr, int input_index) {
+inline vixl::aarch64::Operand InputOperandAt(HInstruction* instr, int input_index) {
return OperandFrom(instr->GetLocations()->InAt(input_index),
instr->InputAt(input_index)->GetType());
}
-static inline vixl::aarch64::MemOperand StackOperandFrom(Location location) {
+inline vixl::aarch64::MemOperand StackOperandFrom(Location location) {
return vixl::aarch64::MemOperand(vixl::aarch64::sp, location.GetStackIndex());
}
-static inline vixl::aarch64::MemOperand HeapOperand(const vixl::aarch64::Register& base,
+inline vixl::aarch64::MemOperand HeapOperand(const vixl::aarch64::Register& base,
size_t offset = 0) {
// A heap reference must be 32bit, so fit in a W register.
DCHECK(base.IsW());
return vixl::aarch64::MemOperand(base.X(), offset);
}
-static inline vixl::aarch64::MemOperand HeapOperand(const vixl::aarch64::Register& base,
+inline vixl::aarch64::MemOperand HeapOperand(const vixl::aarch64::Register& base,
const vixl::aarch64::Register& regoffset,
vixl::aarch64::Shift shift = vixl::aarch64::LSL,
unsigned shift_amount = 0) {
@@ -181,24 +181,24 @@
return vixl::aarch64::MemOperand(base.X(), regoffset, shift, shift_amount);
}
-static inline vixl::aarch64::MemOperand HeapOperand(const vixl::aarch64::Register& base,
+inline vixl::aarch64::MemOperand HeapOperand(const vixl::aarch64::Register& base,
Offset offset) {
return HeapOperand(base, offset.SizeValue());
}
-static inline vixl::aarch64::MemOperand HeapOperandFrom(Location location, Offset offset) {
+inline vixl::aarch64::MemOperand HeapOperandFrom(Location location, Offset offset) {
return HeapOperand(RegisterFrom(location, Primitive::kPrimNot), offset);
}
-static inline Location LocationFrom(const vixl::aarch64::Register& reg) {
+inline Location LocationFrom(const vixl::aarch64::Register& reg) {
return Location::RegisterLocation(ARTRegCodeFromVIXL(reg.GetCode()));
}
-static inline Location LocationFrom(const vixl::aarch64::FPRegister& fpreg) {
+inline Location LocationFrom(const vixl::aarch64::FPRegister& fpreg) {
return Location::FpuRegisterLocation(fpreg.GetCode());
}
-static inline vixl::aarch64::Operand OperandFromMemOperand(
+inline vixl::aarch64::Operand OperandFromMemOperand(
const vixl::aarch64::MemOperand& mem_op) {
if (mem_op.IsImmediateOffset()) {
return vixl::aarch64::Operand(mem_op.GetOffset());
@@ -219,7 +219,7 @@
}
}
-static bool CanEncodeConstantAsImmediate(HConstant* constant, HInstruction* instr) {
+inline bool CanEncodeConstantAsImmediate(HConstant* constant, HInstruction* instr) {
DCHECK(constant->IsIntConstant() || constant->IsLongConstant() || constant->IsNullConstant())
<< constant->DebugName();
@@ -258,7 +258,7 @@
}
}
-static inline Location ARM64EncodableConstantOrRegister(HInstruction* constant,
+inline Location ARM64EncodableConstantOrRegister(HInstruction* constant,
HInstruction* instr) {
if (constant->IsConstant()
&& CanEncodeConstantAsImmediate(constant->AsConstant(), instr)) {
@@ -272,7 +272,7 @@
// codes are same, we can initialize vixl register list simply by the register masks. Currently,
// only SP/WSP and ZXR/WZR codes are different between art and vixl.
// Note: This function is only used for debug checks.
-static inline bool ArtVixlRegCodeCoherentForRegSet(uint32_t art_core_registers,
+inline bool ArtVixlRegCodeCoherentForRegSet(uint32_t art_core_registers,
size_t num_core,
uint32_t art_fpu_registers,
size_t num_fpu) {
@@ -290,7 +290,7 @@
return true;
}
-static inline vixl::aarch64::Shift ShiftFromOpKind(HArm64DataProcWithShifterOp::OpKind op_kind) {
+inline vixl::aarch64::Shift ShiftFromOpKind(HArm64DataProcWithShifterOp::OpKind op_kind) {
switch (op_kind) {
case HArm64DataProcWithShifterOp::kASR: return vixl::aarch64::ASR;
case HArm64DataProcWithShifterOp::kLSL: return vixl::aarch64::LSL;
@@ -302,7 +302,7 @@
}
}
-static inline vixl::aarch64::Extend ExtendFromOpKind(HArm64DataProcWithShifterOp::OpKind op_kind) {
+inline vixl::aarch64::Extend ExtendFromOpKind(HArm64DataProcWithShifterOp::OpKind op_kind) {
switch (op_kind) {
case HArm64DataProcWithShifterOp::kUXTB: return vixl::aarch64::UXTB;
case HArm64DataProcWithShifterOp::kUXTH: return vixl::aarch64::UXTH;
@@ -317,7 +317,7 @@
}
}
-static inline bool CanFitInShifterOperand(HInstruction* instruction) {
+inline bool CanFitInShifterOperand(HInstruction* instruction) {
if (instruction->IsTypeConversion()) {
HTypeConversion* conversion = instruction->AsTypeConversion();
Primitive::Type result_type = conversion->GetResultType();
@@ -332,7 +332,7 @@
}
}
-static inline bool HasShifterOperand(HInstruction* instr) {
+inline bool HasShifterOperand(HInstruction* instr) {
// `neg` instructions are an alias of `sub` using the zero register as the
// first register input.
bool res = instr->IsAdd() || instr->IsAnd() || instr->IsNeg() ||
@@ -340,7 +340,7 @@
return res;
}
-static inline bool ShifterOperandSupportsExtension(HInstruction* instruction) {
+inline bool ShifterOperandSupportsExtension(HInstruction* instruction) {
DCHECK(HasShifterOperand(instruction));
// Although the `neg` instruction is an alias of the `sub` instruction, `HNeg`
// does *not* support extension. This is because the `extended register` form
@@ -351,7 +351,7 @@
return instruction->IsAdd() || instruction->IsSub();
}
-static inline bool IsConstantZeroBitPattern(const HInstruction* instruction) {
+inline bool IsConstantZeroBitPattern(const HInstruction* instruction) {
return instruction->IsConstant() && instruction->AsConstant()->IsZeroBitPattern();
}
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index 8d4d143..b8e1379 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -297,7 +297,15 @@
DCHECK(!runtime->UseJitCompilation());
mirror::String* string = class_linker->ResolveString(dex_file, string_index, dex_cache);
CHECK(string != nullptr);
- // TODO: In follow up CL, add PcRelative and Address back in.
+ if (compiler_driver_->GetSupportBootImageFixup()) {
+ DCHECK(ContainsElement(compiler_driver_->GetDexFilesForOatFile(), &dex_file));
+ desired_load_kind = codegen_->GetCompilerOptions().GetCompilePic()
+ ? HLoadString::LoadKind::kBootImageLinkTimePcRelative
+ : HLoadString::LoadKind::kBootImageLinkTimeAddress;
+ } else {
+ // MIPS64 or compiler_driver_test. Do not sharpen.
+ DCHECK_EQ(desired_load_kind, HLoadString::LoadKind::kDexCacheViaMethod);
+ }
} else if (runtime->UseJitCompilation()) {
// TODO: Make sure we don't set the "compile PIC" flag for JIT as that's bogus.
// DCHECK(!codegen_->GetCompilerOptions().GetCompilePic());
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index f2ef41f..cd30872 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -1708,6 +1708,13 @@
}
+void X86Assembler::repne_scasb() {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0xAE);
+}
+
+
void X86Assembler::repne_scasw() {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
@@ -1716,6 +1723,13 @@
}
+void X86Assembler::repe_cmpsb() {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0xA6);
+}
+
+
void X86Assembler::repe_cmpsw() {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
@@ -1731,6 +1745,13 @@
}
+void X86Assembler::rep_movsb() {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0xA4);
+}
+
+
void X86Assembler::rep_movsw() {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index 2ddcd76..9738784 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -592,9 +592,12 @@
void jmp(Label* label);
void jmp(NearLabel* label);
+ void repne_scasb();
void repne_scasw();
+ void repe_cmpsb();
void repe_cmpsw();
void repe_cmpsl();
+ void rep_movsb();
void rep_movsw();
X86Assembler* lock();
diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc
index 61d70d7..9bae6c2 100644
--- a/compiler/utils/x86/assembler_x86_test.cc
+++ b/compiler/utils/x86/assembler_x86_test.cc
@@ -207,12 +207,24 @@
DriverStr(expected, "FPUIntegerStore");
}
+TEST_F(AssemblerX86Test, Repnescasb) {
+ GetAssembler()->repne_scasb();
+ const char* expected = "repne scasb\n";
+ DriverStr(expected, "Repnescasb");
+}
+
TEST_F(AssemblerX86Test, Repnescasw) {
GetAssembler()->repne_scasw();
const char* expected = "repne scasw\n";
DriverStr(expected, "Repnescasw");
}
+TEST_F(AssemblerX86Test, Repecmpsb) {
+ GetAssembler()->repe_cmpsb();
+ const char* expected = "repe cmpsb\n";
+ DriverStr(expected, "Repecmpsb");
+}
+
TEST_F(AssemblerX86Test, Repecmpsw) {
GetAssembler()->repe_cmpsw();
const char* expected = "repe cmpsw\n";
@@ -225,10 +237,10 @@
DriverStr(expected, "Repecmpsl");
}
-TEST_F(AssemblerX86Test, RepneScasw) {
- GetAssembler()->repne_scasw();
- const char* expected = "repne scasw\n";
- DriverStr(expected, "repne_scasw");
+TEST_F(AssemblerX86Test, RepMovsb) {
+ GetAssembler()->rep_movsb();
+ const char* expected = "rep movsb\n";
+ DriverStr(expected, "rep_movsb");
}
TEST_F(AssemblerX86Test, RepMovsw) {
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 1f73aa7..e9a0607 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -2325,6 +2325,12 @@
EmitOperand(dst.LowBits(), src);
}
+void X86_64Assembler::repne_scasb() {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0xAE);
+}
+
void X86_64Assembler::repne_scasw() {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
@@ -2332,7 +2338,6 @@
EmitUint8(0xAF);
}
-
void X86_64Assembler::repe_cmpsw() {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 3a4bfca..fdd3aa9 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -670,6 +670,7 @@
void rolq(CpuRegister reg, const Immediate& imm);
void rolq(CpuRegister operand, CpuRegister shifter);
+ void repne_scasb();
void repne_scasw();
void repe_cmpsw();
void repe_cmpsl();
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index 48a1876..ff01429 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -956,6 +956,12 @@
DriverStr(expected, "xorq");
}
+TEST_F(AssemblerX86_64Test, RepneScasb) {
+ GetAssembler()->repne_scasb();
+ const char* expected = "repne scasb\n";
+ DriverStr(expected, "repne_scasb");
+}
+
TEST_F(AssemblerX86_64Test, RepneScasw) {
GetAssembler()->repne_scasw();
const char* expected = "repne scasw\n";
diff --git a/dalvikvm/Android.bp b/dalvikvm/Android.bp
new file mode 100644
index 0000000..ab645bb
--- /dev/null
+++ b/dalvikvm/Android.bp
@@ -0,0 +1,63 @@
+//
+// Copyright (C) 2013 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.
+//
+
+art_cc_binary {
+ name: "dalvikvm",
+ host_supported: true,
+ compile_multilib: "both",
+
+ srcs: ["dalvikvm.cc"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ include_dirs: ["art/runtime"],
+ shared_libs: [
+ "libnativehelper",
+ ],
+ whole_static_libs: ["libsigchain"],
+ target: {
+ host: {
+ host_ldlibs: [
+ "-ldl",
+ "-lpthread",
+ ],
+ },
+ android: {
+ shared_libs: [
+ "libdl",
+ "liblog",
+ ],
+ ldflags: ["-Wl,--export-dynamic"],
+ },
+ linux: {
+ ldflags: ["-Wl,--export-dynamic"],
+ },
+ },
+
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+
+ // Create symlink for the primary version target.
+ symlink_preferred_arch: true,
+}
diff --git a/dalvikvm/Android.mk b/dalvikvm/Android.mk
deleted file mode 100644
index 6c0bcb1..0000000
--- a/dalvikvm/Android.mk
+++ /dev/null
@@ -1,87 +0,0 @@
-#
-# Copyright (C) 2013 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.mk
-
-dalvikvm_cflags := -Wall -Werror -Wextra
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := dalvikvm
-LOCAL_MODULE_TAGS := optional
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := dalvikvm.cc
-LOCAL_CFLAGS := $(dalvikvm_cflags)
-LOCAL_C_INCLUDES := art/runtime
-LOCAL_SHARED_LIBRARIES := libdl liblog libnativehelper
-LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
-LOCAL_LDFLAGS := -Wl,--export-dynamic
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common.mk
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := dalvikvm32
-LOCAL_MODULE_STEM_64 := dalvikvm64
-LOCAL_NATIVE_COVERAGE := $(ART_COVERAGE)
-include $(BUILD_EXECUTABLE)
-
-# Create symlink for the primary version target.
-include $(BUILD_SYSTEM)/executable_prefer_symlink.mk
-
-ART_TARGET_EXECUTABLES += $(TARGET_OUT_EXECUTABLES)/$(LOCAL_MODULE)
-ART_TARGET_EXECUTABLES += $(TARGET_OUT_EXECUTABLES)/$(LOCAL_MODULE)$(ART_PHONY_TEST_TARGET_SUFFIX)
-ifdef 2ND_ART_PHONY_TEST_TARGET_SUFFIX
- ART_TARGET_EXECUTABLES += $(TARGET_OUT_EXECUTABLES)/$(LOCAL_MODULE)$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
-endif
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := dalvikvm
-LOCAL_MODULE_TAGS := optional
-LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := dalvikvm.cc
-LOCAL_CFLAGS := $(dalvikvm_cflags)
-LOCAL_C_INCLUDES := art/runtime
-LOCAL_SHARED_LIBRARIES := libnativehelper
-LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
-LOCAL_LDFLAGS := -ldl -lpthread
-# Mac OS linker doesn't understand --export-dynamic.
-ifneq ($(HOST_OS),darwin)
- LOCAL_LDFLAGS += -Wl,--export-dynamic
-endif
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common.mk
-LOCAL_IS_HOST_MODULE := true
-LOCAL_MULTILIB := both
-ifdef ART_MULTILIB_OVERRIDE_host
- LOCAL_MULTILIB := $(ART_MULTILIB_OVERRIDE_host)
-endif
-ifeq ($(LOCAL_MULTILIB),both)
-LOCAL_MODULE_STEM_32 := dalvikvm32
-LOCAL_MODULE_STEM_64 := dalvikvm64
-endif
-LOCAL_NATIVE_COVERAGE := $(ART_COVERAGE)
-include $(BUILD_HOST_EXECUTABLE)
-# Create symlink for the primary version target.
-ifeq ($(LOCAL_MULTILIB),both)
-include $(BUILD_SYSTEM)/executable_prefer_symlink.mk
-
-ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)$(ART_PHONY_TEST_HOST_SUFFIX)
-ifdef 2ND_ART_PHONY_TEST_HOST_SUFFIX
- ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
-endif
-endif
-ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)
diff --git a/dexdump/Android.bp b/dexdump/Android.bp
new file mode 100644
index 0000000..e77f809
--- /dev/null
+++ b/dexdump/Android.bp
@@ -0,0 +1,26 @@
+// 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.
+
+// TODO(ajcbik): rename dexdump2 into dexdump when Dalvik version is removed
+
+art_cc_binary {
+ name: "dexdump2",
+ host_supported: true,
+ srcs: [
+ "dexdump_main.cc",
+ "dexdump.cc",
+ ],
+ cflags: ["-Wall"],
+ shared_libs: ["libart"],
+}
diff --git a/dexdump/Android.mk b/dexdump/Android.mk
deleted file mode 100755
index ec2529e..0000000
--- a/dexdump/Android.mk
+++ /dev/null
@@ -1,52 +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.
-
-# TODO(ajcbik): Art-i-fy this makefile
-
-# TODO(ajcbik): rename dexdump2 into dexdump when Dalvik version is removed
-
-LOCAL_PATH:= $(call my-dir)
-
-dexdump_src_files := dexdump_main.cc dexdump.cc
-dexdump_c_includes := art/runtime
-dexdump_libraries := libart
-
-##
-## Build the device command line tool dexdump.
-##
-
-ifneq ($(SDK_ONLY),true) # SDK_only doesn't need device version
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := $(dexdump_src_files)
-LOCAL_C_INCLUDES := $(dexdump_c_includes)
-LOCAL_CFLAGS += -Wall
-LOCAL_SHARED_LIBRARIES += $(dexdump_libraries)
-LOCAL_MODULE := dexdump2
-include $(BUILD_EXECUTABLE)
-endif # !SDK_ONLY
-
-##
-## Build the host command line tool dexdump.
-##
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := $(dexdump_src_files)
-LOCAL_C_INCLUDES := $(dexdump_c_includes)
-LOCAL_CFLAGS += -Wall
-LOCAL_SHARED_LIBRARIES += $(dexdump_libraries)
-LOCAL_MODULE := dexdump2
-LOCAL_MULTILIB := $(ART_MULTILIB_OVERRIDE_host)
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
new file mode 100644
index 0000000..852f6c2
--- /dev/null
+++ b/dexlayout/Android.bp
@@ -0,0 +1,25 @@
+// 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.
+
+art_cc_binary {
+ name: "dexlayout",
+ host_supported: true,
+ srcs: [
+ "dexlayout_main.cc",
+ "dexlayout.cc",
+ "dex_ir_builder.cc",
+ ],
+ cflags: ["-Wall"],
+ shared_libs: ["libart"],
+}
diff --git a/dexlayout/Android.mk b/dexlayout/Android.mk
deleted file mode 100755
index de02580..0000000
--- a/dexlayout/Android.mk
+++ /dev/null
@@ -1,50 +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.
-
-# TODO(sehr): Art-i-fy this makefile
-
-LOCAL_PATH:= $(call my-dir)
-
-dexlayout_src_files := dexlayout_main.cc dexlayout.cc dex_ir_builder.cc
-dexlayout_c_includes := art/runtime
-dexlayout_libraries := libart
-
-##
-## Build the device command line tool dexlayout.
-##
-
-ifneq ($(SDK_ONLY),true) # SDK_only doesn't need device version
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := $(dexlayout_src_files)
-LOCAL_C_INCLUDES := $(dexlayout_c_includes)
-LOCAL_CFLAGS += -Wall
-LOCAL_SHARED_LIBRARIES += $(dexlayout_libraries)
-LOCAL_MODULE := dexlayout
-include $(BUILD_EXECUTABLE)
-endif # !SDK_ONLY
-
-##
-## Build the host command line tool dexlayout.
-##
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := $(dexlayout_src_files)
-LOCAL_C_INCLUDES := $(dexlayout_c_includes)
-LOCAL_CFLAGS += -Wall
-LOCAL_SHARED_LIBRARIES += $(dexlayout_libraries)
-LOCAL_MODULE := dexlayout
-LOCAL_MULTILIB := $(ART_MULTILIB_OVERRIDE_host)
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/dexlist/Android.bp b/dexlist/Android.bp
new file mode 100644
index 0000000..8e3c91d
--- /dev/null
+++ b/dexlist/Android.bp
@@ -0,0 +1,21 @@
+// 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.
+
+art_cc_binary {
+ name: "dexlist",
+ host_supported: true,
+ srcs: ["dexlist.cc"],
+ cflags: ["-Wall"],
+ shared_libs: ["libart"],
+}
diff --git a/dexlist/Android.mk b/dexlist/Android.mk
deleted file mode 100755
index 6ec6c97..0000000
--- a/dexlist/Android.mk
+++ /dev/null
@@ -1,52 +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.
-
-# TODO(ajcbik): Art-i-fy this makefile
-
-LOCAL_PATH:= $(call my-dir)
-
-dexlist_src_files := dexlist.cc
-dexlist_c_includes := art/runtime
-dexlist_libraries := libart
-
-##
-## Build the device command line tool dexlist.
-##
-
-ifneq ($(SDK_ONLY),true) # SDK_only doesn't need device version
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := $(dexlist_src_files)
-LOCAL_C_INCLUDES := $(dexlist_c_includes)
-LOCAL_CFLAGS += -Wall
-LOCAL_SHARED_LIBRARIES += $(dexlist_libraries)
-LOCAL_MODULE := dexlist
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-include $(BUILD_EXECUTABLE)
-endif # !SDK_ONLY
-
-##
-## Build the host command line tool dexlist.
-##
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := $(dexlist_src_files)
-LOCAL_C_INCLUDES := $(dexlist_c_includes)
-LOCAL_CFLAGS += -Wall
-LOCAL_SHARED_LIBRARIES += $(dexlist_libraries)
-LOCAL_MODULE := dexlist
-LOCAL_MULTILIB := $(ART_MULTILIB_OVERRIDE_host)
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/disassembler/Android.bp b/disassembler/Android.bp
new file mode 100644
index 0000000..d06e4de
--- /dev/null
+++ b/disassembler/Android.bp
@@ -0,0 +1,58 @@
+//
+// 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.
+//
+
+art_cc_defaults {
+ name: "libart-disassembler-defaults",
+ defaults: ["art_defaults"],
+ host_supported: true,
+ clang: true,
+ srcs: [
+ "disassembler.cc",
+ "disassembler_arm.cc",
+ "disassembler_arm64.cc",
+ "disassembler_mips.cc",
+ "disassembler_x86.cc",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libbase",
+ ],
+ export_include_dirs: ["."],
+}
+
+art_cc_library {
+ name: "libart-disassembler",
+ defaults: ["libart-disassembler-defaults"],
+ shared_libs: [
+ "libart",
+ // For disassembler_arm64.
+ "libvixld-arm64",
+ ],
+}
+
+art_cc_library {
+ name: "libartd-disassembler",
+ defaults: [
+ "libart-disassembler-defaults",
+ "art_debug_defaults",
+ ],
+ shared_libs: [
+ "libartd",
+ // For disassembler_arm64.
+ "libvixld-arm64",
+ ],
+}
diff --git a/disassembler/Android.mk b/disassembler/Android.mk
deleted file mode 100644
index 630f3e4..0000000
--- a/disassembler/Android.mk
+++ /dev/null
@@ -1,165 +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_DISASSEMBLER_SRC_FILES := \
- disassembler.cc \
- disassembler_arm.cc \
- disassembler_arm64.cc \
- disassembler_mips.cc \
- disassembler_x86.cc
-
-# $(1): target or host
-# $(2): ndebug or debug
-# $(3): static or shared (static is only valid for host)
-define build-libart-disassembler
- 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
- ifeq ($(3),static)
- ifneq ($(1),host)
- $$(error received static for argument 3, but argument 1 is not host)
- endif
- else
- ifneq ($(3),shared)
- $$(error expected static or shared for argument 3, received $(3))
- 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
- endif
- LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
- ifeq ($$(art_ndebug_or_debug),ndebug)
- LOCAL_MODULE := libart-disassembler
- else # debug
- LOCAL_MODULE := libartd-disassembler
- endif
-
- LOCAL_MODULE_TAGS := optional
- ifeq ($$(art_static_or_shared),static)
- LOCAL_MODULE_CLASS := STATIC_LIBRARIES
- else # shared
- LOCAL_MODULE_CLASS := SHARED_LIBRARIES
- endif
-
- LOCAL_SRC_FILES := $$(LIBART_DISASSEMBLER_SRC_FILES)
-
- 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_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
-
- ifeq ($$(art_static_or_shared),static)
- LOCAL_STATIC_LIBRARIES += liblog
- ifeq ($$(art_ndebug_or_debug),debug)
- LOCAL_STATIC_LIBRARIES += libartd
- else
- LOCAL_STATIC_LIBRARIES += libart
- endif
- else # shared
- LOCAL_SHARED_LIBRARIES += liblog
- ifeq ($$(art_ndebug_or_debug),debug)
- LOCAL_SHARED_LIBRARIES += libartd
- else
- LOCAL_SHARED_LIBRARIES += libart
- endif
- 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 disassembler_arm64.
- ifeq ($$(art_static_or_shared),static)
- ifeq ($$(art_ndebug_or_debug),debug)
- LOCAL_STATIC_LIBRARIES += libvixld-arm64
- else
- LOCAL_STATIC_LIBRARIES += libvixl-arm64
- endif
- ifeq ($$(art_target_or_host),target)
- $$(error libart-disassembler static builds for target are not supported)
- else # host
- include $(BUILD_HOST_STATIC_LIBRARY)
- endif
- else # shared
- 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
- endif
-
- # Clear out local variables now that we're done with them.
- art_target_or_host :=
- art_ndebug_or_debug :=
- art_static_or_shared :=
-endef
-
-ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
- $(eval $(call build-libart-disassembler,target,ndebug,shared))
-endif
-ifeq ($(ART_BUILD_TARGET_DEBUG),true)
- $(eval $(call build-libart-disassembler,target,debug,shared))
-endif
-# 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-disassembler,host,ndebug,shared))
- ifeq ($(ART_BUILD_HOST_STATIC),true)
- $(eval $(call build-libart-disassembler,host,ndebug,static))
- endif
-endif
-ifeq ($(ART_BUILD_HOST_DEBUG),true)
- $(eval $(call build-libart-disassembler,host,debug,shared))
- ifeq ($(ART_BUILD_HOST_STATIC),true)
- $(eval $(call build-libart-disassembler,host,debug,static))
- endif
-endif
diff --git a/disassembler/disassembler.cc b/disassembler/disassembler.cc
index bcd0d16..8eecc62 100644
--- a/disassembler/disassembler.cc
+++ b/disassembler/disassembler.cc
@@ -18,15 +18,23 @@
#include <ostream>
-#include "base/logging.h"
-#include "base/stringprintf.h"
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+
#include "disassembler_arm.h"
#include "disassembler_arm64.h"
#include "disassembler_mips.h"
#include "disassembler_x86.h"
+using android::base::StringPrintf;
+
namespace art {
+Disassembler::Disassembler(DisassemblerOptions* disassembler_options)
+ : disassembler_options_(disassembler_options) {
+ CHECK(disassembler_options_ != nullptr);
+}
+
Disassembler* Disassembler::Create(InstructionSet instruction_set, DisassemblerOptions* options) {
if (instruction_set == kArm || instruction_set == kThumb2) {
return new arm::DisassemblerArm(options);
@@ -39,7 +47,7 @@
} else if (instruction_set == kX86_64) {
return new x86::DisassemblerX86(options, true);
} else {
- UNIMPLEMENTED(FATAL) << "no disassembler for " << instruction_set;
+ UNIMPLEMENTED(FATAL) << static_cast<uint32_t>(instruction_set);
return nullptr;
}
}
diff --git a/disassembler/disassembler.h b/disassembler/disassembler.h
index 86793cc..1ef456c 100644
--- a/disassembler/disassembler.h
+++ b/disassembler/disassembler.h
@@ -21,8 +21,9 @@
#include <iosfwd>
+#include "android-base/macros.h"
+
#include "arch/instruction_set.h"
-#include "base/macros.h"
namespace art {
@@ -81,10 +82,7 @@
}
protected:
- explicit Disassembler(DisassemblerOptions* disassembler_options)
- : disassembler_options_(disassembler_options) {
- CHECK(disassembler_options_ != nullptr);
- }
+ explicit Disassembler(DisassemblerOptions* disassembler_options);
std::string FormatInstructionPointer(const uint8_t* begin);
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index a47b6ad..c3e288d 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -21,10 +21,13 @@
#include <ostream>
#include <sstream>
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+
#include "arch/arm/registers_arm.h"
#include "base/bit_utils.h"
-#include "base/logging.h"
-#include "base/stringprintf.h"
+
+using android::base::StringPrintf;
namespace art {
namespace arm {
diff --git a/disassembler/disassembler_arm64.cc b/disassembler/disassembler_arm64.cc
index 80bacb2..49b9623 100644
--- a/disassembler/disassembler_arm64.cc
+++ b/disassembler/disassembler_arm64.cc
@@ -20,8 +20,10 @@
#include <sstream>
-#include "base/logging.h"
-#include "base/stringprintf.h"
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+
+using android::base::StringPrintf;
using namespace vixl::aarch64; // NOLINT(build/namespaces)
diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc
index 02c6d71..9a73f29 100644
--- a/disassembler/disassembler_mips.cc
+++ b/disassembler/disassembler_mips.cc
@@ -19,8 +19,10 @@
#include <ostream>
#include <sstream>
-#include "base/logging.h"
-#include "base/stringprintf.h"
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+
+using android::base::StringPrintf;
namespace art {
namespace mips {
diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc
index 2ca84e5..9f49ec6 100644
--- a/disassembler/disassembler_x86.cc
+++ b/disassembler/disassembler_x86.cc
@@ -21,8 +21,10 @@
#include <ostream>
#include <sstream>
-#include "base/logging.h"
-#include "base/stringprintf.h"
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+
+using android::base::StringPrintf;
namespace art {
namespace x86 {
diff --git a/oatdump/Android.bp b/oatdump/Android.bp
new file mode 100644
index 0000000..b01bf51
--- /dev/null
+++ b/oatdump/Android.bp
@@ -0,0 +1,89 @@
+//
+// 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.
+//
+
+cc_defaults {
+ name: "oatdump-defaults",
+ defaults: ["art_defaults"],
+ host_supported: true,
+ srcs: ["oatdump.cc"],
+ target: {
+ android: {
+ shared_libs: ["libcutils"],
+ },
+ },
+ include_dirs: ["art/cmdline"],
+}
+
+art_cc_binary {
+ name: "oatdump",
+ defaults: ["oatdump-defaults"],
+ shared_libs: [
+ "libart",
+ "libart-compiler",
+ "libart-disassembler",
+ ],
+}
+
+art_cc_binary {
+ name: "oatdumpd",
+ defaults: [
+ "art_debug_defaults",
+ "oatdump-defaults",
+ ],
+ shared_libs: [
+ "libartd",
+ "libartd-compiler",
+ "libartd-disassembler",
+ ],
+}
+
+art_cc_binary {
+ name: "oatdumps",
+ defaults: ["oatdump-defaults"],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ static_libs: [
+ "libart",
+ "libart-compiler",
+ "libart-disassembler",
+ "libvixl-arm",
+ "libvixl-arm64",
+ ] + art_static_dependencies,
+}
+
+art_cc_binary {
+ name: "oatdumpds",
+ defaults: [
+ "art_debug_defaults",
+ "oatdump-defaults",
+ ],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ static_libs: [
+ "libartd",
+ "libartd-compiler",
+ "libartd-disassembler",
+ "libvixld-arm",
+ "libvixld-arm64",
+ ] + art_static_dependencies,
+}
+
diff --git a/oatdump/Android.mk b/oatdump/Android.mk
index 4b37c6a..7be8a8d 100644
--- a/oatdump/Android.mk
+++ b/oatdump/Android.mk
@@ -16,41 +16,6 @@
LOCAL_PATH := $(call my-dir)
-include art/build/Android.executable.mk
-
-OATDUMP_SRC_FILES := \
- oatdump.cc
-
-# Build variants {target,host} x {debug,ndebug}
-$(eval $(call build-art-multi-executable,oatdump,$(OATDUMP_SRC_FILES),libart-compiler libart-disassembler,libcutils,,art/compiler art/disassembler))
-
-# Static variants (only for host).
-ifeq ($(ART_BUILD_HOST_STATIC),true)
- ifeq ($(HOST_PREFER_32_BIT),true)
- # We need to explicitly restrict the host arch to 32-bit only, as
- # giving 'both' would make build-art-executable generate a build
- # rule for a 64-bit oatdump executable too.
- oatdump_host_arch := 32
- else
- oatdump_host_arch := both
- endif
-
- ifeq ($(ART_BUILD_HOST_NDEBUG),true)
- $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libart libart-compiler libart-disassembler libvixl-arm64 $(ART_STATIC_DEPENDENCIES),art/compiler art/disassembler,host,ndebug,$(oatdump_host_arch),static))
- endif
- ifeq ($(ART_BUILD_HOST_DEBUG),true)
- $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),libartd libartd-compiler libartd-disassembler libvixld-arm64 $(ART_STATIC_DEPENDENCIES),art/compiler art/disassembler,host,debug,$(oatdump_host_arch),static))
- endif
-
- # Clear locals now they've served their purpose.
- oatdump_host_arch :=
-endif
-
-########################################################################
-# oatdump targets
-
-ART_DUMP_OAT_PATH ?= $(OUT_DIR)
-
OATDUMP := $(HOST_OUT_EXECUTABLES)/oatdump$(HOST_EXECUTABLE_SUFFIX)
OATDUMPD := $(HOST_OUT_EXECUTABLES)/oatdumpd$(HOST_EXECUTABLE_SUFFIX)
# TODO: for now, override with debug version for better error reporting
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 22d79cb..59e4a15 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -97,7 +97,6 @@
"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",
diff --git a/runtime/arch/instruction_set.cc b/runtime/arch/instruction_set.cc
index b35e088..8f64dcd 100644
--- a/runtime/arch/instruction_set.cc
+++ b/runtime/arch/instruction_set.cc
@@ -19,11 +19,31 @@
// Explicitly include our own elf.h to avoid Linux and other dependencies.
#include "../elf.h"
#include "base/bit_utils.h"
+#include "base/logging.h"
#include "globals.h"
namespace art {
-const char* GetInstructionSetString(const InstructionSet isa) {
+void InstructionSetAbort(InstructionSet isa) {
+ switch (isa) {
+ case kArm:
+ case kThumb2:
+ case kArm64:
+ case kX86:
+ case kX86_64:
+ case kMips:
+ case kMips64:
+ case kNone:
+ LOG(FATAL) << "Unsupported instruction set " << isa;
+ UNREACHABLE();
+
+ default:
+ LOG(FATAL) << "Unknown ISA " << isa;
+ UNREACHABLE();
+ }
+}
+
+const char* GetInstructionSetString(InstructionSet isa) {
switch (isa) {
case kArm:
case kThumb2:
diff --git a/runtime/arch/instruction_set.h b/runtime/arch/instruction_set.h
index 917acc9..4a8bea4 100644
--- a/runtime/arch/instruction_set.h
+++ b/runtime/arch/instruction_set.h
@@ -21,7 +21,7 @@
#include <string>
#include "base/enums.h"
-#include "base/logging.h" // Logging is required for FATAL in the helper functions.
+#include "base/macros.h"
namespace art {
@@ -75,7 +75,6 @@
// X86 instruction alignment. This is the recommended alignment for maximum performance.
static constexpr size_t kX86Alignment = 16;
-
const char* GetInstructionSetString(InstructionSet isa);
// Note: Returns kNone when the string cannot be parsed to a known value.
@@ -83,6 +82,9 @@
InstructionSet GetInstructionSetFromELF(uint16_t e_machine, uint32_t e_flags);
+// Fatal logging out of line to keep the header clean of logging.h.
+NO_RETURN void InstructionSetAbort(InstructionSet isa);
+
static inline PointerSize GetInstructionSetPointerSize(InstructionSet isa) {
switch (isa) {
case kArm:
@@ -99,12 +101,8 @@
return kMipsPointerSize;
case kMips64:
return kMips64PointerSize;
- case kNone:
- LOG(FATAL) << "ISA kNone does not have pointer size.";
- UNREACHABLE();
default:
- LOG(FATAL) << "Unknown ISA " << isa;
- UNREACHABLE();
+ InstructionSetAbort(isa);
}
}
@@ -139,12 +137,8 @@
case kMips64:
return true;
- case kNone:
- LOG(FATAL) << "ISA kNone does not have bit width.";
- UNREACHABLE();
default:
- LOG(FATAL) << "Unknown ISA " << isa;
- UNREACHABLE();
+ InstructionSetAbort(isa);
}
}
@@ -168,12 +162,9 @@
return 4;
case kMips64:
return 8;
- case kNone:
- LOG(FATAL) << "ISA kNone does not have spills.";
- UNREACHABLE();
+
default:
- LOG(FATAL) << "Unknown ISA " << isa;
- UNREACHABLE();
+ InstructionSetAbort(isa);
}
}
@@ -193,12 +184,9 @@
return 4;
case kMips64:
return 8;
- case kNone:
- LOG(FATAL) << "ISA kNone does not have spills.";
- UNREACHABLE();
+
default:
- LOG(FATAL) << "Unknown ISA " << isa;
- UNREACHABLE();
+ InstructionSetAbort(isa);
}
}
diff --git a/runtime/arch/instruction_set_features_test.cc b/runtime/arch/instruction_set_features_test.cc
index fb38b47..7bbc709 100644
--- a/runtime/arch/instruction_set_features_test.cc
+++ b/runtime/arch/instruction_set_features_test.cc
@@ -22,6 +22,7 @@
#include "cutils/properties.h"
#endif
+#include "base/logging.h"
#include "base/stringprintf.h"
namespace art {
diff --git a/runtime/arch/mips/instruction_set_features_mips.h b/runtime/arch/mips/instruction_set_features_mips.h
index 120dc1c..2d54988 100644
--- a/runtime/arch/mips/instruction_set_features_mips.h
+++ b/runtime/arch/mips/instruction_set_features_mips.h
@@ -18,6 +18,8 @@
#define ART_RUNTIME_ARCH_MIPS_INSTRUCTION_SET_FEATURES_MIPS_H_
#include "arch/instruction_set_features.h"
+#include "base/logging.h"
+#include "base/macros.h"
namespace art {
diff --git a/runtime/base/bit_utils.h b/runtime/base/bit_utils.h
index 378371d..d2f0fdb 100644
--- a/runtime/base/bit_utils.h
+++ b/runtime/base/bit_utils.h
@@ -21,7 +21,12 @@
#include <limits>
#include <type_traits>
+// This header is used in the disassembler with libbase's logging. Only include ART logging
+// when no other logging macros are available. b/15436106, b/31338270
+#ifndef CHECK
#include "base/logging.h"
+#endif
+
#include "base/iteration_range.h"
#include "base/stl_util.h"
diff --git a/runtime/base/enums.h b/runtime/base/enums.h
index 51b86ea..52cab2a 100644
--- a/runtime/base/enums.h
+++ b/runtime/base/enums.h
@@ -20,9 +20,6 @@
#include <cstddef>
#include <ostream>
-#include "base/logging.h"
-#include "base/macros.h"
-
namespace art {
enum class PointerSize : size_t {
@@ -35,16 +32,6 @@
? PointerSize::k64
: PointerSize::k32;
-template <typename T>
-static constexpr PointerSize ConvertToPointerSize(T any) {
- if (any == 4 || any == 8) {
- return static_cast<PointerSize>(any);
- } else {
- LOG(FATAL);
- UNREACHABLE();
- }
-}
-
} // namespace art
#endif // ART_RUNTIME_BASE_ENUMS_H_
diff --git a/runtime/base/stl_util.h b/runtime/base/stl_util.h
index a53dcea..a4cf249 100644
--- a/runtime/base/stl_util.h
+++ b/runtime/base/stl_util.h
@@ -20,7 +20,11 @@
#include <algorithm>
#include <sstream>
+// This header is used in the disassembler with libbase's logging. Only include ART logging
+// when no other logging macros are available. b/15436106, b/31338270
+#ifndef CHECK
#include "base/logging.h"
+#endif
namespace art {
diff --git a/runtime/code_simulator_container.h b/runtime/code_simulator_container.h
index 655a247..10178ba 100644
--- a/runtime/code_simulator_container.h
+++ b/runtime/code_simulator_container.h
@@ -18,6 +18,7 @@
#define ART_RUNTIME_CODE_SIMULATOR_CONTAINER_H_
#include "arch/instruction_set.h"
+#include "base/logging.h"
#include "simulator/code_simulator.h"
namespace art {
diff --git a/runtime/image.cc b/runtime/image.cc
index 6888183..7e6790a 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -20,6 +20,7 @@
#include "mirror/object_array.h"
#include "mirror/object_array-inl.h"
#include "mirror/object-inl.h"
+#include "utils.h"
namespace art {
@@ -179,4 +180,8 @@
}
}
+PointerSize ImageHeader::GetPointerSize() const {
+ return ConvertToPointerSize(pointer_size_);
+}
+
} // namespace art
diff --git a/runtime/image.h b/runtime/image.h
index 8cd94bb..3a4fa79 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -157,9 +157,7 @@
return reinterpret_cast<uint8_t*>(oat_file_end_);
}
- PointerSize GetPointerSize() const {
- return ConvertToPointerSize(pointer_size_);
- }
+ PointerSize GetPointerSize() const;
uint32_t GetPointerSizeUnchecked() const {
return pointer_size_;
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 277bda4..0003e72 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -20,7 +20,6 @@
#include "common_throws.h"
#include "interpreter_common.h"
-#include "interpreter_goto_table_impl.h"
#include "interpreter_mterp_impl.h"
#include "interpreter_switch_impl.h"
#include "mirror/string-inl.h"
@@ -231,15 +230,12 @@
enum InterpreterImplKind {
kSwitchImplKind, // Switch-based interpreter implementation.
- kComputedGotoImplKind, // Computed-goto-based interpreter implementation.
kMterpImplKind // Assembly interpreter
};
static std::ostream& operator<<(std::ostream& os, const InterpreterImplKind& rhs) {
os << ((rhs == kSwitchImplKind)
? "Switch-based interpreter"
- : (rhs == kComputedGotoImplKind)
- ? "Computed-goto-based interpreter"
- : "Asm interpreter");
+ : "Asm interpreter");
return os;
}
@@ -323,7 +319,8 @@
}
}
}
- } else if (kInterpreterImplKind == kSwitchImplKind) {
+ } else {
+ DCHECK_EQ(kInterpreterImplKind, kSwitchImplKind);
if (transaction_active) {
return ExecuteSwitchImpl<false, true>(self, code_item, shadow_frame, result_register,
false);
@@ -331,13 +328,6 @@
return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register,
false);
}
- } else {
- DCHECK_EQ(kInterpreterImplKind, kComputedGotoImplKind);
- if (transaction_active) {
- return ExecuteGotoImpl<false, true>(self, code_item, shadow_frame, result_register);
- } else {
- return ExecuteGotoImpl<false, false>(self, code_item, shadow_frame, result_register);
- }
}
} else {
// Enter the "with access check" interpreter.
@@ -350,7 +340,8 @@
return ExecuteSwitchImpl<true, false>(self, code_item, shadow_frame, result_register,
false);
}
- } else if (kInterpreterImplKind == kSwitchImplKind) {
+ } else {
+ DCHECK_EQ(kInterpreterImplKind, kSwitchImplKind);
if (transaction_active) {
return ExecuteSwitchImpl<true, true>(self, code_item, shadow_frame, result_register,
false);
@@ -358,13 +349,6 @@
return ExecuteSwitchImpl<true, false>(self, code_item, shadow_frame, result_register,
false);
}
- } else {
- DCHECK_EQ(kInterpreterImplKind, kComputedGotoImplKind);
- if (transaction_active) {
- return ExecuteGotoImpl<true, true>(self, code_item, shadow_frame, result_register);
- } else {
- return ExecuteGotoImpl<true, false>(self, code_item, shadow_frame, result_register);
- }
}
}
}
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
deleted file mode 100644
index 37dd63b..0000000
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ /dev/null
@@ -1,2607 +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.
- */
-
-#include "interpreter_goto_table_impl.h"
-
-// Common includes
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/mutex.h"
-#include "stack.h"
-#include "thread.h"
-
-// Clang compiles the GOTO interpreter very slowly. So we skip it. These are the implementation
-// details only necessary when compiling it.
-#if !defined(__clang__)
-#include "experimental_flags.h"
-#include "interpreter_common.h"
-#include "jit/jit.h"
-#include "safe_math.h"
-#endif
-
-namespace art {
-namespace interpreter {
-
-#if !defined(__clang__)
-
-// In the following macros, we expect the following local variables exist:
-// - "self": the current Thread*.
-// - "inst" : the current Instruction*.
-// - "inst_data" : the current instruction's first 16 bits.
-// - "dex_pc": the current pc.
-// - "shadow_frame": the current shadow frame.
-// - "currentHandlersTable": the current table of pointer to each instruction handler.
-
-// Advance to the next instruction and updates interpreter state.
-#define ADVANCE(_offset) \
- do { \
- int32_t disp = static_cast<int32_t>(_offset); \
- inst = inst->RelativeAt(disp); \
- dex_pc = static_cast<uint32_t>(static_cast<int32_t>(dex_pc) + disp); \
- shadow_frame.SetDexPC(dex_pc); \
- TraceExecution(shadow_frame, inst, dex_pc); \
- inst_data = inst->Fetch16(0); \
- goto *currentHandlersTable[inst->Opcode(inst_data)]; \
- } while (false)
-
-#define HANDLE_PENDING_EXCEPTION() goto exception_pending_label
-
-#define POSSIBLY_HANDLE_PENDING_EXCEPTION(_is_exception_pending, _offset) \
- do { \
- if (UNLIKELY(_is_exception_pending)) { \
- HANDLE_PENDING_EXCEPTION(); \
- } else { \
- ADVANCE(_offset); \
- } \
- } while (false)
-
-#define UPDATE_HANDLER_TABLE() \
- currentHandlersTable = handlersTable[ \
- Runtime::Current()->GetInstrumentation()->GetInterpreterHandlerTable()]
-
-#define BRANCH_INSTRUMENTATION(offset) \
- do { \
- if (UNLIKELY(instrumentation->HasBranchListeners())) { \
- instrumentation->Branch(self, method, dex_pc, offset); \
- } \
- JValue result; \
- if (jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, &result)) { \
- return result; \
- } \
- } while (false)
-
-#define HOTNESS_UPDATE() \
- do { \
- if (jit != nullptr) { \
- jit->AddSamples(self, method, 1, /*with_backedges*/ true); \
- } \
- } while (false)
-
-#define UNREACHABLE_CODE_CHECK() \
- do { \
- if (kIsDebugBuild) { \
- LOG(FATAL) << "We should not be here !"; \
- UNREACHABLE(); \
- } \
- } while (false)
-
-#define HANDLE_INSTRUCTION_START(opcode) op_##opcode: // NOLINT(whitespace/labels)
-#define HANDLE_INSTRUCTION_END() UNREACHABLE_CODE_CHECK()
-
-#define HANDLE_MONITOR_CHECKS() \
- if (!DoMonitorCheckOnExit<do_assignability_check>(self, &shadow_frame)) { \
- HANDLE_PENDING_EXCEPTION(); \
- }
-
-/**
- * Interpreter based on computed goto tables.
- *
- * Each instruction is associated to a handler. This handler is responsible for executing the
- * instruction and jump to the next instruction's handler.
- * In order to limit the cost of instrumentation, we have two handler tables:
- * - the "main" handler table: it contains handlers for normal execution of each instruction without
- * handling of instrumentation.
- * - the "alternative" handler table: it contains alternative handlers which first handle
- * instrumentation before jumping to the corresponding "normal" instruction's handler.
- *
- * When instrumentation is active, the interpreter uses the "alternative" handler table. Otherwise
- * it uses the "main" handler table.
- *
- * The current handler table is the handler table being used by the interpreter. It is updated:
- * - on backward branch (goto, if and switch instructions)
- * - after invoke
- * - when an exception is thrown.
- * This allows to support an attaching debugger to an already running application for instance.
- *
- * For a fast handler table update, handler tables are stored in an array of handler tables. Each
- * handler table is represented by the InterpreterHandlerTable enum which allows to associate it
- * to an index in this array of handler tables ((see Instrumentation::GetInterpreterHandlerTable).
- *
- * Here's the current layout of this array of handler tables:
- *
- * ---------------------+---------------+
- * | NOP | (handler for NOP instruction)
- * +---------------+
- * "main" | MOVE | (handler for MOVE instruction)
- * handler table +---------------+
- * | ... |
- * +---------------+
- * | UNUSED_FF | (handler for UNUSED_FF instruction)
- * ---------------------+---------------+
- * | NOP | (alternative handler for NOP instruction)
- * +---------------+
- * "alternative" | MOVE | (alternative handler for MOVE instruction)
- * handler table +---------------+
- * | ... |
- * +---------------+
- * | UNUSED_FF | (alternative handler for UNUSED_FF instruction)
- * ---------------------+---------------+
- *
- */
-template<bool do_access_check, bool transaction_active>
-JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item, ShadowFrame& shadow_frame,
- JValue result_register) {
- // Define handler tables:
- // - The main handler table contains execution handlers for each instruction.
- // - The alternative handler table contains prelude handlers which check for thread suspend and
- // manage instrumentation before jumping to the execution handler.
- static const void* const handlersTable[instrumentation::kNumHandlerTables][kNumPackedOpcodes] = {
- {
- // Main handler table.
-#define INSTRUCTION_HANDLER(o, code, n, f, i, a, v) &&op_##code,
-#include "dex_instruction_list.h"
- DEX_INSTRUCTION_LIST(INSTRUCTION_HANDLER)
-#undef DEX_INSTRUCTION_LIST
-#undef INSTRUCTION_HANDLER
- }, {
- // Alternative handler table.
-#define INSTRUCTION_HANDLER(o, code, n, f, i, a, v) &&alt_op_##code,
-#include "dex_instruction_list.h"
- DEX_INSTRUCTION_LIST(INSTRUCTION_HANDLER)
-#undef DEX_INSTRUCTION_LIST
-#undef INSTRUCTION_HANDLER
- }
- };
-
- constexpr bool do_assignability_check = do_access_check;
- if (UNLIKELY(!shadow_frame.HasReferenceArray())) {
- LOG(FATAL) << "Invalid shadow frame for interpreter use";
- return JValue();
- }
- self->VerifyStack();
-
- uint32_t dex_pc = shadow_frame.GetDexPC();
- const Instruction* inst = Instruction::At(code_item->insns_ + dex_pc);
- uint16_t inst_data;
- const void* const* currentHandlersTable;
- UPDATE_HANDLER_TABLE();
- const auto* const instrumentation = Runtime::Current()->GetInstrumentation();
- ArtMethod* method = shadow_frame.GetMethod();
- jit::Jit* jit = Runtime::Current()->GetJit();
-
- // Jump to first instruction.
- ADVANCE(0);
- UNREACHABLE_CODE_CHECK();
-
- HANDLE_INSTRUCTION_START(NOP)
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MOVE)
- shadow_frame.SetVReg(inst->VRegA_12x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MOVE_FROM16)
- shadow_frame.SetVReg(inst->VRegA_22x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MOVE_16)
- shadow_frame.SetVReg(inst->VRegA_32x(),
- shadow_frame.GetVReg(inst->VRegB_32x()));
- ADVANCE(3);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MOVE_WIDE)
- shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MOVE_WIDE_FROM16)
- shadow_frame.SetVRegLong(inst->VRegA_22x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_22x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MOVE_WIDE_16)
- shadow_frame.SetVRegLong(inst->VRegA_32x(),
- shadow_frame.GetVRegLong(inst->VRegB_32x()));
- ADVANCE(3);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MOVE_OBJECT)
- shadow_frame.SetVRegReference(inst->VRegA_12x(inst_data),
- shadow_frame.GetVRegReference(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MOVE_OBJECT_FROM16)
- shadow_frame.SetVRegReference(inst->VRegA_22x(inst_data),
- shadow_frame.GetVRegReference(inst->VRegB_22x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MOVE_OBJECT_16)
- shadow_frame.SetVRegReference(inst->VRegA_32x(),
- shadow_frame.GetVRegReference(inst->VRegB_32x()));
- ADVANCE(3);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MOVE_RESULT)
- shadow_frame.SetVReg(inst->VRegA_11x(inst_data), result_register.GetI());
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MOVE_RESULT_WIDE)
- shadow_frame.SetVRegLong(inst->VRegA_11x(inst_data), result_register.GetJ());
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MOVE_RESULT_OBJECT)
- shadow_frame.SetVRegReference(inst->VRegA_11x(inst_data), result_register.GetL());
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MOVE_EXCEPTION) {
- Throwable* exception = self->GetException();
- DCHECK(exception != nullptr) << "No pending exception on MOVE_EXCEPTION instruction";
- shadow_frame.SetVRegReference(inst->VRegA_11x(inst_data), exception);
- self->ClearException();
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(RETURN_VOID_NO_BARRIER) {
- JValue result;
- self->AllowThreadSuspension();
- HANDLE_MONITOR_CHECKS();
- if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
- instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
- shadow_frame.GetMethod(), dex_pc,
- result);
- }
- return result;
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(RETURN_VOID) {
- QuasiAtomic::ThreadFenceForConstructor();
- JValue result;
- self->AllowThreadSuspension();
- HANDLE_MONITOR_CHECKS();
- if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
- instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
- shadow_frame.GetMethod(), dex_pc,
- result);
- }
- return result;
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(RETURN) {
- JValue result;
- result.SetJ(0);
- result.SetI(shadow_frame.GetVReg(inst->VRegA_11x(inst_data)));
- self->AllowThreadSuspension();
- HANDLE_MONITOR_CHECKS();
- if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
- instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
- shadow_frame.GetMethod(), dex_pc,
- result);
- }
- return result;
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(RETURN_WIDE) {
- JValue result;
- result.SetJ(shadow_frame.GetVRegLong(inst->VRegA_11x(inst_data)));
- self->AllowThreadSuspension();
- HANDLE_MONITOR_CHECKS();
- if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
- instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
- shadow_frame.GetMethod(), dex_pc,
- result);
- }
- return result;
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(RETURN_OBJECT) {
- JValue result;
- self->AllowThreadSuspension();
- HANDLE_MONITOR_CHECKS();
- const uint8_t vreg_index = inst->VRegA_11x(inst_data);
- Object* obj_result = shadow_frame.GetVRegReference(vreg_index);
- if (do_assignability_check && obj_result != nullptr) {
- size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
- Class* return_type = shadow_frame.GetMethod()->GetReturnType(true /* resolve */,
- pointer_size);
- obj_result = shadow_frame.GetVRegReference(vreg_index);
- if (return_type == nullptr) {
- // Return the pending exception.
- HANDLE_PENDING_EXCEPTION();
- }
- if (!obj_result->VerifierInstanceOf(return_type)) {
- // This should never happen.
- std::string temp1, temp2;
- self->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;",
- "Returning '%s' that is not instance of return type '%s'",
- obj_result->GetClass()->GetDescriptor(&temp1),
- return_type->GetDescriptor(&temp2));
- HANDLE_PENDING_EXCEPTION();
- }
- }
- result.SetL(obj_result);
- if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
- instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
- shadow_frame.GetMethod(), dex_pc,
- result);
- }
- return result;
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(CONST_4) {
- uint32_t dst = inst->VRegA_11n(inst_data);
- int32_t val = inst->VRegB_11n(inst_data);
- shadow_frame.SetVReg(dst, val);
- if (val == 0) {
- shadow_frame.SetVRegReference(dst, nullptr);
- }
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(CONST_16) {
- uint32_t dst = inst->VRegA_21s(inst_data);
- int32_t val = inst->VRegB_21s();
- shadow_frame.SetVReg(dst, val);
- if (val == 0) {
- shadow_frame.SetVRegReference(dst, nullptr);
- }
- ADVANCE(2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(CONST) {
- uint32_t dst = inst->VRegA_31i(inst_data);
- int32_t val = inst->VRegB_31i();
- shadow_frame.SetVReg(dst, val);
- if (val == 0) {
- shadow_frame.SetVRegReference(dst, nullptr);
- }
- ADVANCE(3);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(CONST_HIGH16) {
- uint32_t dst = inst->VRegA_21h(inst_data);
- int32_t val = static_cast<int32_t>(inst->VRegB_21h() << 16);
- shadow_frame.SetVReg(dst, val);
- if (val == 0) {
- shadow_frame.SetVRegReference(dst, nullptr);
- }
- ADVANCE(2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(CONST_WIDE_16)
- shadow_frame.SetVRegLong(inst->VRegA_21s(inst_data), inst->VRegB_21s());
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(CONST_WIDE_32)
- shadow_frame.SetVRegLong(inst->VRegA_31i(inst_data), inst->VRegB_31i());
- ADVANCE(3);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(CONST_WIDE)
- shadow_frame.SetVRegLong(inst->VRegA_51l(inst_data), inst->VRegB_51l());
- ADVANCE(5);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(CONST_WIDE_HIGH16)
- shadow_frame.SetVRegLong(inst->VRegA_21h(inst_data),
- static_cast<uint64_t>(inst->VRegB_21h()) << 48);
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(CONST_STRING) {
- String* s = ResolveString(self, shadow_frame, inst->VRegB_21c());
- if (UNLIKELY(s == nullptr)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), s);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(CONST_STRING_JUMBO) {
- String* s = ResolveString(self, shadow_frame, inst->VRegB_31c());
- if (UNLIKELY(s == nullptr)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- shadow_frame.SetVRegReference(inst->VRegA_31c(inst_data), s);
- ADVANCE(3);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(CONST_CLASS) {
- Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame.GetMethod(),
- self, false, do_access_check);
- if (UNLIKELY(c == nullptr)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), c);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MONITOR_ENTER) {
- Object* obj = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
- if (UNLIKELY(obj == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- DoMonitorEnter<do_access_check>(self, &shadow_frame, obj);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), 1);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MONITOR_EXIT) {
- Object* obj = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
- if (UNLIKELY(obj == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- DoMonitorExit<do_access_check>(self, &shadow_frame, obj);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), 1);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(CHECK_CAST) {
- Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame.GetMethod(),
- self, false, do_access_check);
- if (UNLIKELY(c == nullptr)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- Object* obj = shadow_frame.GetVRegReference(inst->VRegA_21c(inst_data));
- if (UNLIKELY(obj != nullptr && !obj->InstanceOf(c))) {
- ThrowClassCastException(c, obj->GetClass());
- HANDLE_PENDING_EXCEPTION();
- } else {
- ADVANCE(2);
- }
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INSTANCE_OF) {
- Class* c = ResolveVerifyAndClinit(inst->VRegC_22c(), shadow_frame.GetMethod(),
- self, false, do_access_check);
- if (UNLIKELY(c == nullptr)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
- shadow_frame.SetVReg(inst->VRegA_22c(inst_data), (obj != nullptr && obj->InstanceOf(c)) ? 1 : 0);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(ARRAY_LENGTH) {
- Object* array = shadow_frame.GetVRegReference(inst->VRegB_12x(inst_data));
- if (UNLIKELY(array == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- shadow_frame.SetVReg(inst->VRegA_12x(inst_data), array->AsArray()->GetLength());
- ADVANCE(1);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(NEW_INSTANCE) {
- Object* obj = nullptr;
- Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame.GetMethod(),
- self, false, do_access_check);
- if (LIKELY(c != nullptr)) {
- if (UNLIKELY(c->IsStringClass())) {
- gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
- obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
- } else {
- obj = AllocObjectFromCode<do_access_check, true>(
- inst->VRegB_21c(), shadow_frame.GetMethod(), self,
- Runtime::Current()->GetHeap()->GetCurrentAllocator());
- }
- }
- if (UNLIKELY(obj == nullptr)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- obj->GetClass()->AssertInitializedOrInitializingInThread(self);
- // Don't allow finalizable objects to be allocated during a transaction since these can't be
- // finalized without a started runtime.
- if (transaction_active && obj->GetClass()->IsFinalizable()) {
- AbortTransactionF(self, "Allocating finalizable object in transaction: %s",
- PrettyTypeOf(obj).c_str());
- HANDLE_PENDING_EXCEPTION();
- }
- shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), obj);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(NEW_ARRAY) {
- int32_t length = shadow_frame.GetVReg(inst->VRegB_22c(inst_data));
- Object* obj = AllocArrayFromCode<do_access_check, true>(
- inst->VRegC_22c(), length, shadow_frame.GetMethod(), self,
- Runtime::Current()->GetHeap()->GetCurrentAllocator());
- if (UNLIKELY(obj == nullptr)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- shadow_frame.SetVRegReference(inst->VRegA_22c(inst_data), obj);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(FILLED_NEW_ARRAY) {
- bool success =
- DoFilledNewArray<false, do_access_check, transaction_active>(inst, shadow_frame,
- self, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(FILLED_NEW_ARRAY_RANGE) {
- bool success =
- DoFilledNewArray<true, do_access_check, transaction_active>(inst, shadow_frame,
- self, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(FILL_ARRAY_DATA) {
- Object* obj = shadow_frame.GetVRegReference(inst->VRegA_31t(inst_data));
- const uint16_t* payload_addr = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
- const Instruction::ArrayDataPayload* payload =
- reinterpret_cast<const Instruction::ArrayDataPayload*>(payload_addr);
- bool success = FillArrayData(obj, payload);
- if (transaction_active && success) {
- RecordArrayElementsInTransaction(obj->AsArray(), payload->element_count);
- }
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(THROW) {
- Object* exception = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
- if (UNLIKELY(exception == nullptr)) {
- ThrowNullPointerException("throw with null exception");
- } else if (do_assignability_check && !exception->GetClass()->IsThrowableClass()) {
- // This should never happen.
- std::string temp;
- self->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;",
- "Throwing '%s' that is not instance of Throwable",
- exception->GetClass()->GetDescriptor(&temp));
- } else {
- self->SetException(exception->AsThrowable());
- }
- HANDLE_PENDING_EXCEPTION();
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(GOTO) {
- int8_t offset = inst->VRegA_10t(inst_data);
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(GOTO_16) {
- int16_t offset = inst->VRegA_20t();
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(GOTO_32) {
- int32_t offset = inst->VRegA_30t();
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(PACKED_SWITCH) {
- int32_t offset = DoPackedSwitch(inst, shadow_frame, inst_data);
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SPARSE_SWITCH) {
- int32_t offset = DoSparseSwitch(inst, shadow_frame, inst_data);
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- }
- HANDLE_INSTRUCTION_END();
-
-#if defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wfloat-equal"
-#endif
-
- HANDLE_INSTRUCTION_START(CMPL_FLOAT) {
- float val1 = shadow_frame.GetVRegFloat(inst->VRegB_23x());
- float val2 = shadow_frame.GetVRegFloat(inst->VRegC_23x());
- int32_t result;
- if (val1 > val2) {
- result = 1;
- } else if (val1 == val2) {
- result = 0;
- } else {
- result = -1;
- }
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
- ADVANCE(2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(CMPG_FLOAT) {
- float val1 = shadow_frame.GetVRegFloat(inst->VRegB_23x());
- float val2 = shadow_frame.GetVRegFloat(inst->VRegC_23x());
- int32_t result;
- if (val1 < val2) {
- result = -1;
- } else if (val1 == val2) {
- result = 0;
- } else {
- result = 1;
- }
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
- ADVANCE(2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(CMPL_DOUBLE) {
- double val1 = shadow_frame.GetVRegDouble(inst->VRegB_23x());
- double val2 = shadow_frame.GetVRegDouble(inst->VRegC_23x());
- int32_t result;
- if (val1 > val2) {
- result = 1;
- } else if (val1 == val2) {
- result = 0;
- } else {
- result = -1;
- }
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
- ADVANCE(2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(CMPG_DOUBLE) {
- double val1 = shadow_frame.GetVRegDouble(inst->VRegB_23x());
- double val2 = shadow_frame.GetVRegDouble(inst->VRegC_23x());
- int32_t result;
- if (val1 < val2) {
- result = -1;
- } else if (val1 == val2) {
- result = 0;
- } else {
- result = 1;
- }
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
- ADVANCE(2);
- }
- HANDLE_INSTRUCTION_END();
-
-#if defined(__clang__)
-#pragma clang diagnostic pop
-#endif
-
- HANDLE_INSTRUCTION_START(CMP_LONG) {
- int64_t val1 = shadow_frame.GetVRegLong(inst->VRegB_23x());
- int64_t val2 = shadow_frame.GetVRegLong(inst->VRegC_23x());
- int32_t result;
- if (val1 > val2) {
- result = 1;
- } else if (val1 == val2) {
- result = 0;
- } else {
- result = -1;
- }
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
- ADVANCE(2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IF_EQ) {
- if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) == shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
- int16_t offset = inst->VRegC_22t();
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IF_NE) {
- if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) !=
- shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
- int16_t offset = inst->VRegC_22t();
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IF_LT) {
- if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) <
- shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
- int16_t offset = inst->VRegC_22t();
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IF_GE) {
- if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) >=
- shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
- int16_t offset = inst->VRegC_22t();
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IF_GT) {
- if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) >
- shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
- int16_t offset = inst->VRegC_22t();
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IF_LE) {
- if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) <=
- shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
- int16_t offset = inst->VRegC_22t();
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IF_EQZ) {
- if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) == 0) {
- int16_t offset = inst->VRegB_21t();
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IF_NEZ) {
- if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) != 0) {
- int16_t offset = inst->VRegB_21t();
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IF_LTZ) {
- if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) < 0) {
- int16_t offset = inst->VRegB_21t();
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IF_GEZ) {
- if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) >= 0) {
- int16_t offset = inst->VRegB_21t();
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IF_GTZ) {
- if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) > 0) {
- int16_t offset = inst->VRegB_21t();
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IF_LEZ) {
- if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) <= 0) {
- int16_t offset = inst->VRegB_21t();
- BRANCH_INSTRUMENTATION(offset);
- if (IsBackwardBranch(offset)) {
- HOTNESS_UPDATE();
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- }
- ADVANCE(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- ADVANCE(2);
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(AGET_BOOLEAN) {
- Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- BooleanArray* array = a->AsBooleanArray();
- if (LIKELY(array->CheckIsValidIndex(index))) {
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
- ADVANCE(2);
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(AGET_BYTE) {
- Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- ByteArray* array = a->AsByteArray();
- if (LIKELY(array->CheckIsValidIndex(index))) {
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
- ADVANCE(2);
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(AGET_CHAR) {
- Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- CharArray* array = a->AsCharArray();
- if (LIKELY(array->CheckIsValidIndex(index))) {
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
- ADVANCE(2);
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(AGET_SHORT) {
- Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- ShortArray* array = a->AsShortArray();
- if (LIKELY(array->CheckIsValidIndex(index))) {
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
- ADVANCE(2);
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(AGET) {
- Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- DCHECK(a->IsIntArray() || a->IsFloatArray()) << PrettyTypeOf(a);
- auto* array = down_cast<IntArray*>(a);
- if (LIKELY(array->CheckIsValidIndex(index))) {
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
- ADVANCE(2);
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(AGET_WIDE) {
- Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- DCHECK(a->IsLongArray() || a->IsDoubleArray()) << PrettyTypeOf(a);
- auto* array = down_cast<LongArray*>(a);
- if (LIKELY(array->CheckIsValidIndex(index))) {
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
- ADVANCE(2);
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(AGET_OBJECT) {
- Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- ObjectArray<Object>* array = a->AsObjectArray<Object>();
- if (LIKELY(array->CheckIsValidIndex(index))) {
- shadow_frame.SetVRegReference(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
- ADVANCE(2);
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(APUT_BOOLEAN) {
- Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- uint8_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- BooleanArray* array = a->AsBooleanArray();
- if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks<transaction_active>(index, val);
- ADVANCE(2);
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(APUT_BYTE) {
- Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- int8_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- ByteArray* array = a->AsByteArray();
- if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks<transaction_active>(index, val);
- ADVANCE(2);
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(APUT_CHAR) {
- Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- uint16_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- CharArray* array = a->AsCharArray();
- if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks<transaction_active>(index, val);
- ADVANCE(2);
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(APUT_SHORT) {
- Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- int16_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- ShortArray* array = a->AsShortArray();
- if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks<transaction_active>(index, val);
- ADVANCE(2);
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(APUT) {
- Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- int32_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- DCHECK(a->IsIntArray() || a->IsFloatArray()) << PrettyTypeOf(a);
- auto* array = down_cast<IntArray*>(a);
- if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks<transaction_active>(index, val);
- ADVANCE(2);
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(APUT_WIDE) {
- Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- int64_t val = shadow_frame.GetVRegLong(inst->VRegA_23x(inst_data));
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- DCHECK(a->IsLongArray() || a->IsDoubleArray()) << PrettyTypeOf(a);
- auto* array = down_cast<LongArray*>(a);
- if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks<transaction_active>(index, val);
- ADVANCE(2);
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(APUT_OBJECT) {
- Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- Object* val = shadow_frame.GetVRegReference(inst->VRegA_23x(inst_data));
- ObjectArray<Object>* array = a->AsObjectArray<Object>();
- if (LIKELY(array->CheckIsValidIndex(index) && array->CheckAssignable(val))) {
- array->SetWithoutChecks<transaction_active>(index, val);
- ADVANCE(2);
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- }
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IGET_BOOLEAN) {
- bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimBoolean, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IGET_BYTE) {
- bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimByte, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IGET_CHAR) {
- bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimChar, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IGET_SHORT) {
- bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimShort, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IGET) {
- bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimInt, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IGET_WIDE) {
- bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimLong, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IGET_OBJECT) {
- bool success = DoFieldGet<InstanceObjectRead, Primitive::kPrimNot, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IGET_QUICK) {
- bool success = DoIGetQuick<Primitive::kPrimInt>(shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IGET_BOOLEAN_QUICK) {
- bool success = DoIGetQuick<Primitive::kPrimBoolean>(shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IGET_BYTE_QUICK) {
- bool success = DoIGetQuick<Primitive::kPrimByte>(shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IGET_CHAR_QUICK) {
- bool success = DoIGetQuick<Primitive::kPrimChar>(shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IGET_SHORT_QUICK) {
- bool success = DoIGetQuick<Primitive::kPrimShort>(shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IGET_WIDE_QUICK) {
- bool success = DoIGetQuick<Primitive::kPrimLong>(shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IGET_OBJECT_QUICK) {
- bool success = DoIGetQuick<Primitive::kPrimNot>(shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SGET_BOOLEAN) {
- bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SGET_BYTE) {
- bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SGET_CHAR) {
- bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SGET_SHORT) {
- bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SGET) {
- bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SGET_WIDE) {
- bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SGET_OBJECT) {
- bool success = DoFieldGet<StaticObjectRead, Primitive::kPrimNot, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IPUT_BOOLEAN) {
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IPUT_BYTE) {
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IPUT_CHAR) {
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IPUT_SHORT) {
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IPUT) {
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IPUT_WIDE) {
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IPUT_OBJECT) {
- bool success = DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IPUT_QUICK) {
- bool success = DoIPutQuick<Primitive::kPrimInt, transaction_active>(
- shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IPUT_BOOLEAN_QUICK) {
- bool success = DoIPutQuick<Primitive::kPrimBoolean, transaction_active>(
- shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IPUT_BYTE_QUICK) {
- bool success = DoIPutQuick<Primitive::kPrimByte, transaction_active>(
- shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IPUT_CHAR_QUICK) {
- bool success = DoIPutQuick<Primitive::kPrimChar, transaction_active>(
- shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IPUT_SHORT_QUICK) {
- bool success = DoIPutQuick<Primitive::kPrimShort, transaction_active>(
- shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IPUT_WIDE_QUICK) {
- bool success = DoIPutQuick<Primitive::kPrimLong, transaction_active>(
- shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(IPUT_OBJECT_QUICK) {
- bool success = DoIPutQuick<Primitive::kPrimNot, transaction_active>(
- shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SPUT_BOOLEAN) {
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SPUT_BYTE) {
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SPUT_CHAR) {
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SPUT_SHORT) {
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SPUT) {
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SPUT_WIDE) {
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SPUT_OBJECT) {
- bool success = DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INVOKE_VIRTUAL) {
- bool success = DoInvoke<kVirtual, false, do_access_check>(
- self, shadow_frame, inst, inst_data, &result_register);
- UPDATE_HANDLER_TABLE();
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INVOKE_VIRTUAL_RANGE) {
- bool success = DoInvoke<kVirtual, true, do_access_check>(
- self, shadow_frame, inst, inst_data, &result_register);
- UPDATE_HANDLER_TABLE();
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INVOKE_SUPER) {
- bool success = DoInvoke<kSuper, false, do_access_check>(
- self, shadow_frame, inst, inst_data, &result_register);
- UPDATE_HANDLER_TABLE();
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INVOKE_SUPER_RANGE) {
- bool success = DoInvoke<kSuper, true, do_access_check>(
- self, shadow_frame, inst, inst_data, &result_register);
- UPDATE_HANDLER_TABLE();
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INVOKE_DIRECT) {
- bool success = DoInvoke<kDirect, false, do_access_check>(
- self, shadow_frame, inst, inst_data, &result_register);
- UPDATE_HANDLER_TABLE();
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INVOKE_DIRECT_RANGE) {
- bool success = DoInvoke<kDirect, true, do_access_check>(
- self, shadow_frame, inst, inst_data, &result_register);
- UPDATE_HANDLER_TABLE();
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INVOKE_INTERFACE) {
- bool success = DoInvoke<kInterface, false, do_access_check>(
- self, shadow_frame, inst, inst_data, &result_register);
- UPDATE_HANDLER_TABLE();
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INVOKE_INTERFACE_RANGE) {
- bool success = DoInvoke<kInterface, true, do_access_check>(
- self, shadow_frame, inst, inst_data, &result_register);
- UPDATE_HANDLER_TABLE();
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INVOKE_STATIC) {
- bool success = DoInvoke<kStatic, false, do_access_check>(
- self, shadow_frame, inst, inst_data, &result_register);
- UPDATE_HANDLER_TABLE();
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INVOKE_STATIC_RANGE) {
- bool success = DoInvoke<kStatic, true, do_access_check>(
- self, shadow_frame, inst, inst_data, &result_register);
- UPDATE_HANDLER_TABLE();
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INVOKE_VIRTUAL_QUICK) {
- bool success = DoInvokeVirtualQuick<false>(
- self, shadow_frame, inst, inst_data, &result_register);
- UPDATE_HANDLER_TABLE();
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INVOKE_VIRTUAL_RANGE_QUICK) {
- bool success = DoInvokeVirtualQuick<true>(
- self, shadow_frame, inst, inst_data, &result_register);
- UPDATE_HANDLER_TABLE();
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(NEG_INT)
- shadow_frame.SetVReg(
- inst->VRegA_12x(inst_data), -shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(NOT_INT)
- shadow_frame.SetVReg(
- inst->VRegA_12x(inst_data), ~shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(NEG_LONG)
- shadow_frame.SetVRegLong(
- inst->VRegA_12x(inst_data), -shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(NOT_LONG)
- shadow_frame.SetVRegLong(
- inst->VRegA_12x(inst_data), ~shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(NEG_FLOAT)
- shadow_frame.SetVRegFloat(
- inst->VRegA_12x(inst_data), -shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(NEG_DOUBLE)
- shadow_frame.SetVRegDouble(
- inst->VRegA_12x(inst_data), -shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INT_TO_LONG)
- shadow_frame.SetVRegLong(
- inst->VRegA_12x(inst_data), shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INT_TO_FLOAT)
- shadow_frame.SetVRegFloat(
- inst->VRegA_12x(inst_data), shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INT_TO_DOUBLE)
- shadow_frame.SetVRegDouble(
- inst->VRegA_12x(inst_data), shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(LONG_TO_INT)
- shadow_frame.SetVReg(
- inst->VRegA_12x(inst_data), shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(LONG_TO_FLOAT)
- shadow_frame.SetVRegFloat(
- inst->VRegA_12x(inst_data), shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(LONG_TO_DOUBLE)
- shadow_frame.SetVRegDouble(
- inst->VRegA_12x(inst_data), shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(FLOAT_TO_INT) {
- float val = shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data));
- int32_t result = art_float_to_integral<int32_t, float>(val);
- shadow_frame.SetVReg(inst->VRegA_12x(inst_data), result);
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(FLOAT_TO_LONG) {
- float val = shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data));
- int64_t result = art_float_to_integral<int64_t, float>(val);
- shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data), result);
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(FLOAT_TO_DOUBLE)
- shadow_frame.SetVRegDouble(
- inst->VRegA_12x(inst_data), shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(DOUBLE_TO_INT) {
- double val = shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data));
- int32_t result = art_float_to_integral<int32_t, double>(val);
- shadow_frame.SetVReg(inst->VRegA_12x(inst_data), result);
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(DOUBLE_TO_LONG) {
- double val = shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data));
- int64_t result = art_float_to_integral<int64_t, double>(val);
- shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data), result);
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(DOUBLE_TO_FLOAT)
- shadow_frame.SetVRegFloat(
- inst->VRegA_12x(inst_data), shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INT_TO_BYTE)
- shadow_frame.SetVReg(inst->VRegA_12x(inst_data),
- static_cast<int8_t>(shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INT_TO_CHAR)
- shadow_frame.SetVReg(inst->VRegA_12x(inst_data),
- static_cast<uint16_t>(shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(INT_TO_SHORT)
- shadow_frame.SetVReg(inst->VRegA_12x(inst_data),
- static_cast<int16_t>(shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
- ADVANCE(1);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(ADD_INT)
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- SafeAdd(shadow_frame.GetVReg(inst->VRegB_23x()),
- shadow_frame.GetVReg(inst->VRegC_23x())));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SUB_INT)
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- SafeSub(shadow_frame.GetVReg(inst->VRegB_23x()),
- shadow_frame.GetVReg(inst->VRegC_23x())));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MUL_INT)
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- SafeMul(shadow_frame.GetVReg(inst->VRegB_23x()),
- shadow_frame.GetVReg(inst->VRegC_23x())));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(DIV_INT) {
- bool success = DoIntDivide(shadow_frame, inst->VRegA_23x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_23x()),
- shadow_frame.GetVReg(inst->VRegC_23x()));
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(REM_INT) {
- bool success = DoIntRemainder(shadow_frame, inst->VRegA_23x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_23x()),
- shadow_frame.GetVReg(inst->VRegC_23x()));
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SHL_INT)
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_23x()) <<
- (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x1f));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SHR_INT)
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_23x()) >>
- (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x1f));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(USHR_INT)
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- static_cast<uint32_t>(shadow_frame.GetVReg(inst->VRegB_23x())) >>
- (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x1f));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(AND_INT)
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_23x()) &
- shadow_frame.GetVReg(inst->VRegC_23x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(OR_INT)
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_23x()) |
- shadow_frame.GetVReg(inst->VRegC_23x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(XOR_INT)
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_23x()) ^
- shadow_frame.GetVReg(inst->VRegC_23x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(ADD_LONG)
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- SafeAdd(shadow_frame.GetVRegLong(inst->VRegB_23x()),
- shadow_frame.GetVRegLong(inst->VRegC_23x())));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SUB_LONG)
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- SafeSub(shadow_frame.GetVRegLong(inst->VRegB_23x()),
- shadow_frame.GetVRegLong(inst->VRegC_23x())));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MUL_LONG)
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- SafeMul(shadow_frame.GetVRegLong(inst->VRegB_23x()),
- shadow_frame.GetVRegLong(inst->VRegC_23x())));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(DIV_LONG) {
- bool success = DoLongDivide(shadow_frame, inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_23x()),
- shadow_frame.GetVRegLong(inst->VRegC_23x()));
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(REM_LONG) {
- bool success = DoLongRemainder(shadow_frame, inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_23x()),
- shadow_frame.GetVRegLong(inst->VRegC_23x()));
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(AND_LONG)
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_23x()) &
- shadow_frame.GetVRegLong(inst->VRegC_23x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(OR_LONG)
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_23x()) |
- shadow_frame.GetVRegLong(inst->VRegC_23x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(XOR_LONG)
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_23x()) ^
- shadow_frame.GetVRegLong(inst->VRegC_23x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SHL_LONG)
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_23x()) <<
- (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x3f));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SHR_LONG)
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_23x()) >>
- (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x3f));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(USHR_LONG)
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- static_cast<uint64_t>(shadow_frame.GetVRegLong(inst->VRegB_23x())) >>
- (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x3f));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(ADD_FLOAT)
- shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegFloat(inst->VRegB_23x()) +
- shadow_frame.GetVRegFloat(inst->VRegC_23x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SUB_FLOAT)
- shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegFloat(inst->VRegB_23x()) -
- shadow_frame.GetVRegFloat(inst->VRegC_23x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MUL_FLOAT)
- shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegFloat(inst->VRegB_23x()) *
- shadow_frame.GetVRegFloat(inst->VRegC_23x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(DIV_FLOAT)
- shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegFloat(inst->VRegB_23x()) /
- shadow_frame.GetVRegFloat(inst->VRegC_23x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(REM_FLOAT)
- shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
- fmodf(shadow_frame.GetVRegFloat(inst->VRegB_23x()),
- shadow_frame.GetVRegFloat(inst->VRegC_23x())));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(ADD_DOUBLE)
- shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegDouble(inst->VRegB_23x()) +
- shadow_frame.GetVRegDouble(inst->VRegC_23x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SUB_DOUBLE)
- shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegDouble(inst->VRegB_23x()) -
- shadow_frame.GetVRegDouble(inst->VRegC_23x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MUL_DOUBLE)
- shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegDouble(inst->VRegB_23x()) *
- shadow_frame.GetVRegDouble(inst->VRegC_23x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(DIV_DOUBLE)
- shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegDouble(inst->VRegB_23x()) /
- shadow_frame.GetVRegDouble(inst->VRegC_23x()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(REM_DOUBLE)
- shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
- fmod(shadow_frame.GetVRegDouble(inst->VRegB_23x()),
- shadow_frame.GetVRegDouble(inst->VRegC_23x())));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(ADD_INT_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- SafeAdd(shadow_frame.GetVReg(vregA),
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SUB_INT_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- SafeSub(shadow_frame.GetVReg(vregA),
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MUL_INT_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- SafeMul(shadow_frame.GetVReg(vregA),
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(DIV_INT_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- bool success = DoIntDivide(shadow_frame, vregA, shadow_frame.GetVReg(vregA),
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(REM_INT_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- bool success = DoIntRemainder(shadow_frame, vregA, shadow_frame.GetVReg(vregA),
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SHL_INT_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- shadow_frame.GetVReg(vregA) <<
- (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x1f));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SHR_INT_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- shadow_frame.GetVReg(vregA) >>
- (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x1f));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(USHR_INT_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- static_cast<uint32_t>(shadow_frame.GetVReg(vregA)) >>
- (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x1f));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(AND_INT_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- shadow_frame.GetVReg(vregA) &
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(OR_INT_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- shadow_frame.GetVReg(vregA) |
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(XOR_INT_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- shadow_frame.GetVReg(vregA) ^
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(ADD_LONG_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- SafeAdd(shadow_frame.GetVRegLong(vregA),
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SUB_LONG_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- SafeSub(shadow_frame.GetVRegLong(vregA),
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MUL_LONG_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- SafeMul(shadow_frame.GetVRegLong(vregA),
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(DIV_LONG_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- bool success = DoLongDivide(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(REM_LONG_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- bool success = DoLongRemainder(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(AND_LONG_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- shadow_frame.GetVRegLong(vregA) &
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(OR_LONG_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- shadow_frame.GetVRegLong(vregA) |
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(XOR_LONG_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- shadow_frame.GetVRegLong(vregA) ^
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SHL_LONG_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- shadow_frame.GetVRegLong(vregA) <<
- (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x3f));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SHR_LONG_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- shadow_frame.GetVRegLong(vregA) >>
- (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x3f));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(USHR_LONG_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- static_cast<uint64_t>(shadow_frame.GetVRegLong(vregA)) >>
- (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x3f));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(ADD_FLOAT_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegFloat(vregA,
- shadow_frame.GetVRegFloat(vregA) +
- shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SUB_FLOAT_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegFloat(vregA,
- shadow_frame.GetVRegFloat(vregA) -
- shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MUL_FLOAT_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegFloat(vregA,
- shadow_frame.GetVRegFloat(vregA) *
- shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(DIV_FLOAT_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegFloat(vregA,
- shadow_frame.GetVRegFloat(vregA) /
- shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(REM_FLOAT_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegFloat(vregA,
- fmodf(shadow_frame.GetVRegFloat(vregA),
- shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data))));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(ADD_DOUBLE_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegDouble(vregA,
- shadow_frame.GetVRegDouble(vregA) +
- shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SUB_DOUBLE_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegDouble(vregA,
- shadow_frame.GetVRegDouble(vregA) -
- shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MUL_DOUBLE_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegDouble(vregA,
- shadow_frame.GetVRegDouble(vregA) *
- shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(DIV_DOUBLE_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegDouble(vregA,
- shadow_frame.GetVRegDouble(vregA) /
- shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(REM_DOUBLE_2ADDR) {
- uint32_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegDouble(vregA,
- fmod(shadow_frame.GetVRegDouble(vregA),
- shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data))));
- ADVANCE(1);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(ADD_INT_LIT16)
- shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
- SafeAdd(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
- inst->VRegC_22s()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(RSUB_INT)
- shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
- SafeSub(inst->VRegC_22s(),
- shadow_frame.GetVReg(inst->VRegB_22s(inst_data))));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MUL_INT_LIT16)
- shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
- SafeMul(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
- inst->VRegC_22s()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(DIV_INT_LIT16) {
- bool success = DoIntDivide(
- shadow_frame, inst->VRegA_22s(inst_data), shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
- inst->VRegC_22s());
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(REM_INT_LIT16) {
- bool success = DoIntRemainder(
- shadow_frame, inst->VRegA_22s(inst_data), shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
- inst->VRegC_22s());
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(AND_INT_LIT16)
- shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) &
- inst->VRegC_22s());
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(OR_INT_LIT16)
- shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) |
- inst->VRegC_22s());
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(XOR_INT_LIT16)
- shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) ^
- inst->VRegC_22s());
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(ADD_INT_LIT8)
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- SafeAdd(shadow_frame.GetVReg(inst->VRegB_22b()),
- inst->VRegC_22b()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(RSUB_INT_LIT8)
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- SafeSub(inst->VRegC_22b(),
- shadow_frame.GetVReg(inst->VRegB_22b())));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(MUL_INT_LIT8)
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- SafeMul(shadow_frame.GetVReg(inst->VRegB_22b()),
- inst->VRegC_22b()));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(DIV_INT_LIT8) {
- bool success = DoIntDivide(shadow_frame, inst->VRegA_22b(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b());
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(REM_INT_LIT8) {
- bool success = DoIntRemainder(shadow_frame, inst->VRegA_22b(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b());
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
- }
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(AND_INT_LIT8)
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22b()) &
- inst->VRegC_22b());
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(OR_INT_LIT8)
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22b()) |
- inst->VRegC_22b());
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(XOR_INT_LIT8)
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22b()) ^
- inst->VRegC_22b());
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SHL_INT_LIT8)
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22b()) <<
- (inst->VRegC_22b() & 0x1f));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(SHR_INT_LIT8)
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22b()) >>
- (inst->VRegC_22b() & 0x1f));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(USHR_INT_LIT8)
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- static_cast<uint32_t>(shadow_frame.GetVReg(inst->VRegB_22b())) >>
- (inst->VRegC_22b() & 0x1f));
- ADVANCE(2);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_3E)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_3F)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_40)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_41)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_42)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_43)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_79)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_7A)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_F3)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_F4)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_F5)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_F6)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_F7)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_F8)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_F9)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_FA)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_FB)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_FC)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_FD)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_FE)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- HANDLE_INSTRUCTION_START(UNUSED_FF)
- UnexpectedOpcode(inst, shadow_frame);
- HANDLE_INSTRUCTION_END();
-
- exception_pending_label: {
- CHECK(self->IsExceptionPending());
- if (UNLIKELY(self->TestAllFlags())) {
- self->CheckSuspend();
- UPDATE_HANDLER_TABLE();
- }
- uint32_t found_dex_pc = FindNextInstructionFollowingException(self, shadow_frame, dex_pc,
- instrumentation);
- if (found_dex_pc == DexFile::kDexNoIndex) {
- // Structured locking is to be enforced for abnormal termination, too.
- DoMonitorCheckOnExit<do_assignability_check>(self, &shadow_frame);
- return JValue(); /* Handled in caller. */
- } else {
- int32_t displacement = static_cast<int32_t>(found_dex_pc) - static_cast<int32_t>(dex_pc);
- ADVANCE(displacement);
- }
- }
-
-// Create alternative instruction handlers dedicated to instrumentation.
-// Return instructions must not call Instrumentation::DexPcMovedEvent since they already call
-// Instrumentation::MethodExited. This is to avoid posting debugger events twice for this location.
-// Note: we do not use the kReturn instruction flag here (to test the instruction is a return). The
-// compiler seems to not evaluate "(Instruction::FlagsOf(Instruction::code) & kReturn) != 0" to
-// a constant condition that would remove the "if" statement so the test is free.
-#define INSTRUMENTATION_INSTRUCTION_HANDLER(o, code, n, f, i, a, v) \
- alt_op_##code: { \
- if (UNLIKELY(instrumentation->HasDexPcListeners())) { \
- Object* this_object = shadow_frame.GetThisObject(code_item->ins_size_); \
- instrumentation->DexPcMovedEvent(self, this_object, shadow_frame.GetMethod(), dex_pc); \
- } \
- UPDATE_HANDLER_TABLE(); \
- goto *handlersTable[instrumentation::kMainHandlerTable][Instruction::code]; \
- }
-#include "dex_instruction_list.h"
- DEX_INSTRUCTION_LIST(INSTRUMENTATION_INSTRUCTION_HANDLER)
-#undef DEX_INSTRUCTION_LIST
-#undef INSTRUMENTATION_INSTRUCTION_HANDLER
-} // NOLINT(readability/fn_size)
-
-// Explicit definitions of ExecuteGotoImpl.
-template HOT_ATTR
-JValue ExecuteGotoImpl<true, false>(Thread* self, const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame, JValue result_register);
-template HOT_ATTR
-JValue ExecuteGotoImpl<false, false>(Thread* self, const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame, JValue result_register);
-template
-JValue ExecuteGotoImpl<true, true>(Thread* self, const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame, JValue result_register);
-template
-JValue ExecuteGotoImpl<false, true>(Thread* self, const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame, JValue result_register);
-
-#else
-
-template<bool do_access_check, bool transaction_active>
-JValue ExecuteGotoImpl(Thread*, const DexFile::CodeItem*, ShadowFrame&, JValue) {
- LOG(FATAL) << "UNREACHABLE";
- UNREACHABLE();
-}
-// Explicit definitions of ExecuteGotoImpl.
-template<>
-JValue ExecuteGotoImpl<true, false>(Thread* self, const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame, JValue result_register);
-template<>
-JValue ExecuteGotoImpl<false, false>(Thread* self, const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame, JValue result_register);
-template<>
-JValue ExecuteGotoImpl<true, true>(Thread* self, const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame, JValue result_register);
-template<>
-JValue ExecuteGotoImpl<false, true>(Thread* self, const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame, JValue result_register);
-#endif
-
-} // namespace interpreter
-} // namespace art
diff --git a/runtime/interpreter/interpreter_goto_table_impl.h b/runtime/interpreter/interpreter_goto_table_impl.h
deleted file mode 100644
index c54746d..0000000
--- a/runtime/interpreter/interpreter_goto_table_impl.h
+++ /dev/null
@@ -1,41 +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.
- */
-
-#ifndef ART_RUNTIME_INTERPRETER_INTERPRETER_GOTO_TABLE_IMPL_H_
-#define ART_RUNTIME_INTERPRETER_INTERPRETER_GOTO_TABLE_IMPL_H_
-
-#include "base/macros.h"
-#include "base/mutex.h"
-#include "dex_file.h"
-#include "jvalue.h"
-
-namespace art {
-
-class ShadowFrame;
-class Thread;
-
-namespace interpreter {
-
-template<bool do_access_check, bool transaction_active>
-JValue ExecuteGotoImpl(Thread* self,
- const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame,
- JValue result_register) REQUIRES_SHARED(Locks::mutator_lock_);
-
-} // namespace interpreter
-} // namespace art
-
-#endif // ART_RUNTIME_INTERPRETER_INTERPRETER_GOTO_TABLE_IMPL_H_
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index a3071b7..220979a 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -44,13 +44,29 @@
inline void DexCache::SetResolvedString(uint32_t string_idx, mirror::String* resolved) {
DCHECK_LT(string_idx % NumStrings(), NumStrings());
- // TODO default transaction support.
- StringDexCachePair idx_ptr;
- idx_ptr.string_index = string_idx;
- idx_ptr.string_pointer = GcRoot<String>(resolved);
- GetStrings()[string_idx % NumStrings()].store(idx_ptr, std::memory_order_relaxed);
+ GetStrings()[string_idx % NumStrings()].store(
+ StringDexCachePair(resolved, string_idx),
+ std::memory_order_relaxed);
+ Runtime* const runtime = Runtime::Current();
+ if (UNLIKELY(runtime->IsActiveTransaction())) {
+ DCHECK(runtime->IsAotCompiler());
+ runtime->RecordResolveString(this, string_idx);
+ }
// TODO: Fine-grained marking, so that we don't need to go through all arrays in full.
- Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(this);
+ runtime->GetHeap()->WriteBarrierEveryFieldOf(this);
+}
+
+inline void DexCache::ClearString(uint32_t string_idx) {
+ const uint32_t slot_idx = string_idx % NumStrings();
+ DCHECK(Runtime::Current()->IsAotCompiler());
+ StringDexCacheType* slot = &GetStrings()[slot_idx];
+ // This is racy but should only be called from the transactional interpreter.
+ if (slot->load(std::memory_order_relaxed).string_index == string_idx) {
+ StringDexCachePair cleared(
+ nullptr,
+ StringDexCachePair::InvalidStringIndexForSlot(slot_idx));
+ slot->store(cleared, std::memory_order_relaxed);
+ }
}
inline Class* DexCache::GetResolvedType(uint32_t type_idx) {
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index caf00c2..7d4021f 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -56,12 +56,20 @@
// it's always non-null if the string id branch succeeds (except for the 0th string id).
// Set the initial state for the 0th entry to be {0,1} which is guaranteed to fail
// the lookup string id == stored id branch.
+ StringDexCachePair(String* string, uint32_t string_idx)
+ : string_pointer(string),
+ string_index(string_idx) {}
+ StringDexCachePair() = default;
+ StringDexCachePair(const StringDexCachePair&) = default;
+ StringDexCachePair& operator=(const StringDexCachePair&) = default;
+
static void Initialize(StringDexCacheType* strings) {
mirror::StringDexCachePair first_elem;
first_elem.string_pointer = GcRoot<String>(nullptr);
- first_elem.string_index = 1;
+ first_elem.string_index = InvalidStringIndexForSlot(0);
strings[0].store(first_elem, std::memory_order_relaxed);
}
+
static GcRoot<String> LookupString(StringDexCacheType* dex_cache,
uint32_t string_idx,
uint32_t cache_size) {
@@ -71,10 +79,15 @@
DCHECK(!index_string.string_pointer.IsNull());
return index_string.string_pointer;
}
+
+ static uint32_t InvalidStringIndexForSlot(uint32_t slot) {
+ // Since the cache size is a power of two, 0 will always map to slot 0.
+ // Use 1 for slot 0 and 0 for all other slots.
+ return (slot == 0) ? 1u : 0u;
+ }
};
using StringDexCacheType = std::atomic<StringDexCachePair>;
-
// C++ mirror of java.lang.DexCache.
class MANAGED DexCache FINAL : public Object {
public:
@@ -164,6 +177,10 @@
void SetResolvedString(uint32_t string_idx, mirror::String* resolved) ALWAYS_INLINE
REQUIRES_SHARED(Locks::mutator_lock_);
+ // Clear a string for a string_idx, used to undo string intern transactions to make sure
+ // the string isn't kept live.
+ void ClearString(uint32_t string_idx) REQUIRES_SHARED(Locks::mutator_lock_);
+
Class* GetResolvedType(uint32_t type_idx) REQUIRES_SHARED(Locks::mutator_lock_);
void SetResolvedType(uint32_t type_idx, Class* resolved) REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index a365a73..ba12d33 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1929,6 +1929,12 @@
preinitialization_transaction_->RecordWeakStringRemoval(s);
}
+void Runtime::RecordResolveString(mirror::DexCache* dex_cache, uint32_t string_idx) const {
+ DCHECK(IsAotCompiler());
+ DCHECK(IsActiveTransaction());
+ preinitialization_transaction_->RecordResolveString(dex_cache, string_idx);
+}
+
void Runtime::SetFaultMessage(const std::string& message) {
MutexLock mu(Thread::Current(), fault_message_lock_);
fault_message_ = message;
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 44f765a..dc14c04 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -55,8 +55,9 @@
} // namespace jit
namespace mirror {
- class ClassLoader;
class Array;
+ class ClassLoader;
+ class DexCache;
template<class T> class ObjectArray;
template<class T> class PrimitiveArray;
typedef PrimitiveArray<int8_t> ByteArray;
@@ -508,6 +509,8 @@
REQUIRES(Locks::intern_table_lock_);
void RecordWeakStringRemoval(mirror::String* s) const
REQUIRES(Locks::intern_table_lock_);
+ void RecordResolveString(mirror::DexCache* dex_cache, uint32_t string_idx) const
+ REQUIRES_SHARED(Locks::mutator_lock_);
void SetFaultMessage(const std::string& message) REQUIRES(!fault_message_lock_);
// Only read by the signal handler, NO_THREAD_SAFETY_ANALYSIS to prevent lock order violations
diff --git a/runtime/simulator/Android.bp b/runtime/simulator/Android.bp
index ec0b49e..49322fc 100644
--- a/runtime/simulator/Android.bp
+++ b/runtime/simulator/Android.bp
@@ -16,6 +16,9 @@
cc_defaults {
name: "libart_simulator_defaults",
+ host_supported: true,
+ device_supported: false,
+
defaults: ["art_defaults"],
srcs: [
"code_simulator.cc",
@@ -29,7 +32,7 @@
include_dirs: ["art/runtime"],
}
-cc_library_host_shared {
+art_cc_library {
name: "libart-simulator",
defaults: ["libart_simulator_defaults"],
shared_libs: [
@@ -38,7 +41,7 @@
],
}
-cc_library_host_shared {
+art_cc_library {
name: "libartd-simulator",
defaults: [
"art_debug_defaults",
diff --git a/runtime/simulator/code_simulator_arm64.cc b/runtime/simulator/code_simulator_arm64.cc
index 897d4f5..c7ad1fd 100644
--- a/runtime/simulator/code_simulator_arm64.cc
+++ b/runtime/simulator/code_simulator_arm64.cc
@@ -16,6 +16,8 @@
#include "simulator/code_simulator_arm64.h"
+#include "base/logging.h"
+
using namespace vixl::aarch64; // NOLINT(build/namespaces)
namespace art {
diff --git a/runtime/transaction.cc b/runtime/transaction.cc
index d91860b..9f8d981 100644
--- a/runtime/transaction.cc
+++ b/runtime/transaction.cc
@@ -49,13 +49,15 @@
for (auto it : array_logs_) {
array_values_count += it.second.Size();
}
- size_t string_count = intern_string_logs_.size();
+ size_t intern_string_count = intern_string_logs_.size();
+ size_t resolve_string_count = resolve_string_logs_.size();
LOG(INFO) << "Transaction::~Transaction"
<< ": objects_count=" << objects_count
<< ", field_values_count=" << field_values_count
<< ", array_count=" << array_count
<< ", array_values_count=" << array_values_count
- << ", string_count=" << string_count;
+ << ", intern_string_count=" << intern_string_count
+ << ", resolve_string_count=" << resolve_string_count;
}
}
@@ -165,6 +167,13 @@
array_log.LogValue(index, value);
}
+void Transaction::RecordResolveString(mirror::DexCache* dex_cache, uint32_t string_idx) {
+ DCHECK(dex_cache != nullptr);
+ DCHECK_LT(string_idx, dex_cache->GetDexFile()->NumStringIds());
+ MutexLock mu(Thread::Current(), log_lock_);
+ resolve_string_logs_.push_back(ResolveStringLog(dex_cache, string_idx));
+}
+
void Transaction::RecordStrongStringInsertion(mirror::String* s) {
InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert);
LogInternedString(log);
@@ -200,6 +209,7 @@
UndoObjectModifications();
UndoArrayModifications();
UndoInternStringTableModifications();
+ UndoResolveStringModifications();
}
void Transaction::UndoObjectModifications() {
@@ -230,11 +240,19 @@
intern_string_logs_.clear();
}
+void Transaction::UndoResolveStringModifications() {
+ for (ResolveStringLog& string_log : resolve_string_logs_) {
+ string_log.Undo();
+ }
+ resolve_string_logs_.clear();
+}
+
void Transaction::VisitRoots(RootVisitor* visitor) {
MutexLock mu(Thread::Current(), log_lock_);
VisitObjectLogs(visitor);
VisitArrayLogs(visitor);
- VisitStringLogs(visitor);
+ VisitInternStringLogs(visitor);
+ VisitResolveStringLogs(visitor);
}
void Transaction::VisitObjectLogs(RootVisitor* visitor) {
@@ -292,12 +310,18 @@
}
}
-void Transaction::VisitStringLogs(RootVisitor* visitor) {
+void Transaction::VisitInternStringLogs(RootVisitor* visitor) {
for (InternStringLog& log : intern_string_logs_) {
log.VisitRoots(visitor);
}
}
+void Transaction::VisitResolveStringLogs(RootVisitor* visitor) {
+ for (ResolveStringLog& log : resolve_string_logs_) {
+ log.VisitRoots(visitor);
+ }
+}
+
void Transaction::ObjectLog::LogBooleanValue(MemberOffset offset, uint8_t value, bool is_volatile) {
LogValue(ObjectLog::kBoolean, offset, value, is_volatile);
}
@@ -481,6 +505,21 @@
visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&str_), RootInfo(kRootInternedString));
}
+void Transaction::ResolveStringLog::Undo() {
+ dex_cache_.Read()->ClearString(string_idx_);
+}
+
+Transaction::ResolveStringLog::ResolveStringLog(mirror::DexCache* dex_cache, uint32_t string_idx)
+ : dex_cache_(dex_cache),
+ string_idx_(string_idx) {
+ DCHECK(dex_cache != nullptr);
+ DCHECK_LT(string_idx_, dex_cache->GetDexFile()->NumStringIds());
+}
+
+void Transaction::ResolveStringLog::VisitRoots(RootVisitor* visitor) {
+ dex_cache_.VisitRoot(visitor, RootInfo(kRootVMInternal));
+}
+
void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
auto it = array_values_.find(index);
if (it == array_values_.end()) {
diff --git a/runtime/transaction.h b/runtime/transaction.h
index bc9c640..584dfb89 100644
--- a/runtime/transaction.h
+++ b/runtime/transaction.h
@@ -32,6 +32,7 @@
namespace art {
namespace mirror {
class Array;
+class DexCache;
class Object;
class String;
}
@@ -95,6 +96,11 @@
REQUIRES(Locks::intern_table_lock_)
REQUIRES(!log_lock_);
+ // Record resolve string.
+ void RecordResolveString(mirror::DexCache* dex_cache, uint32_t string_idx)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!log_lock_);
+
// Abort transaction by undoing all recorded changes.
void Rollback()
REQUIRES_SHARED(Locks::mutator_lock_)
@@ -192,6 +198,19 @@
const StringOp string_op_;
};
+ class ResolveStringLog : public ValueObject {
+ public:
+ ResolveStringLog(mirror::DexCache* dex_cache, uint32_t string_idx);
+
+ void Undo() REQUIRES_SHARED(Locks::mutator_lock_);
+
+ void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
+
+ private:
+ GcRoot<mirror::DexCache> dex_cache_;
+ const uint32_t string_idx_;
+ };
+
void LogInternedString(const InternStringLog& log)
REQUIRES(Locks::intern_table_lock_)
REQUIRES(!log_lock_);
@@ -206,6 +225,9 @@
REQUIRES(Locks::intern_table_lock_)
REQUIRES(log_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
+ void UndoResolveStringModifications()
+ REQUIRES(log_lock_)
+ REQUIRES_SHARED(Locks::mutator_lock_);
void VisitObjectLogs(RootVisitor* visitor)
REQUIRES(log_lock_)
@@ -213,7 +235,10 @@
void VisitArrayLogs(RootVisitor* visitor)
REQUIRES(log_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- void VisitStringLogs(RootVisitor* visitor)
+ void VisitInternStringLogs(RootVisitor* visitor)
+ REQUIRES(log_lock_)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ void VisitResolveStringLogs(RootVisitor* visitor)
REQUIRES(log_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -223,6 +248,7 @@
std::map<mirror::Object*, ObjectLog> object_logs_ GUARDED_BY(log_lock_);
std::map<mirror::Array*, ArrayLog> array_logs_ GUARDED_BY(log_lock_);
std::list<InternStringLog> intern_string_logs_ GUARDED_BY(log_lock_);
+ std::list<ResolveStringLog> resolve_string_logs_ GUARDED_BY(log_lock_);
bool aborted_ GUARDED_BY(log_lock_);
std::string abort_message_ GUARDED_BY(log_lock_);
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
index 8279a26..82e529c 100644
--- a/runtime/transaction_test.cc
+++ b/runtime/transaction_test.cc
@@ -20,11 +20,14 @@
#include "art_method-inl.h"
#include "class_linker-inl.h"
#include "common_runtime_test.h"
+#include "dex_file.h"
#include "mirror/array-inl.h"
#include "scoped_thread_state_change.h"
namespace art {
+static const size_t kDexNoIndex = DexFile::kDexNoIndex; // Make copy to prevent linking errors.
+
class TransactionTest : public CommonRuntimeTest {
public:
// Tests failing class initialization due to native call with transaction rollback.
@@ -482,6 +485,55 @@
EXPECT_EQ(objectArray->GetWithoutChecks(0), nullptr);
}
+// Tests rolling back interned strings and resolved strings.
+TEST_F(TransactionTest, ResolveString) {
+ ScopedObjectAccess soa(Thread::Current());
+ StackHandleScope<3> hs(soa.Self());
+ Handle<mirror::ClassLoader> class_loader(
+ hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+ ASSERT_TRUE(class_loader.Get() != nullptr);
+
+ Handle<mirror::Class> h_klass(
+ hs.NewHandle(class_linker_->FindClass(soa.Self(), "LTransaction$ResolveString;",
+ class_loader)));
+ ASSERT_TRUE(h_klass.Get() != nullptr);
+
+ Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(h_klass->GetDexCache()));
+ ASSERT_TRUE(h_dex_cache.Get() != nullptr);
+ const DexFile* const dex_file = h_dex_cache->GetDexFile();
+ ASSERT_TRUE(dex_file != nullptr);
+
+ // Go search the dex file to find the string id of our string.
+ static const char* kResolvedString = "ResolvedString";
+ const DexFile::StringId* string_id = dex_file->FindStringId(kResolvedString);
+ ASSERT_TRUE(string_id != nullptr);
+ uint32_t string_idx = dex_file->GetIndexForStringId(*string_id);
+ ASSERT_NE(string_idx, kDexNoIndex);
+ // String should only get resolved by the initializer.
+ EXPECT_TRUE(class_linker_->LookupString(*dex_file, string_idx, h_dex_cache) == nullptr);
+ EXPECT_TRUE(h_dex_cache->GetResolvedString(string_idx) == nullptr);
+ // Do the transaction, then roll back.
+ Transaction transaction;
+ Runtime::Current()->EnterTransactionMode(&transaction);
+ bool success = class_linker_->EnsureInitialized(soa.Self(), h_klass, true, true);
+ ASSERT_TRUE(success);
+ ASSERT_TRUE(h_klass->IsInitialized());
+ // Make sure the string got resolved by the transaction.
+ {
+ mirror::String* s = class_linker_->LookupString(*dex_file, string_idx, h_dex_cache);
+ ASSERT_TRUE(s != nullptr);
+ EXPECT_STREQ(s->ToModifiedUtf8().c_str(), kResolvedString);
+ EXPECT_EQ(s, h_dex_cache->GetResolvedString(string_idx));
+ }
+ Runtime::Current()->ExitTransactionMode();
+ transaction.Rollback();
+ // Check that the string did not stay resolved.
+ EXPECT_TRUE(class_linker_->LookupString(*dex_file, string_idx, h_dex_cache) == nullptr);
+ EXPECT_TRUE(h_dex_cache->GetResolvedString(string_idx) == nullptr);
+ ASSERT_FALSE(h_klass->IsInitialized());
+ ASSERT_FALSE(soa.Self()->IsExceptionPending());
+}
+
// Tests successful class initialization without class initializer.
TEST_F(TransactionTest, EmptyClass) {
ScopedObjectAccess soa(Thread::Current());
diff --git a/runtime/utils.h b/runtime/utils.h
index 2389ce7..958f0a3 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -386,6 +386,16 @@
__builtin___clear_cache(begin, end);
}
+template <typename T>
+constexpr PointerSize ConvertToPointerSize(T any) {
+ if (any == 4 || any == 8) {
+ return static_cast<PointerSize>(any);
+ } else {
+ LOG(FATAL);
+ UNREACHABLE();
+ }
+}
+
} // namespace art
#endif // ART_RUNTIME_UTILS_H_
diff --git a/runtime/utils/dex_cache_arrays_layout-inl.h b/runtime/utils/dex_cache_arrays_layout-inl.h
index 4c63156..a85d033 100644
--- a/runtime/utils/dex_cache_arrays_layout-inl.h
+++ b/runtime/utils/dex_cache_arrays_layout-inl.h
@@ -55,7 +55,8 @@
template <typename T>
static constexpr PointerSize GcRootAsPointerSize() {
- return ConvertToPointerSize(sizeof(GcRoot<T>));
+ static_assert(sizeof(GcRoot<T>) == 4U, "Unexpected GcRoot size");
+ return PointerSize::k32;
}
inline size_t DexCacheArraysLayout::TypeOffset(uint32_t type_idx) const {
diff --git a/test/538-checker-embed-constants/src/Main.java b/test/538-checker-embed-constants/src/Main.java
index f6713a2..04a12fa 100644
--- a/test/538-checker-embed-constants/src/Main.java
+++ b/test/538-checker-embed-constants/src/Main.java
@@ -102,12 +102,12 @@
/// CHECK-START-ARM: long Main.and255(long) disassembly (after)
/// CHECK-NOT: movs {{r\d+}}, #255
- /// CHECK-NOT: and
- /// CHECK-NOT: bic
+ /// CHECK-NOT: and{{(\.w)?}}
+ /// CHECK-NOT: bic{{(\.w)?}}
/// CHECK-DAG: and {{r\d+}}, {{r\d+}}, #255
/// CHECK-DAG: movs {{r\d+}}, #0
- /// CHECK-NOT: and
- /// CHECK-NOT: bic
+ /// CHECK-NOT: and{{(\.w)?}}
+ /// CHECK-NOT: bic{{(\.w)?}}
public static long and255(long arg) {
return arg & 255L;
@@ -115,12 +115,13 @@
/// CHECK-START-ARM: long Main.and511(long) disassembly (after)
/// CHECK: movw {{r\d+}}, #511
- /// CHECK-NOT: and
- /// CHECK-NOT: bic
- /// CHECK-DAG: and{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
- /// CHECK-DAG: movs {{r\d+}}, #0
- /// CHECK-NOT: and
- /// CHECK-NOT: bic
+ /// CHECK-NEXT: movs {{r\d+}}, #0
+ /// CHECK-NOT: and{{(\.w)?}}
+ /// CHECK-NOT: bic{{(\.w)?}}
+ /// CHECK: and{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+ /// CHECK-NEXT: and{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+ /// CHECK-NOT: and{{(\.w)?}}
+ /// CHECK-NOT: bic{{(\.w)?}}
public static long and511(long arg) {
return arg & 511L;
@@ -128,11 +129,11 @@
/// CHECK-START-ARM: long Main.andNot15(long) disassembly (after)
/// CHECK-NOT: mvn {{r\d+}}, #15
- /// CHECK-NOT: and
- /// CHECK-NOT: bic
+ /// CHECK-NOT: and{{(\.w)?}}
+ /// CHECK-NOT: bic{{(\.w)?}}
/// CHECK: bic {{r\d+}}, {{r\d+}}, #15
- /// CHECK-NOT: and
- /// CHECK-NOT: bic
+ /// CHECK-NOT: and{{(\.w)?}}
+ /// CHECK-NOT: bic{{(\.w)?}}
public static long andNot15(long arg) {
return arg & ~15L;
@@ -141,12 +142,12 @@
/// CHECK-START-ARM: long Main.and0xfffffff00000000f(long) disassembly (after)
/// CHECK-NOT: movs {{r\d+}}, #15
/// CHECK-NOT: mvn {{r\d+}}, #15
- /// CHECK-NOT: and
- /// CHECK-NOT: bic
+ /// CHECK-NOT: and{{(\.w)?}}
+ /// CHECK-NOT: bic{{(\.w)?}}
/// CHECK-DAG: and {{r\d+}}, {{r\d+}}, #15
/// CHECK-DAG: bic {{r\d+}}, {{r\d+}}, #15
- /// CHECK-NOT: and
- /// CHECK-NOT: bic
+ /// CHECK-NOT: and{{(\.w)?}}
+ /// CHECK-NOT: bic{{(\.w)?}}
public static long and0xfffffff00000000f(long arg) {
return arg & 0xfffffff00000000fL;
@@ -154,10 +155,10 @@
/// CHECK-START-ARM: long Main.or255(long) disassembly (after)
/// CHECK-NOT: movs {{r\d+}}, #255
- /// CHECK-NOT: orr
+ /// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
/// CHECK: orr {{r\d+}}, {{r\d+}}, #255
- /// CHECK-NOT: orr
+ /// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
public static long or255(long arg) {
@@ -166,10 +167,12 @@
/// CHECK-START-ARM: long Main.or511(long) disassembly (after)
/// CHECK: movw {{r\d+}}, #511
- /// CHECK-NOT: orr
+ /// CHECK-NEXT: movs {{r\d+}}, #0
+ /// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
/// CHECK: orr{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
- /// CHECK-NOT: orr
+ /// CHECK-NEXT: orr{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+ /// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
public static long or511(long arg) {
@@ -178,11 +181,11 @@
/// CHECK-START-ARM: long Main.orNot15(long) disassembly (after)
/// CHECK-NOT: mvn {{r\d+}}, #15
- /// CHECK-NOT: orr
+ /// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
/// CHECK-DAG: orn {{r\d+}}, {{r\d+}}, #15
/// CHECK-DAG: mvn {{r\d+}}, #0
- /// CHECK-NOT: orr
+ /// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
public static long orNot15(long arg) {
@@ -192,11 +195,11 @@
/// CHECK-START-ARM: long Main.or0xfffffff00000000f(long) disassembly (after)
/// CHECK-NOT: movs {{r\d+}}, #15
/// CHECK-NOT: mvn {{r\d+}}, #15
- /// CHECK-NOT: orr
+ /// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
/// CHECK-DAG: orr {{r\d+}}, {{r\d+}}, #15
/// CHECK-DAG: orn {{r\d+}}, {{r\d+}}, #15
- /// CHECK-NOT: orr
+ /// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
public static long or0xfffffff00000000f(long arg) {
@@ -205,9 +208,9 @@
/// CHECK-START-ARM: long Main.xor255(long) disassembly (after)
/// CHECK-NOT: movs {{r\d+}}, #255
- /// CHECK-NOT: eor
+ /// CHECK-NOT: eor{{(\.w)?}}
/// CHECK: eor {{r\d+}}, {{r\d+}}, #255
- /// CHECK-NOT: eor
+ /// CHECK-NOT: eor{{(\.w)?}}
public static long xor255(long arg) {
return arg ^ 255L;
@@ -215,9 +218,11 @@
/// CHECK-START-ARM: long Main.xor511(long) disassembly (after)
/// CHECK: movw {{r\d+}}, #511
- /// CHECK-NOT: eor
- /// CHECK-DAG: eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
- /// CHECK-NOT: eor
+ /// CHECK-NEXT: movs {{r\d+}}, #0
+ /// CHECK-NOT: eor{{(\.w)?}}
+ /// CHECK: eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+ /// CHECK-NEXT: eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+ /// CHECK-NOT: eor{{(\.w)?}}
public static long xor511(long arg) {
return arg ^ 511L;
@@ -226,10 +231,10 @@
/// CHECK-START-ARM: long Main.xorNot15(long) disassembly (after)
/// CHECK-DAG: mvn {{r\d+}}, #15
/// CHECK-DAG: mov.w {{r\d+}}, #-1
- /// CHECK-NOT: eor
+ /// CHECK-NOT: eor{{(\.w)?}}
/// CHECK-DAG: eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
/// CHECK-DAG: eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
- /// CHECK-NOT: eor
+ /// CHECK-NOT: eor{{(\.w)?}}
public static long xorNot15(long arg) {
return arg ^ ~15L;
@@ -239,10 +244,10 @@
/// CHECK-START-ARM: long Main.xor0xfffffff00000000f(long) disassembly (after)
/// CHECK-DAG: movs {{r\d+}}, #15
/// CHECK-DAG: mvn {{r\d+}}, #15
- /// CHECK-NOT: eor
+ /// CHECK-NOT: eor{{(\.w)?}}
/// CHECK-DAG: eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
/// CHECK-DAG: eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
- /// CHECK-NOT: eor
+ /// CHECK-NOT: eor{{(\.w)?}}
public static long xor0xfffffff00000000f(long arg) {
return arg ^ 0xfffffff00000000fL;
@@ -251,10 +256,10 @@
/// CHECK-START-ARM: long Main.xor0xf00000000000000f(long) disassembly (after)
/// CHECK-NOT: movs {{r\d+}}, #15
/// CHECK-NOT: mov.w {{r\d+}}, #-268435456
- /// CHECK-NOT: eor
+ /// CHECK-NOT: eor{{(\.w)?}}
/// CHECK-DAG: eor {{r\d+}}, {{r\d+}}, #15
/// CHECK-DAG: eor {{r\d+}}, {{r\d+}}, #-268435456
- /// CHECK-NOT: eor
+ /// CHECK-NOT: eor{{(\.w)?}}
public static long xor0xf00000000000000f(long arg) {
return arg ^ 0xf00000000000000fL;
diff --git a/test/Transaction/Transaction.java b/test/Transaction/Transaction.java
index 00e1fbb..e7085c1 100644
--- a/test/Transaction/Transaction.java
+++ b/test/Transaction/Transaction.java
@@ -18,6 +18,10 @@
static class EmptyStatic {
}
+ static class ResolveString {
+ static String s = "ResolvedString";
+ }
+
static class StaticFieldClass {
public static int intField;
static {
diff --git a/tools/bisection-search/README.md b/tools/bisection_search/README.md
similarity index 100%
rename from tools/bisection-search/README.md
rename to tools/bisection_search/README.md
diff --git a/tools/bisection_search/__init__.py b/tools/bisection_search/__init__.py
new file mode 100644
index 0000000..0a42789
--- /dev/null
+++ b/tools/bisection_search/__init__.py
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+
+# This file is intentionally left empty. It indicates that the directory is a Python package.
diff --git a/tools/bisection-search/bisection_search.py b/tools/bisection_search/bisection_search.py
similarity index 100%
rename from tools/bisection-search/bisection_search.py
rename to tools/bisection_search/bisection_search.py
diff --git a/tools/bisection-search/bisection_test.py b/tools/bisection_search/bisection_test.py
similarity index 100%
rename from tools/bisection-search/bisection_test.py
rename to tools/bisection_search/bisection_test.py
diff --git a/tools/bisection-search/common.py b/tools/bisection_search/common.py
similarity index 100%
rename from tools/bisection-search/common.py
rename to tools/bisection_search/common.py
diff --git a/tools/cpp-define-generator/Android.bp b/tools/cpp-define-generator/Android.bp
new file mode 100644
index 0000000..d792e90
--- /dev/null
+++ b/tools/cpp-define-generator/Android.bp
@@ -0,0 +1,36 @@
+//
+// 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.
+//
+
+// Build a "data" binary which will hold all the symbol values that will be parsed by the other scripts.
+//
+// Builds are for host only, target-specific define generation is possibly but is trickier and would need extra tooling.
+//
+// In the future we may wish to parameterize this on (32,64)x(read_barrier,no_read_barrier).
+
+art_cc_binary {
+ name: "cpp-define-generator-data",
+ host_supported: true,
+ device_supported: false,
+ defaults: [
+ "art_debug_defaults",
+ "art_defaults",
+ ],
+ include_dirs: ["art/runtime"],
+ srcs: ["main.cc"],
+ shared_libs: [
+ "libbase",
+ ],
+}
diff --git a/tools/cpp-define-generator/Android.mk b/tools/cpp-define-generator/Android.mk
deleted file mode 100644
index 6ba643c..0000000
--- a/tools/cpp-define-generator/Android.mk
+++ /dev/null
@@ -1,34 +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.executable.mk
-
-CPP_DEFINE_GENERATOR_SRC_FILES := \
- main.cc
-
-CPP_DEFINE_GENERATOR_EXTRA_SHARED_LIBRARIES :=
-CPP_DEFINE_GENERATOR_EXTRA_INCLUDE :=
-CPP_DEFINE_GENERATOR_MULTILIB :=
-
-# Build a "data" binary which will hold all the symbol values that will be parsed by the other scripts.
-#
-# Builds are for host only, target-specific define generation is possibly but is trickier and would need extra tooling.
-#
-# In the future we may wish to parameterize this on (32,64)x(read_barrier,no_read_barrier).
-$(eval $(call build-art-executable,cpp-define-generator-data,$(CPP_DEFINE_GENERATOR_SRC_FILES),$(CPP_DEFINE_GENERATOR_EXTRA_SHARED_LIBRARIES),$(CPP_DEFINE_GENERATOR_EXTRA_INCLUDE),host,debug,$(CPP_DEFINE_GENERATOR_MULTILIB),shared))
-
diff --git a/tools/dmtracedump/Android.bp b/tools/dmtracedump/Android.bp
new file mode 100644
index 0000000..4f942bd
--- /dev/null
+++ b/tools/dmtracedump/Android.bp
@@ -0,0 +1,44 @@
+// 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.
+
+// Java method trace dump tool
+
+art_cc_binary {
+ name: "dmtracedump",
+ host_supported: true,
+ device_supported: false,
+ srcs: ["tracedump.cc"],
+ cflags: [
+ "-O0",
+ "-g",
+ "-Wall",
+ ],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+}
+
+art_cc_binary {
+ name: "create_test_dmtrace",
+ host_supported: true,
+ device_supported: false,
+ srcs: ["createtesttrace.cc"],
+ cflags: [
+ "-O0",
+ "-g",
+ "-Wall",
+ ],
+}
diff --git a/tools/dmtracedump/Android.mk b/tools/dmtracedump/Android.mk
deleted file mode 100644
index da0d632..0000000
--- a/tools/dmtracedump/Android.mk
+++ /dev/null
@@ -1,32 +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.
-
-# Java method trace dump tool
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := tracedump.cc
-LOCAL_CFLAGS += -O0 -g -Wall
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_MODULE := dmtracedump
-include $(BUILD_HOST_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := createtesttrace.cc
-LOCAL_CFLAGS += -O0 -g -Wall
-LOCAL_MODULE := create_test_dmtrace
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/tools/javafuzz/__init__.py b/tools/javafuzz/__init__.py
new file mode 100644
index 0000000..3955c71
--- /dev/null
+++ b/tools/javafuzz/__init__.py
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+
+# This file is intentionally left empty. It indicates that the directory is a Python package.
\ No newline at end of file