diff options
278 files changed, 12788 insertions, 1854 deletions
diff --git a/Android.bp b/Android.bp index 4bcceffcd1..bb92e5f2f8 100644 --- a/Android.bp +++ b/Android.bp @@ -1,7 +1,6 @@ // TODO: These should be handled with transitive static library dependencies art_static_dependencies = [ // Note: the order is important because of static linking resolution. - "libdexfile", "libziparchive", "libnativehelper", "libnativebridge", @@ -36,6 +35,7 @@ subdirs = [ "dt_fd_forward", "dt_fd_forward/export", "imgdiag", + "libdexfile", "oatdump", "openjdkjvm", "openjdkjvmti", diff --git a/Android.mk b/Android.mk index 3267483f2d..2489308c02 100644 --- a/Android.mk +++ b/Android.mk @@ -487,8 +487,10 @@ build-art-target-golem: dex2oat dalvikvm patchoat linker libstdc++ \ $(ART_TARGET_SHARED_LIBRARY_BENCHMARK) \ $(TARGET_CORE_IMG_OUT_BASE).art \ $(TARGET_CORE_IMG_OUT_BASE)-interpreter.art + # remove libartd.so and libdexfiled.so from public.libraries.txt because golem builds + # won't have it. sed -i '/libartd.so/d' $(TARGET_OUT)/etc/public.libraries.txt - # remove libartd.so from public.libraries.txt because golem builds won't have it. + sed -i '/libdexfiled.so/d' $(TARGET_OUT)/etc/public.libraries.txt ######################################################################## # Phony target for building what go/lem requires on host. diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc index a0c99663b4..06ded26a2d 100644 --- a/adbconnection/adbconnection.cc +++ b/adbconnection/adbconnection.cc @@ -488,7 +488,6 @@ android::base::unique_fd AdbConnectionState::ReadFdFromAdb() { bool AdbConnectionState::SetupAdbConnection() { int sleep_ms = 500; const int sleep_max_ms = 2*1000; - char buff[sizeof(pid_t) + 1]; android::base::unique_fd sock(socket(AF_UNIX, SOCK_SEQPACKET, 0)); if (sock < 0) { @@ -499,8 +498,7 @@ bool AdbConnectionState::SetupAdbConnection() { timeout.tv_sec = kControlSockSendTimeout; timeout.tv_usec = 0; setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); - snprintf(buff, sizeof(buff), "%04x", getpid()); - buff[sizeof(pid_t)] = 0; + int32_t pid = getpid(); while (!shutting_down_) { // If adbd isn't running, because USB debugging was disabled or @@ -529,9 +527,9 @@ bool AdbConnectionState::SetupAdbConnection() { return false; } /* now try to send our pid to the ADB daemon */ - ret = TEMP_FAILURE_RETRY(send(sock, buff, sizeof(pid_t), 0)); - if (ret == sizeof(pid_t)) { - VLOG(jdwp) << "PID " << getpid() << " send to adb"; + ret = TEMP_FAILURE_RETRY(send(sock, &pid, sizeof(pid), 0)); + if (ret == sizeof(pid)) { + VLOG(jdwp) << "PID " << pid << " sent to adb"; control_sock_ = std::move(sock); return true; } else { @@ -539,7 +537,9 @@ bool AdbConnectionState::SetupAdbConnection() { return false; } } else { - PLOG(ERROR) << "Can't connect to ADB control socket. Will retry."; + if (VLOG_IS_ON(jdwp)) { + PLOG(ERROR) << "Can't connect to ADB control socket. Will retry."; + } usleep(sleep_ms * 1000); diff --git a/benchmark/type-check/info.txt b/benchmark/type-check/info.txt new file mode 100644 index 0000000000..d14fb9685b --- /dev/null +++ b/benchmark/type-check/info.txt @@ -0,0 +1 @@ +Benchmarks for repeating check-cast and instance-of instructions in a loop. diff --git a/benchmark/type-check/src/TypeCheckBenchmark.java b/benchmark/type-check/src/TypeCheckBenchmark.java new file mode 100644 index 0000000000..96904d99b6 --- /dev/null +++ b/benchmark/type-check/src/TypeCheckBenchmark.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class TypeCheckBenchmark { + public void timeCheckCastLevel1ToLevel1(int count) { + Object[] arr = arr1; + for (int i = 0; i < count; ++i) { + Level1 l1 = (Level1) arr[i & 1023]; + } + } + + public void timeCheckCastLevel2ToLevel1(int count) { + Object[] arr = arr2; + for (int i = 0; i < count; ++i) { + Level1 l1 = (Level1) arr[i & 1023]; + } + } + + public void timeCheckCastLevel3ToLevel1(int count) { + Object[] arr = arr3; + for (int i = 0; i < count; ++i) { + Level1 l1 = (Level1) arr[i & 1023]; + } + } + + public void timeCheckCastLevel9ToLevel1(int count) { + Object[] arr = arr9; + for (int i = 0; i < count; ++i) { + Level1 l1 = (Level1) arr[i & 1023]; + } + } + + public void timeCheckCastLevel9ToLevel2(int count) { + Object[] arr = arr9; + for (int i = 0; i < count; ++i) { + Level2 l2 = (Level2) arr[i & 1023]; + } + } + + public void timeInstanceOfLevel1ToLevel1(int count) { + int sum = 0; + Object[] arr = arr1; + for (int i = 0; i < count; ++i) { + if (arr[i & 1023] instanceof Level1) { + ++sum; + } + } + result = sum; + } + + public void timeInstanceOfLevel2ToLevel1(int count) { + int sum = 0; + Object[] arr = arr2; + for (int i = 0; i < count; ++i) { + if (arr[i & 1023] instanceof Level1) { + ++sum; + } + } + result = sum; + } + + public void timeInstanceOfLevel3ToLevel1(int count) { + int sum = 0; + Object[] arr = arr3; + for (int i = 0; i < count; ++i) { + if (arr[i & 1023] instanceof Level1) { + ++sum; + } + } + result = sum; + } + + public void timeInstanceOfLevel9ToLevel1(int count) { + int sum = 0; + Object[] arr = arr9; + for (int i = 0; i < count; ++i) { + if (arr[i & 1023] instanceof Level1) { + ++sum; + } + } + result = sum; + } + + public void timeInstanceOfLevel9ToLevel2(int count) { + int sum = 0; + Object[] arr = arr9; + for (int i = 0; i < count; ++i) { + if (arr[i & 1023] instanceof Level2) { + ++sum; + } + } + result = sum; + } + + public static Object[] createArray(int level) { + try { + Class<?>[] ls = { + null, + Level1.class, + Level2.class, + Level3.class, + Level4.class, + Level5.class, + Level6.class, + Level7.class, + Level8.class, + Level9.class, + }; + Class<?> l = ls[level]; + Object[] array = new Object[1024]; + for (int i = 0; i < array.length; ++i) { + array[i] = l.newInstance(); + } + return array; + } catch (Exception unexpected) { + throw new Error("Initialization failure!"); + } + } + Object[] arr1 = createArray(1); + Object[] arr2 = createArray(2); + Object[] arr3 = createArray(3); + Object[] arr9 = createArray(9); + int result; +} + +class Level1 { } +class Level2 extends Level1 { } +class Level3 extends Level2 { } +class Level4 extends Level3 { } +class Level5 extends Level4 { } +class Level6 extends Level5 { } +class Level7 extends Level6 { } +class Level8 extends Level7 { } +class Level9 extends Level8 { } diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index 894b33b00a..4a35ccfa13 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -83,6 +83,11 @@ ART_TEST_TARGET_GTEST_MainUncompressed_DEX := $(basename $(ART_TEST_TARGET_GTEST ART_TEST_HOST_GTEST_EmptyUncompressed_DEX := $(basename $(ART_TEST_HOST_GTEST_Main_DEX))EmptyUncompressed$(suffix $(ART_TEST_HOST_GTEST_Main_DEX)) ART_TEST_TARGET_GTEST_EmptyUncompressed_DEX := $(basename $(ART_TEST_TARGET_GTEST_Main_DEX))EmptyUncompressed$(suffix $(ART_TEST_TARGET_GTEST_Main_DEX)) +# Create rules for MultiDexUncompressed, a copy of MultiDex with the classes.dex uncompressed +# for the OatFile tests. +ART_TEST_HOST_GTEST_MultiDexUncompressed_DEX := $(basename $(ART_TEST_HOST_GTEST_MultiDex_DEX))Uncompressed$(suffix $(ART_TEST_HOST_GTEST_MultiDex_DEX)) +ART_TEST_TARGET_GTEST_MultiDexUncompressed_DEX := $(basename $(ART_TEST_TARGET_GTEST_MultiDex_DEX))Uncompressed$(suffix $(ART_TEST_TARGET_GTEST_MultiDex_DEX)) + $(ART_TEST_HOST_GTEST_MainStripped_DEX): $(ART_TEST_HOST_GTEST_Main_DEX) cp $< $@ $(call dexpreopt-remove-classes.dex,$@) @@ -111,6 +116,16 @@ $(ART_TEST_TARGET_GTEST_EmptyUncompressed_DEX): $(ZIPALIGN) zip -j -qD -X -0 $@ $(dir $@)classes.dex rm $(dir $@)classes.dex +$(ART_TEST_HOST_GTEST_MultiDexUncompressed_DEX): $(ART_TEST_HOST_GTEST_MultiDex_DEX) $(ZIPALIGN) + cp $< $@ + $(call uncompress-dexs, $@) + $(call align-package, $@) + +$(ART_TEST_TARGET_GTEST_MultiDexUncompressed_DEX): $(ART_TEST_TARGET_GTEST_MultiDex_DEX) $(ZIPALIGN) + cp $< $@ + $(call uncompress-dexs, $@) + $(call align-package, $@) + ART_TEST_GTEST_VerifierDeps_SRC := $(abspath $(wildcard $(LOCAL_PATH)/VerifierDeps/*.smali)) ART_TEST_GTEST_VerifierDepsMulti_SRC := $(abspath $(wildcard $(LOCAL_PATH)/VerifierDepsMulti/*.smali)) ART_TEST_HOST_GTEST_VerifierDeps_DEX := $(dir $(ART_TEST_HOST_GTEST_Main_DEX))$(subst Main,VerifierDeps,$(basename $(notdir $(ART_TEST_HOST_GTEST_Main_DEX))))$(suffix $(ART_TEST_HOST_GTEST_Main_DEX)) @@ -131,6 +146,7 @@ $(ART_TEST_TARGET_GTEST_VerifierDepsMulti_DEX): $(ART_TEST_GTEST_VerifierDepsMul $(HOST_OUT_EXECUTABLES)/smali assemble --output $@ $(filter %.smali,$^) # Dex file dependencies for each gtest. +ART_GTEST_art_dex_file_loader_test_DEX_DEPS := GetMethodSignature Main Nested MultiDex ART_GTEST_dex2oat_environment_tests_DEX_DEPS := Main MainStripped MultiDex MultiDexModifiedSecondary MyClassNatives Nested VerifierDeps VerifierDepsMulti ART_GTEST_atomic_dex_ref_map_test_DEX_DEPS := Interfaces @@ -139,7 +155,6 @@ ART_GTEST_class_loader_context_test_DEX_DEPS := Main MultiDex MyClass ForClassLo ART_GTEST_class_table_test_DEX_DEPS := XandY ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod StaticLeafMethods ProfileTestMultiDex ART_GTEST_dex_cache_test_DEX_DEPS := Main Packages MethodTypes -ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature Main Nested MultiDex ART_GTEST_dexlayout_test_DEX_DEPS := ManyMethods ART_GTEST_dex2oat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) ManyMethods Statics VerifierDeps MainUncompressed EmptyUncompressed ART_GTEST_dex2oat_image_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) Statics VerifierDeps @@ -153,7 +168,7 @@ ART_GTEST_jni_internal_test_DEX_DEPS := AllFields StaticLeafMethods ART_GTEST_oat_file_assistant_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) ART_GTEST_dexoptanalyzer_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) ART_GTEST_image_space_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) -ART_GTEST_oat_file_test_DEX_DEPS := Main MultiDex +ART_GTEST_oat_file_test_DEX_DEPS := Main MultiDex MainUncompressed MultiDexUncompressed ART_GTEST_oat_test_DEX_DEPS := Main ART_GTEST_object_test_DEX_DEPS := ProtoCompare ProtoCompare2 StaticsFromCode XandY ART_GTEST_patchoat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) @@ -318,6 +333,7 @@ ART_TEST_MODULES := \ art_dexoptanalyzer_tests \ art_hiddenapi_tests \ art_imgdiag_tests \ + art_libdexfile_tests \ art_oatdump_tests \ art_patchoat_tests \ art_profman_tests \ @@ -360,19 +376,31 @@ ifneq ($(ART_TEST_ANDROID_ROOT),) ART_GTEST_TARGET_ANDROID_ROOT := $(ART_TEST_ANDROID_ROOT) endif -ART_VALGRIND_TARGET_DEPENDENCIES := \ +ART_VALGRIND_TARGET_DEPENDENCIES := + +# Has to match list in external/valgrind/Android.build_one.mk +ART_VALGRIND_SUPPORTED_ARCH := arm arm64 x86_64 + +# Valgrind is not supported for x86 +ifneq (,$(filter $(ART_VALGRIND_SUPPORTED_ARCH),$(TARGET_ARCH))) +art_vg_arch := $(if $(filter x86_64,$(TARGET_ARCH)),amd64,$(TARGET_ARCH)) +ART_VALGRIND_TARGET_DEPENDENCIES += \ $(TARGET_OUT_EXECUTABLES)/valgrind \ - $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/memcheck-$(TARGET_ARCH)-linux \ - $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/vgpreload_core-$(TARGET_ARCH)-linux.so \ - $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/vgpreload_memcheck-$(TARGET_ARCH)-linux.so \ + $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/memcheck-$(art_vg_arch)-linux \ + $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/vgpreload_core-$(art_vg_arch)-linux.so \ + $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/vgpreload_memcheck-$(art_vg_arch)-linux.so \ $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/default.supp +art_vg_arch := +endif ifdef TARGET_2ND_ARCH +ifneq (,$(filter $(ART_VALGRIND_SUPPORTED_ARCH),$(TARGET_2ND_ARCH))) ART_VALGRIND_TARGET_DEPENDENCIES += \ $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/memcheck-$(TARGET_2ND_ARCH)-linux \ $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/vgpreload_core-$(TARGET_2ND_ARCH)-linux.so \ $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/vgpreload_memcheck-$(TARGET_2ND_ARCH)-linux.so endif +endif include $(CLEAR_VARS) LOCAL_MODULE := valgrind-target-suppressions.txt diff --git a/compiler/Android.bp b/compiler/Android.bp index 453965947d..ba08d7975b 100644 --- a/compiler/Android.bp +++ b/compiler/Android.bp @@ -184,7 +184,6 @@ art_cc_defaults { }, generated_sources: ["art_compiler_operator_srcs"], shared_libs: [ - "libdexfile", "libbase", "libcutils", // for atrace. "liblzma", @@ -250,6 +249,7 @@ art_cc_library { }, shared_libs: [ "libart", + "libdexfile", ], pgo: { @@ -295,6 +295,7 @@ art_cc_library { }, shared_libs: [ "libartd", + "libdexfiled", ], } diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc index f34e9b844b..451a909965 100644 --- a/compiler/jni/jni_compiler_test.cc +++ b/compiler/jni/jni_compiler_test.cc @@ -76,7 +76,7 @@ static bool IsCurrentJniNormal() { return gCurrentJni == static_cast<uint32_t>(JniKind::kNormal); } -// Signifify that a different kind of JNI is about to be tested. +// Signify that a different kind of JNI is about to be tested. static void UpdateCurrentJni(JniKind kind) { gCurrentJni = static_cast<uint32_t>(kind); } @@ -523,7 +523,8 @@ struct ScopedDisableCheckNumStackReferences { bool ScopedDisableCheckNumStackReferences::sCheckNumStackReferences = true; -// Check that the handle scope at the start of this block is the same as the handle scope at the end of the block. +// Check that the handle scope at the start of this block is the same +// as the handle scope at the end of the block. struct ScopedCheckHandleScope { ScopedCheckHandleScope() : handle_scope_(Thread::Current()->GetTopHandleScope()) { } diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index eb122b7781..97604b38a1 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -3702,77 +3702,251 @@ void InstructionCodeGeneratorMIPS::HandleCondition(HCondition* instruction) { void InstructionCodeGeneratorMIPS::DivRemOneOrMinusOne(HBinaryOperation* instruction) { DCHECK(instruction->IsDiv() || instruction->IsRem()); - DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt32); LocationSummary* locations = instruction->GetLocations(); Location second = locations->InAt(1); DCHECK(second.IsConstant()); - - Register out = locations->Out().AsRegister<Register>(); - Register dividend = locations->InAt(0).AsRegister<Register>(); - int32_t imm = second.GetConstant()->AsIntConstant()->GetValue(); + int64_t imm = Int64FromConstant(second.GetConstant()); DCHECK(imm == 1 || imm == -1); - if (instruction->IsRem()) { - __ Move(out, ZERO); + if (instruction->GetResultType() == DataType::Type::kInt32) { + Register out = locations->Out().AsRegister<Register>(); + Register dividend = locations->InAt(0).AsRegister<Register>(); + + if (instruction->IsRem()) { + __ Move(out, ZERO); + } else { + if (imm == -1) { + __ Subu(out, ZERO, dividend); + } else if (out != dividend) { + __ Move(out, dividend); + } + } } else { - if (imm == -1) { - __ Subu(out, ZERO, dividend); - } else if (out != dividend) { - __ Move(out, dividend); + DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64); + Register out_high = locations->Out().AsRegisterPairHigh<Register>(); + Register out_low = locations->Out().AsRegisterPairLow<Register>(); + Register in_high = locations->InAt(0).AsRegisterPairHigh<Register>(); + Register in_low = locations->InAt(0).AsRegisterPairLow<Register>(); + + if (instruction->IsRem()) { + __ Move(out_high, ZERO); + __ Move(out_low, ZERO); + } else { + if (imm == -1) { + __ Subu(out_low, ZERO, in_low); + __ Sltu(AT, ZERO, out_low); + __ Subu(out_high, ZERO, in_high); + __ Subu(out_high, out_high, AT); + } else { + __ Move(out_low, in_low); + __ Move(out_high, in_high); + } } } } void InstructionCodeGeneratorMIPS::DivRemByPowerOfTwo(HBinaryOperation* instruction) { DCHECK(instruction->IsDiv() || instruction->IsRem()); - DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt32); LocationSummary* locations = instruction->GetLocations(); Location second = locations->InAt(1); + const bool is_r2_or_newer = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2(); + const bool is_r6 = codegen_->GetInstructionSetFeatures().IsR6(); DCHECK(second.IsConstant()); - Register out = locations->Out().AsRegister<Register>(); - Register dividend = locations->InAt(0).AsRegister<Register>(); - int32_t imm = second.GetConstant()->AsIntConstant()->GetValue(); - uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm)); - int ctz_imm = CTZ(abs_imm); + if (instruction->GetResultType() == DataType::Type::kInt32) { + Register out = locations->Out().AsRegister<Register>(); + Register dividend = locations->InAt(0).AsRegister<Register>(); + int32_t imm = second.GetConstant()->AsIntConstant()->GetValue(); + uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm)); + int ctz_imm = CTZ(abs_imm); - if (instruction->IsDiv()) { - if (ctz_imm == 1) { - // Fast path for division by +/-2, which is very common. - __ Srl(TMP, dividend, 31); + if (instruction->IsDiv()) { + if (ctz_imm == 1) { + // Fast path for division by +/-2, which is very common. + __ Srl(TMP, dividend, 31); + } else { + __ Sra(TMP, dividend, 31); + __ Srl(TMP, TMP, 32 - ctz_imm); + } + __ Addu(out, dividend, TMP); + __ Sra(out, out, ctz_imm); + if (imm < 0) { + __ Subu(out, ZERO, out); + } } else { - __ Sra(TMP, dividend, 31); - __ Srl(TMP, TMP, 32 - ctz_imm); - } - __ Addu(out, dividend, TMP); - __ Sra(out, out, ctz_imm); - if (imm < 0) { - __ Subu(out, ZERO, out); + if (ctz_imm == 1) { + // Fast path for modulo +/-2, which is very common. + __ Sra(TMP, dividend, 31); + __ Subu(out, dividend, TMP); + __ Andi(out, out, 1); + __ Addu(out, out, TMP); + } else { + __ Sra(TMP, dividend, 31); + __ Srl(TMP, TMP, 32 - ctz_imm); + __ Addu(out, dividend, TMP); + if (IsUint<16>(abs_imm - 1)) { + __ Andi(out, out, abs_imm - 1); + } else { + if (is_r2_or_newer) { + __ Ins(out, ZERO, ctz_imm, 32 - ctz_imm); + } else { + __ Sll(out, out, 32 - ctz_imm); + __ Srl(out, out, 32 - ctz_imm); + } + } + __ Subu(out, out, TMP); + } } } else { - if (ctz_imm == 1) { - // Fast path for modulo +/-2, which is very common. - __ Sra(TMP, dividend, 31); - __ Subu(out, dividend, TMP); - __ Andi(out, out, 1); - __ Addu(out, out, TMP); + DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64); + Register out_high = locations->Out().AsRegisterPairHigh<Register>(); + Register out_low = locations->Out().AsRegisterPairLow<Register>(); + Register in_high = locations->InAt(0).AsRegisterPairHigh<Register>(); + Register in_low = locations->InAt(0).AsRegisterPairLow<Register>(); + int64_t imm = Int64FromConstant(second.GetConstant()); + uint64_t abs_imm = static_cast<uint64_t>(AbsOrMin(imm)); + int ctz_imm = CTZ(abs_imm); + + if (instruction->IsDiv()) { + if (ctz_imm < 32) { + if (ctz_imm == 1) { + __ Srl(AT, in_high, 31); + } else { + __ Sra(AT, in_high, 31); + __ Srl(AT, AT, 32 - ctz_imm); + } + __ Addu(AT, AT, in_low); + __ Sltu(TMP, AT, in_low); + __ Addu(out_high, in_high, TMP); + __ Srl(out_low, AT, ctz_imm); + if (is_r2_or_newer) { + __ Ins(out_low, out_high, 32 - ctz_imm, ctz_imm); + __ Sra(out_high, out_high, ctz_imm); + } else { + __ Sll(AT, out_high, 32 - ctz_imm); + __ Sra(out_high, out_high, ctz_imm); + __ Or(out_low, out_low, AT); + } + if (imm < 0) { + __ Subu(out_low, ZERO, out_low); + __ Sltu(AT, ZERO, out_low); + __ Subu(out_high, ZERO, out_high); + __ Subu(out_high, out_high, AT); + } + } else if (ctz_imm == 32) { + __ Sra(AT, in_high, 31); + __ Addu(AT, AT, in_low); + __ Sltu(AT, AT, in_low); + __ Addu(out_low, in_high, AT); + if (imm < 0) { + __ Srl(TMP, out_low, 31); + __ Subu(out_low, ZERO, out_low); + __ Sltu(AT, ZERO, out_low); + __ Subu(out_high, TMP, AT); + } else { + __ Sra(out_high, out_low, 31); + } + } else if (ctz_imm < 63) { + __ Sra(AT, in_high, 31); + __ Srl(TMP, AT, 64 - ctz_imm); + __ Addu(AT, AT, in_low); + __ Sltu(AT, AT, in_low); + __ Addu(out_low, in_high, AT); + __ Addu(out_low, out_low, TMP); + __ Sra(out_low, out_low, ctz_imm - 32); + if (imm < 0) { + __ Subu(out_low, ZERO, out_low); + } + __ Sra(out_high, out_low, 31); + } else { + DCHECK_LT(imm, 0); + if (is_r6) { + __ Aui(AT, in_high, 0x8000); + } else { + __ Lui(AT, 0x8000); + __ Xor(AT, AT, in_high); + } + __ Or(AT, AT, in_low); + __ Sltiu(out_low, AT, 1); + __ Move(out_high, ZERO); + } } else { - __ Sra(TMP, dividend, 31); - __ Srl(TMP, TMP, 32 - ctz_imm); - __ Addu(out, dividend, TMP); - if (IsUint<16>(abs_imm - 1)) { - __ Andi(out, out, abs_imm - 1); + if ((ctz_imm == 1) && !is_r6) { + __ Andi(AT, in_low, 1); + __ Sll(TMP, in_low, 31); + __ And(TMP, in_high, TMP); + __ Sra(out_high, TMP, 31); + __ Or(out_low, out_high, AT); + } else if (ctz_imm < 32) { + __ Sra(AT, in_high, 31); + if (ctz_imm <= 16) { + __ Andi(out_low, in_low, abs_imm - 1); + } else if (is_r2_or_newer) { + __ Ext(out_low, in_low, 0, ctz_imm); + } else { + __ Sll(out_low, in_low, 32 - ctz_imm); + __ Srl(out_low, out_low, 32 - ctz_imm); + } + if (is_r6) { + __ Selnez(out_high, AT, out_low); + } else { + __ Movz(AT, ZERO, out_low); + __ Move(out_high, AT); + } + if (is_r2_or_newer) { + __ Ins(out_low, out_high, ctz_imm, 32 - ctz_imm); + } else { + __ Sll(AT, out_high, ctz_imm); + __ Or(out_low, out_low, AT); + } + } else if (ctz_imm == 32) { + __ Sra(AT, in_high, 31); + __ Move(out_low, in_low); + if (is_r6) { + __ Selnez(out_high, AT, out_low); + } else { + __ Movz(AT, ZERO, out_low); + __ Move(out_high, AT); + } + } else if (ctz_imm < 63) { + __ Sra(AT, in_high, 31); + __ Move(TMP, in_low); + if (ctz_imm - 32 <= 16) { + __ Andi(out_high, in_high, (1 << (ctz_imm - 32)) - 1); + } else if (is_r2_or_newer) { + __ Ext(out_high, in_high, 0, ctz_imm - 32); + } else { + __ Sll(out_high, in_high, 64 - ctz_imm); + __ Srl(out_high, out_high, 64 - ctz_imm); + } + __ Move(out_low, TMP); + __ Or(TMP, TMP, out_high); + if (is_r6) { + __ Selnez(AT, AT, TMP); + } else { + __ Movz(AT, ZERO, TMP); + } + if (is_r2_or_newer) { + __ Ins(out_high, AT, ctz_imm - 32, 64 - ctz_imm); + } else { + __ Sll(AT, AT, ctz_imm - 32); + __ Or(out_high, out_high, AT); + } } else { - if (codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2()) { - __ Ins(out, ZERO, ctz_imm, 32 - ctz_imm); + if (is_r6) { + __ Aui(AT, in_high, 0x8000); } else { - __ Sll(out, out, 32 - ctz_imm); - __ Srl(out, out, 32 - ctz_imm); + __ Lui(AT, 0x8000); + __ Xor(AT, AT, in_high); } + __ Or(AT, AT, in_low); + __ Sltiu(AT, AT, 1); + __ Sll(AT, AT, 31); + __ Move(out_low, in_low); + __ Xor(out_high, in_high, AT); } - __ Subu(out, out, TMP); } } } @@ -3870,7 +4044,16 @@ void InstructionCodeGeneratorMIPS::GenerateDivRemIntegral(HBinaryOperation* inst void LocationsBuilderMIPS::VisitDiv(HDiv* div) { DataType::Type type = div->GetResultType(); - LocationSummary::CallKind call_kind = (type == DataType::Type::kInt64) + bool call_long_div = false; + if (type == DataType::Type::kInt64) { + if (div->InputAt(1)->IsConstant()) { + int64_t imm = CodeGenerator::GetInt64ValueOf(div->InputAt(1)->AsConstant()); + call_long_div = (imm != 0) && !IsPowerOfTwo(static_cast<uint64_t>(AbsOrMin(imm))); + } else { + call_long_div = true; + } + } + LocationSummary::CallKind call_kind = call_long_div ? LocationSummary::kCallOnMainOnly : LocationSummary::kNoCall; @@ -3884,12 +4067,18 @@ void LocationsBuilderMIPS::VisitDiv(HDiv* div) { break; case DataType::Type::kInt64: { - InvokeRuntimeCallingConvention calling_convention; - locations->SetInAt(0, Location::RegisterPairLocation( - calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); - locations->SetInAt(1, Location::RegisterPairLocation( - calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); - locations->SetOut(calling_convention.GetReturnLocation(type)); + if (call_long_div) { + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterPairLocation( + calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); + locations->SetInAt(1, Location::RegisterPairLocation( + calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); + locations->SetOut(calling_convention.GetReturnLocation(type)); + } else { + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant())); + locations->SetOut(Location::RequiresRegister()); + } break; } @@ -3914,8 +4103,20 @@ void InstructionCodeGeneratorMIPS::VisitDiv(HDiv* instruction) { GenerateDivRemIntegral(instruction); break; case DataType::Type::kInt64: { - codegen_->InvokeRuntime(kQuickLdiv, instruction, instruction->GetDexPc()); - CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>(); + if (locations->InAt(1).IsConstant()) { + int64_t imm = locations->InAt(1).GetConstant()->AsLongConstant()->GetValue(); + if (imm == 0) { + // Do not generate anything. DivZeroCheck would prevent any code to be executed. + } else if (imm == 1 || imm == -1) { + DivRemOneOrMinusOne(instruction); + } else { + DCHECK(IsPowerOfTwo(static_cast<uint64_t>(AbsOrMin(imm)))); + DivRemByPowerOfTwo(instruction); + } + } else { + codegen_->InvokeRuntime(kQuickLdiv, instruction, instruction->GetDexPc()); + CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>(); + } break; } case DataType::Type::kFloat32: @@ -8493,9 +8694,16 @@ void InstructionCodeGeneratorMIPS::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) void LocationsBuilderMIPS::VisitRem(HRem* rem) { DataType::Type type = rem->GetResultType(); - LocationSummary::CallKind call_kind = (type == DataType::Type::kInt32) - ? LocationSummary::kNoCall - : LocationSummary::kCallOnMainOnly; + bool call_rem; + if ((type == DataType::Type::kInt64) && rem->InputAt(1)->IsConstant()) { + int64_t imm = CodeGenerator::GetInt64ValueOf(rem->InputAt(1)->AsConstant()); + call_rem = (imm != 0) && !IsPowerOfTwo(static_cast<uint64_t>(AbsOrMin(imm))); + } else { + call_rem = (type != DataType::Type::kInt32); + } + LocationSummary::CallKind call_kind = call_rem + ? LocationSummary::kCallOnMainOnly + : LocationSummary::kNoCall; LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(rem, call_kind); switch (type) { @@ -8506,12 +8714,18 @@ void LocationsBuilderMIPS::VisitRem(HRem* rem) { break; case DataType::Type::kInt64: { - InvokeRuntimeCallingConvention calling_convention; - locations->SetInAt(0, Location::RegisterPairLocation( - calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); - locations->SetInAt(1, Location::RegisterPairLocation( - calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); - locations->SetOut(calling_convention.GetReturnLocation(type)); + if (call_rem) { + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterPairLocation( + calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); + locations->SetInAt(1, Location::RegisterPairLocation( + calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); + locations->SetOut(calling_convention.GetReturnLocation(type)); + } else { + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant())); + locations->SetOut(Location::RequiresRegister()); + } break; } @@ -8531,14 +8745,27 @@ void LocationsBuilderMIPS::VisitRem(HRem* rem) { void InstructionCodeGeneratorMIPS::VisitRem(HRem* instruction) { DataType::Type type = instruction->GetType(); + LocationSummary* locations = instruction->GetLocations(); switch (type) { case DataType::Type::kInt32: GenerateDivRemIntegral(instruction); break; case DataType::Type::kInt64: { - codegen_->InvokeRuntime(kQuickLmod, instruction, instruction->GetDexPc()); - CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>(); + if (locations->InAt(1).IsConstant()) { + int64_t imm = locations->InAt(1).GetConstant()->AsLongConstant()->GetValue(); + if (imm == 0) { + // Do not generate anything. DivZeroCheck would prevent any code to be executed. + } else if (imm == 1 || imm == -1) { + DivRemOneOrMinusOne(instruction); + } else { + DCHECK(IsPowerOfTwo(static_cast<uint64_t>(AbsOrMin(imm)))); + DivRemByPowerOfTwo(instruction); + } + } else { + codegen_->InvokeRuntime(kQuickLmod, instruction, instruction->GetDexPc()); + CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>(); + } break; } case DataType::Type::kFloat32: { diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index 64a1eccf60..a38e2717cf 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -960,14 +960,18 @@ bool HInstructionBuilder::BuildInvoke(const Instruction& instruction, HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod, dchecked_integral_cast<uint64_t>(string_init_entry_point) }; - MethodReference target_method(dex_file_, method_idx); + ScopedObjectAccess soa(Thread::Current()); + MethodReference target_method(resolved_method->GetDexFile(), + resolved_method->GetDexMethodIndex()); + // We pass null for the resolved_method to ensure optimizations + // don't rely on it. HInvoke* invoke = new (allocator_) HInvokeStaticOrDirect( allocator_, number_of_arguments - 1, DataType::Type::kReference /*return_type */, dex_pc, method_idx, - nullptr, + nullptr /* resolved_method */, dispatch_info, invoke_type, target_method, diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 43ca2cf874..f91d37b3ac 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -4567,7 +4567,7 @@ class HInvokeStaticOrDirect FINAL : public HInvoke { kFieldClinitCheckRequirementSize>; // Cached values of the resolved method, to avoid needing the mutator lock. - MethodReference target_method_; + const MethodReference target_method_; DispatchInfo dispatch_info_; }; std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::MethodLoadKind rhs); diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index 8bb124e066..67a61fc01d 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -537,14 +537,13 @@ void ReferenceTypePropagation::RTPVisitor::SetClassAsTypeInfo(HInstruction* inst Thread* self = Thread::Current(); StackHandleScope<2> hs(self); const DexFile& dex_file = *invoke->GetTargetMethod().dex_file; + uint32_t dex_method_index = invoke->GetTargetMethod().index; Handle<mirror::DexCache> dex_cache( hs.NewHandle(FindDexCacheWithHint(self, dex_file, hint_dex_cache_))); - // Use a null loader. We should probably use the compiling method's class loader, - // but then we would need to pass it to RTPVisitor just for this debug check. Since - // the method is from the String class, the null loader is good enough. + // Use a null loader, the target method is in a boot classpath dex file. Handle<mirror::ClassLoader> loader(hs.NewHandle<mirror::ClassLoader>(nullptr)); ArtMethod* method = cl->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>( - invoke->GetDexMethodIndex(), dex_cache, loader, /* referrer */ nullptr, kDirect); + dex_method_index, dex_cache, loader, /* referrer */ nullptr, kDirect); DCHECK(method != nullptr); mirror::Class* declaring_class = method->GetDeclaringClass(); DCHECK(declaring_class != nullptr); diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc index 8640e2db0e..ea160c8993 100644 --- a/compiler/utils/x86/assembler_x86.cc +++ b/compiler/utils/x86/assembler_x86.cc @@ -1914,7 +1914,7 @@ void X86Assembler::cmpb(const Address& address, const Immediate& imm) { void X86Assembler::cmpw(const Address& address, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); - EmitComplex(7, address, imm); + EmitComplex(7, address, imm, /* is_16_op */ true); } diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc index 937dd80c4e..2fd1b27182 100644 --- a/compiler/utils/x86/assembler_x86_test.cc +++ b/compiler/utils/x86/assembler_x86_test.cc @@ -921,9 +921,7 @@ TEST_F(AssemblerX86Test, Cmpb) { } TEST_F(AssemblerX86Test, Cmpw) { - DriverStr(RepeatAI(&x86::X86Assembler::cmpw, - /*imm_bytes*/ 1U, - "cmpw ${imm}, {mem}"), "cmpw"); // TODO: only imm8? + DriverStr(RepeatAI(&x86::X86Assembler::cmpw, /*imm_bytes*/ 2U, "cmpw ${imm}, {mem}"), "cmpw"); } } // namespace art diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc index feabf260af..ff5a357c5e 100644 --- a/compiler/utils/x86_64/assembler_x86_64.cc +++ b/compiler/utils/x86_64/assembler_x86_64.cc @@ -2199,7 +2199,7 @@ void X86_64Assembler::cmpw(const Address& address, const Immediate& imm) { CHECK(imm.is_int32()); EmitOperandSizeOverride(); EmitOptionalRex32(address); - EmitComplex(7, address, imm); + EmitComplex(7, address, imm, /* is_16_op */ true); } diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc index 5e6c83396a..6b1e53c35a 100644 --- a/compiler/utils/x86_64/assembler_x86_64_test.cc +++ b/compiler/utils/x86_64/assembler_x86_64_test.cc @@ -967,9 +967,8 @@ TEST_F(AssemblerX86_64Test, MovbStore) { } TEST_F(AssemblerX86_64Test, Cmpw) { - DriverStr(RepeatAI(&x86_64::X86_64Assembler::cmpw, - /*imm_bytes*/ 1U, - "cmpw ${imm}, {mem}"), "cmpw"); // TODO: only imm8? + DriverStr( + RepeatAI(&x86_64::X86_64Assembler::cmpw, /*imm_bytes*/ 2U, "cmpw ${imm}, {mem}"), "cmpw"); } TEST_F(AssemblerX86_64Test, MovqAddrImm) { diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp index ab06ddda2d..dd16ba4909 100644 --- a/dex2oat/Android.bp +++ b/dex2oat/Android.bp @@ -152,7 +152,7 @@ art_cc_binary { "libartd-compiler", "libartd-dexlayout", "libartd", - "libdexfile", + "libdexfiled", "libbase", "liblz4", "libsigchain", @@ -185,6 +185,7 @@ art_cc_binary { "libart-compiler", "libart-dexlayout", "libart", + "libdexfile", "libvixl-arm", "libvixl-arm64", ] + art_static_dependencies, @@ -216,6 +217,7 @@ art_cc_binary { "libartd-compiler", "libartd-dexlayout", "libartd", + "libdexfiled", "libvixld-arm", "libvixld-arm64", ] + art_static_dependencies, diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index c4e53987eb..64db7be79c 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -456,6 +456,12 @@ NO_RETURN static void Usage(const char* fmt, ...) { UsageError(" --deduplicate-code=true|false: enable|disable code deduplication. Deduplicated"); UsageError(" code will have an arbitrary symbol tagged with [DEDUPED]."); UsageError(""); + UsageError(" --compilation-reason=<string>: optional metadata specifying the reason for"); + UsageError(" compiling the apk. If specified, the string will be embedded verbatim in"); + UsageError(" the key value store of the oat file."); + UsageError(""); + UsageError(" Example: --compilation-reason=install"); + UsageError(""); std::cerr << "See log for usage error information\n"; exit(EXIT_FAILURE); } @@ -1212,6 +1218,7 @@ class Dex2Oat FINAL { AssignIfExists(args, M::ClasspathDir, &classpath_dir_); AssignIfExists(args, M::DirtyImageObjects, &dirty_image_objects_filename_); AssignIfExists(args, M::ImageFormat, &image_storage_mode_); + AssignIfExists(args, M::CompilationReason, &compilation_reason_); AssignIfExists(args, M::Backend, &compiler_kind_); parser_options->requested_specific_compiler = args.Exists(M::Backend); @@ -1512,6 +1519,10 @@ class Dex2Oat FINAL { return dex2oat::ReturnCode::kOther; } + if (!compilation_reason_.empty()) { + key_value_store_->Put(OatHeader::kCompilationReasonKey, compilation_reason_); + } + if (IsBootImage() && image_filenames_.size() > 1) { // If we're compiling the boot image, store the boot classpath into the Key-Value store. // We need this for the multi-image case. @@ -2907,6 +2918,9 @@ class Dex2Oat FINAL { // Whether the given input vdex is also the output. bool update_input_vdex_ = false; + // The reason for invoking the compiler. + std::string compilation_reason_; + DISALLOW_IMPLICIT_CONSTRUCTORS(Dex2Oat); }; diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc index 0eecc84605..4b6f8a4a54 100644 --- a/dex2oat/dex2oat_options.cc +++ b/dex2oat/dex2oat_options.cc @@ -246,7 +246,10 @@ static Parser CreateArgumentParser() { .IntoKey(M::CompactDexLevel) .Define("--runtime-arg _") .WithType<std::vector<std::string>>().AppendValues() - .IntoKey(M::RuntimeOptions); + .IntoKey(M::RuntimeOptions) + .Define("--compilation-reason=_") + .WithType<std::string>() + .IntoKey(M::CompilationReason); AddCompilerOptionsArgumentParserOptions<Dex2oatArgumentMap>(*parser_builder); diff --git a/dex2oat/dex2oat_options.def b/dex2oat/dex2oat_options.def index 9a8bdf4aee..a1646aafe3 100644 --- a/dex2oat/dex2oat_options.def +++ b/dex2oat/dex2oat_options.def @@ -89,5 +89,6 @@ DEX2OAT_OPTIONS_KEY (std::string, ClasspathDir) DEX2OAT_OPTIONS_KEY (std::string, ClassLoaderContext) DEX2OAT_OPTIONS_KEY (std::string, DirtyImageObjects) DEX2OAT_OPTIONS_KEY (std::vector<std::string>, RuntimeOptions) +DEX2OAT_OPTIONS_KEY (std::string, CompilationReason) #undef DEX2OAT_OPTIONS_KEY diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index d0b0d49a39..4ac8e6a3eb 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -796,7 +796,7 @@ class Dex2oatLayoutTest : public Dex2oatTest { app_image_file_name, /* use_fd */ true, /* num_profile_classes */ 1, - { input_vdex, output_vdex, kDisableCompactDex }, + { input_vdex, output_vdex }, /* expect_success */ true); EXPECT_GT(vdex_file2.GetFile()->GetLength(), 0u); } @@ -926,6 +926,49 @@ class Dex2oatUnquickenTest : public Dex2oatTest { ASSERT_TRUE(success_); } + void RunUnquickenMultiDexCDex() { + std::string dex_location = GetScratchDir() + "/UnquickenMultiDex.jar"; + std::string odex_location = GetOdexDir() + "/UnquickenMultiDex.odex"; + std::string odex_location2 = GetOdexDir() + "/UnquickenMultiDex2.odex"; + std::string vdex_location = GetOdexDir() + "/UnquickenMultiDex.vdex"; + std::string vdex_location2 = GetOdexDir() + "/UnquickenMultiDex2.vdex"; + Copy(GetTestDexFileName("MultiDex"), dex_location); + + std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str())); + std::unique_ptr<File> vdex_file2(OS::CreateEmptyFile(vdex_location2.c_str())); + CHECK(vdex_file1 != nullptr) << vdex_location; + CHECK(vdex_file2 != nullptr) << vdex_location2; + + // Quicken the dex file into a vdex file. + { + std::string input_vdex = "--input-vdex-fd=-1"; + std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd()); + GenerateOdexForTest(dex_location, + odex_location, + CompilerFilter::kQuicken, + { input_vdex, output_vdex, "--compact-dex-level=fast"}, + /* expect_success */ true, + /* use_fd */ true); + EXPECT_GT(vdex_file1->GetLength(), 0u); + } + + // Unquicken by running the verify compiler filter on the vdex file. + { + std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd()); + std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file2->Fd()); + GenerateOdexForTest(dex_location, + odex_location2, + CompilerFilter::kVerify, + { input_vdex, output_vdex, "--compact-dex-level=none"}, + /* expect_success */ true, + /* use_fd */ true); + } + ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file"; + ASSERT_EQ(vdex_file2->FlushCloseOrErase(), 0) << "Could not flush and close vdex file"; + CheckResult(dex_location, odex_location2); + ASSERT_TRUE(success_); + } + void CheckResult(const std::string& dex_location, const std::string& odex_location) { std::string error_msg; std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(), @@ -966,6 +1009,10 @@ TEST_F(Dex2oatUnquickenTest, UnquickenMultiDex) { RunUnquickenMultiDex(); } +TEST_F(Dex2oatUnquickenTest, UnquickenMultiDexCDex) { + RunUnquickenMultiDexCDex(); +} + class Dex2oatWatchdogTest : public Dex2oatTest { protected: void RunTest(bool expect_success, const std::vector<std::string>& extra_args = {}) { @@ -1667,4 +1714,71 @@ TEST_F(Dex2oatTest, CompactDexGenerationFailure) { } } +TEST_F(Dex2oatTest, StderrLoggerOutput) { + std::string dex_location = GetScratchDir() + "/Dex2OatStderrLoggerTest.jar"; + std::string odex_location = GetOdexDir() + "/Dex2OatStderrLoggerTest.odex"; + + // Test file doesn't matter. + Copy(GetDexSrc1(), dex_location); + + GenerateOdexForTest(dex_location, + odex_location, + CompilerFilter::kQuicken, + { "--runtime-arg", "-Xuse-stderr-logger" }, + true); + // Look for some random part of dex2oat logging. With the stderr logger this should be captured, + // even on device. + EXPECT_NE(std::string::npos, output_.find("dex2oat took")); +} + +TEST_F(Dex2oatTest, VerifyCompilationReason) { + std::string dex_location = GetScratchDir() + "/Dex2OatCompilationReason.jar"; + std::string odex_location = GetOdexDir() + "/Dex2OatCompilationReason.odex"; + + // Test file doesn't matter. + Copy(GetDexSrc1(), dex_location); + + GenerateOdexForTest(dex_location, + odex_location, + CompilerFilter::kVerify, + { "--compilation-reason=install" }, + true); + std::string error_msg; + std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(), + odex_location.c_str(), + nullptr, + nullptr, + false, + /*low_4gb*/false, + dex_location.c_str(), + &error_msg)); + ASSERT_TRUE(odex_file != nullptr); + ASSERT_STREQ("install", odex_file->GetCompilationReason()); +} + +TEST_F(Dex2oatTest, VerifyNoCompilationReason) { + std::string dex_location = GetScratchDir() + "/Dex2OatNoCompilationReason.jar"; + std::string odex_location = GetOdexDir() + "/Dex2OatNoCompilationReason.odex"; + + // Test file doesn't matter. + Copy(GetDexSrc1(), dex_location); + + GenerateOdexForTest(dex_location, + odex_location, + CompilerFilter::kVerify, + {}, + true); + std::string error_msg; + std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(), + odex_location.c_str(), + nullptr, + nullptr, + false, + /*low_4gb*/false, + dex_location.c_str(), + &error_msg)); + ASSERT_TRUE(odex_file != nullptr); + ASSERT_EQ(nullptr, odex_file->GetCompilationReason()); +} + } // namespace art diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc index 73eaad47a1..42d228078c 100644 --- a/dex2oat/linker/image_writer.cc +++ b/dex2oat/linker/image_writer.cc @@ -2364,7 +2364,7 @@ void ImageWriter::FixupClass(mirror::Class* orig, mirror::Class* copy) { FixupClassVisitor visitor(this, copy); ObjPtr<mirror::Object>(orig)->VisitReferences(visitor, visitor); - if (compile_app_image_) { + if (kBitstringSubtypeCheckEnabled && compile_app_image_) { // When we call SubtypeCheck::EnsureInitialize, it Assigns new bitstring // values to the parent of that class. // diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index 01125a178e..7d8065e926 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -3373,15 +3373,19 @@ bool OatWriter::WriteDexFiles(OutputStream* out, File* file, bool update_input_v CHECK(!update_input_vdex) << "Update input vdex should have empty dex container"; DexContainer::Section* const section = dex_container_->GetDataSection(); if (section->Size() > 0) { - const uint32_t shared_data_offset = vdex_size_; const off_t existing_offset = out->Seek(0, kSeekCurrent); - if (static_cast<uint32_t>(existing_offset) != shared_data_offset) { - LOG(ERROR) << "Expected offset " << shared_data_offset << " but got " << existing_offset; + if (static_cast<uint32_t>(existing_offset) != vdex_dex_shared_data_offset_) { + PLOG(ERROR) << "Expected offset " << vdex_dex_shared_data_offset_ << " but got " + << existing_offset; return false; } shared_data_size = section->Size(); if (!out->WriteFully(section->Begin(), shared_data_size)) { - LOG(ERROR) << "Failed to write shared data!"; + PLOG(ERROR) << "Failed to write shared data!"; + return false; + } + if (!out->Flush()) { + PLOG(ERROR) << "Failed to flush after writing shared dex section."; return false; } // Fix up the dex headers to have correct offsets to the data section. @@ -3389,49 +3393,69 @@ bool OatWriter::WriteDexFiles(OutputStream* out, File* file, bool update_input_v // Overwrite the header by reading it, updating the offset, and writing it back out. DexFile::Header header; if (!file->PreadFully(&header, sizeof(header), oat_dex_file.dex_file_offset_)) { - LOG(ERROR) << "Failed to read dex header for updating"; + PLOG(ERROR) << "Failed to read dex header for updating"; return false; } CHECK(CompactDexFile::IsMagicValid(header.magic_)) << "Must be compact dex"; - CHECK_GT(shared_data_offset, oat_dex_file.dex_file_offset_); + CHECK_GT(vdex_dex_shared_data_offset_, oat_dex_file.dex_file_offset_); // Offset is from the dex file base. - header.data_off_ = shared_data_offset - oat_dex_file.dex_file_offset_; + header.data_off_ = vdex_dex_shared_data_offset_ - oat_dex_file.dex_file_offset_; // The size should already be what part of the data buffer may be used by the dex. CHECK_LE(header.data_size_, shared_data_size); if (!file->PwriteFully(&header, sizeof(header), oat_dex_file.dex_file_offset_)) { - LOG(ERROR) << "Failed to write dex header for updating"; + PLOG(ERROR) << "Failed to write dex header for updating"; return false; } } section->Clear(); - if (!out->Flush()) { - PLOG(ERROR) << "Failed to flush after writing shared dex section."; - return false; - } } dex_container_.reset(); } else { - if (update_input_vdex) { - for (OatDexFile& oat_dex_file : oat_dex_files_) { - DexFile::Header header; - if (!file->PreadFully(&header, sizeof(header), oat_dex_file.dex_file_offset_)) { - PLOG(ERROR) << "Failed to read dex header"; - return false; - } - if (!CompactDexFile::IsMagicValid(header.magic_)) { - // Non compact dex does not have shared data section. - continue; - } - const uint32_t expected_data_off = vdex_dex_shared_data_offset_ - - oat_dex_file.dex_file_offset_; - if (header.data_off_ != expected_data_off) { - PLOG(ERROR) << "Shared data section offset " << header.data_off_ - << " does not match expected value " << expected_data_off; - return false; + const uint8_t* data_begin = nullptr; + for (OatDexFile& oat_dex_file : oat_dex_files_) { + DexFile::Header header; + if (!file->PreadFully(&header, sizeof(header), oat_dex_file.dex_file_offset_)) { + PLOG(ERROR) << "Failed to read dex header"; + return false; + } + if (!CompactDexFile::IsMagicValid(header.magic_)) { + // Non compact dex does not have shared data section. + continue; + } + const uint32_t expected_data_off = vdex_dex_shared_data_offset_ - + oat_dex_file.dex_file_offset_; + if (header.data_off_ != expected_data_off) { + PLOG(ERROR) << "Shared data section offset " << header.data_off_ + << " does not match expected value " << expected_data_off; + return false; + } + if (oat_dex_file.source_.IsRawData()) { + // Figure out the start of the shared data section so we can copy it below. + const uint8_t* cur_data_begin = oat_dex_file.source_.GetRawData() + header.data_off_; + if (data_begin != nullptr) { + CHECK_EQ(data_begin, cur_data_begin); } - // The different dex files currently can have different data sizes since - // the dex writer writes them one at a time into the shared section.:w - shared_data_size = std::max(shared_data_size, header.data_size_); + data_begin = cur_data_begin; + } + // The different dex files currently can have different data sizes since + // the dex writer writes them one at a time into the shared section.:w + shared_data_size = std::max(shared_data_size, header.data_size_); + } + // If we are not updating the input vdex, write out the shared data section. + if (!update_input_vdex) { + const off_t existing_offset = out->Seek(0, kSeekCurrent); + if (static_cast<uint32_t>(existing_offset) != vdex_dex_shared_data_offset_) { + PLOG(ERROR) << "Expected offset " << vdex_dex_shared_data_offset_ << " but got " + << existing_offset; + return false; + } + if (!out->WriteFully(data_begin, shared_data_size)) { + PLOG(ERROR) << "Failed to write shared data!"; + return false; + } + if (!out->Flush()) { + PLOG(ERROR) << "Failed to flush after writing shared dex section."; + return false; } } } diff --git a/dexdump/Android.bp b/dexdump/Android.bp index f6b7a6b68a..eca08448bc 100644 --- a/dexdump/Android.bp +++ b/dexdump/Android.bp @@ -45,6 +45,7 @@ art_cc_binary { host_supported: true, device_supported: false, static_libs: [ + "libdexfile", "libbase", ] + art_static_dependencies, target: { diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp index 3ea7f4ba82..bea61d0c71 100644 --- a/dexlayout/Android.bp +++ b/dexlayout/Android.bp @@ -27,7 +27,6 @@ art_cc_defaults { ], export_include_dirs: ["."], shared_libs: [ - "libdexfile", "libbase", ], static_libs: ["libz"], @@ -36,7 +35,10 @@ art_cc_defaults { art_cc_library { name: "libart-dexlayout", defaults: ["libart-dexlayout-defaults"], - shared_libs: ["libart"], + shared_libs: [ + "libart", + "libdexfile", + ], pgo: { instrumentation: true, @@ -51,7 +53,10 @@ art_cc_library { "libart-dexlayout-defaults", "art_debug_defaults", ], - shared_libs: ["libartd"], + shared_libs: [ + "libartd", + "libdexfiled", + ], } cc_defaults { diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp new file mode 100644 index 0000000000..90c603f290 --- /dev/null +++ b/libdexfile/Android.bp @@ -0,0 +1,125 @@ +// +// 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: "libdexfile_defaults", + defaults: ["art_defaults"], + host_supported: true, + srcs: [ + "dex/compact_dex_debug_info.cc", + "dex/compact_dex_file.cc", + "dex/descriptors_names.cc", + "dex/dex_file.cc", + "dex/dex_file_exception_helpers.cc", + "dex/dex_file_loader.cc", + "dex/dex_file_tracking_registrar.cc", + "dex/dex_file_verifier.cc", + "dex/dex_instruction.cc", + "dex/modifiers.cc", + "dex/standard_dex_file.cc", + "dex/utf.cc", + ], + + target: { + android: { + static_libs: [ + "libziparchive", + "libz", + "libbase", + ], + shared_libs: [ + "libutils", + ], + }, + host: { + shared_libs: [ + "libziparchive", + "libz", + ], + }, + }, + generated_sources: ["dexfile_operator_srcs"], + shared_libs: [ + "liblog", + // For common macros. + "libbase", + "libz", + ], + header_libs: [ + // This is needed to resolve the base/ header file inclusions here. + // TODO: move those headers to art/ rather than under runtime. + "libart_runtime_headers", + ], + export_include_dirs: ["."], + export_shared_lib_headers: [ + "libbase", + ], +} + +gensrcs { + name: "dexfile_operator_srcs", + cmd: "$(location generate-operator-out.py) art/libdexfile $(in) > $(out)", + tool_files: ["generate-operator-out.py"], + srcs: [ + "dex/dex_file.h", + "dex/dex_instruction.h", + "dex/dex_instruction_utils.h", + "dex/invoke_type.h", + ], + output_extension: "operator_out.cc", +} + +// TODO: add build support for libdexfiled, as we use DCHECK, etc. +art_cc_library { + name: "libdexfile", + defaults: ["libdexfile_defaults"], + // Leave the symbols in the shared library so that stack unwinders can + // produce meaningful name resolution. + strip: { + keep_symbols: true, + }, +} + +art_cc_library { + name: "libdexfiled", + defaults: [ + "art_debug_defaults", + "libdexfile_defaults", + ], +} + +art_cc_test { + name: "art_libdexfile_tests", + defaults: [ + "art_gtest_defaults", + ], + srcs: [ + "dex/code_item_accessors_test.cc", + "dex/compact_dex_debug_info_test.cc", + "dex/compact_dex_file_test.cc", + "dex/dex_file_loader_test.cc", + "dex/dex_file_verifier_test.cc", + "dex/dex_instruction_test.cc", + "dex/utf_test.cc", + ], + shared_libs: [ + "libbacktrace", + "libziparchive", + ], + include_dirs: [ + "external/zlib", + ], +} diff --git a/runtime/dex/base64_test_util.h b/libdexfile/dex/base64_test_util.h index 0657f9fd01..683e429e11 100644 --- a/runtime/dex/base64_test_util.h +++ b/libdexfile/dex/base64_test_util.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_BASE64_TEST_UTIL_H_ -#define ART_RUNTIME_DEX_BASE64_TEST_UTIL_H_ +#ifndef ART_LIBDEXFILE_DEX_BASE64_TEST_UTIL_H_ +#define ART_LIBDEXFILE_DEX_BASE64_TEST_UTIL_H_ #include <base/logging.h> #include <stdint.h> @@ -96,4 +96,4 @@ static inline uint8_t* DecodeBase64(const char* src, size_t* dst_size) { } // namespace art -#endif // ART_RUNTIME_DEX_BASE64_TEST_UTIL_H_ +#endif // ART_LIBDEXFILE_DEX_BASE64_TEST_UTIL_H_ diff --git a/runtime/dex/code_item_accessors-inl.h b/libdexfile/dex/code_item_accessors-inl.h index 9c39935d3b..c166f5f19e 100644 --- a/runtime/dex/code_item_accessors-inl.h +++ b/libdexfile/dex/code_item_accessors-inl.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_INL_H_ -#define ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_INL_H_ +#ifndef ART_LIBDEXFILE_DEX_CODE_ITEM_ACCESSORS_INL_H_ +#define ART_LIBDEXFILE_DEX_CODE_ITEM_ACCESSORS_INL_H_ #include "code_item_accessors.h" @@ -201,4 +201,4 @@ inline bool CodeItemDebugInfoAccessor::DecodeDebugLocalInfo(bool is_static, } // namespace art -#endif // ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_INL_H_ +#endif // ART_LIBDEXFILE_DEX_CODE_ITEM_ACCESSORS_INL_H_ diff --git a/runtime/dex/code_item_accessors.h b/libdexfile/dex/code_item_accessors.h index beb78f6e4f..ba7c126ed8 100644 --- a/runtime/dex/code_item_accessors.h +++ b/libdexfile/dex/code_item_accessors.h @@ -16,10 +16,9 @@ // TODO: Dex helpers have ART specific APIs, we may want to refactor these for use in dexdump. -#ifndef ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_H_ -#define ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_H_ +#ifndef ART_LIBDEXFILE_DEX_CODE_ITEM_ACCESSORS_H_ +#define ART_LIBDEXFILE_DEX_CODE_ITEM_ACCESSORS_H_ -#include "base/mutex.h" #include "compact_dex_file.h" #include "dex_file.h" #include "dex_instruction_iterator.h" @@ -164,4 +163,4 @@ class CodeItemDebugInfoAccessor : public CodeItemDataAccessor { } // namespace art -#endif // ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_H_ +#endif // ART_LIBDEXFILE_DEX_CODE_ITEM_ACCESSORS_H_ diff --git a/runtime/dex/code_item_accessors_test.cc b/libdexfile/dex/code_item_accessors_test.cc index 2bb4dde649..2bb4dde649 100644 --- a/runtime/dex/code_item_accessors_test.cc +++ b/libdexfile/dex/code_item_accessors_test.cc diff --git a/runtime/dex/compact_dex_debug_info.cc b/libdexfile/dex/compact_dex_debug_info.cc index 19495ca92c..19495ca92c 100644 --- a/runtime/dex/compact_dex_debug_info.cc +++ b/libdexfile/dex/compact_dex_debug_info.cc diff --git a/runtime/dex/compact_dex_debug_info.h b/libdexfile/dex/compact_dex_debug_info.h index 1aff75879e..bfd0bbe65c 100644 --- a/runtime/dex/compact_dex_debug_info.h +++ b/libdexfile/dex/compact_dex_debug_info.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_COMPACT_DEX_DEBUG_INFO_H_ -#define ART_RUNTIME_DEX_COMPACT_DEX_DEBUG_INFO_H_ +#ifndef ART_LIBDEXFILE_DEX_COMPACT_DEX_DEBUG_INFO_H_ +#define ART_LIBDEXFILE_DEX_COMPACT_DEX_DEBUG_INFO_H_ #include <cstdint> #include <vector> @@ -62,4 +62,4 @@ class CompactDexDebugInfoOffsetTable { } // namespace art -#endif // ART_RUNTIME_DEX_COMPACT_DEX_DEBUG_INFO_H_ +#endif // ART_LIBDEXFILE_DEX_COMPACT_DEX_DEBUG_INFO_H_ diff --git a/runtime/dex/compact_dex_debug_info_test.cc b/libdexfile/dex/compact_dex_debug_info_test.cc index 3267612443..3267612443 100644 --- a/runtime/dex/compact_dex_debug_info_test.cc +++ b/libdexfile/dex/compact_dex_debug_info_test.cc diff --git a/runtime/dex/compact_dex_file.cc b/libdexfile/dex/compact_dex_file.cc index ce289d4d7b..ce289d4d7b 100644 --- a/runtime/dex/compact_dex_file.cc +++ b/libdexfile/dex/compact_dex_file.cc diff --git a/runtime/dex/compact_dex_file.h b/libdexfile/dex/compact_dex_file.h index 31aeb27872..47b170c4a8 100644 --- a/runtime/dex/compact_dex_file.h +++ b/libdexfile/dex/compact_dex_file.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_COMPACT_DEX_FILE_H_ -#define ART_RUNTIME_DEX_COMPACT_DEX_FILE_H_ +#ifndef ART_LIBDEXFILE_DEX_COMPACT_DEX_FILE_H_ +#define ART_LIBDEXFILE_DEX_COMPACT_DEX_FILE_H_ #include "base/casts.h" #include "dex_file.h" @@ -288,4 +288,4 @@ class CompactDexFile : public DexFile { } // namespace art -#endif // ART_RUNTIME_DEX_COMPACT_DEX_FILE_H_ +#endif // ART_LIBDEXFILE_DEX_COMPACT_DEX_FILE_H_ diff --git a/runtime/dex/compact_dex_file_test.cc b/libdexfile/dex/compact_dex_file_test.cc index 517c5873ed..517c5873ed 100644 --- a/runtime/dex/compact_dex_file_test.cc +++ b/libdexfile/dex/compact_dex_file_test.cc diff --git a/runtime/dex/compact_dex_level.h b/libdexfile/dex/compact_dex_level.h index de9ca3c783..2325ac2cae 100644 --- a/runtime/dex/compact_dex_level.h +++ b/libdexfile/dex/compact_dex_level.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_COMPACT_DEX_LEVEL_H_ -#define ART_RUNTIME_DEX_COMPACT_DEX_LEVEL_H_ +#ifndef ART_LIBDEXFILE_DEX_COMPACT_DEX_LEVEL_H_ +#define ART_LIBDEXFILE_DEX_COMPACT_DEX_LEVEL_H_ #include <string> @@ -47,4 +47,4 @@ static constexpr CompactDexLevel kDefaultCompactDexLevel = ART_DEFAULT_COMPACT_D } // namespace art -#endif // ART_RUNTIME_DEX_COMPACT_DEX_LEVEL_H_ +#endif // ART_LIBDEXFILE_DEX_COMPACT_DEX_LEVEL_H_ diff --git a/runtime/dex/compact_dex_utils.h b/libdexfile/dex/compact_dex_utils.h index 1c7e9514fd..c88b799e1f 100644 --- a/runtime/dex/compact_dex_utils.h +++ b/libdexfile/dex/compact_dex_utils.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_COMPACT_DEX_UTILS_H_ -#define ART_RUNTIME_DEX_COMPACT_DEX_UTILS_H_ +#ifndef ART_LIBDEXFILE_DEX_COMPACT_DEX_UTILS_H_ +#define ART_LIBDEXFILE_DEX_COMPACT_DEX_UTILS_H_ #include <vector> @@ -34,4 +34,4 @@ static inline void AlignmentPadVector(std::vector<T, Allocator<T>>* dest, } // namespace art -#endif // ART_RUNTIME_DEX_COMPACT_DEX_UTILS_H_ +#endif // ART_LIBDEXFILE_DEX_COMPACT_DEX_UTILS_H_ diff --git a/runtime/dex/descriptors_names.cc b/libdexfile/dex/descriptors_names.cc index 8124e7256f..8124e7256f 100644 --- a/runtime/dex/descriptors_names.cc +++ b/libdexfile/dex/descriptors_names.cc diff --git a/runtime/dex/descriptors_names.h b/libdexfile/dex/descriptors_names.h index 22e9573556..10738eead0 100644 --- a/runtime/dex/descriptors_names.h +++ b/libdexfile/dex/descriptors_names.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_DESCRIPTORS_NAMES_H_ -#define ART_RUNTIME_DEX_DESCRIPTORS_NAMES_H_ +#ifndef ART_LIBDEXFILE_DEX_DESCRIPTORS_NAMES_H_ +#define ART_LIBDEXFILE_DEX_DESCRIPTORS_NAMES_H_ #include <string> @@ -60,4 +60,4 @@ bool IsValidMemberName(const char* s); } // namespace art -#endif // ART_RUNTIME_DEX_DESCRIPTORS_NAMES_H_ +#endif // ART_LIBDEXFILE_DEX_DESCRIPTORS_NAMES_H_ diff --git a/runtime/dex/dex_file-inl.h b/libdexfile/dex/dex_file-inl.h index aa53daac35..b424b50f21 100644 --- a/runtime/dex/dex_file-inl.h +++ b/libdexfile/dex/dex_file-inl.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_DEX_FILE_INL_H_ -#define ART_RUNTIME_DEX_DEX_FILE_INL_H_ +#ifndef ART_LIBDEXFILE_DEX_DEX_FILE_INL_H_ +#define ART_LIBDEXFILE_DEX_DEX_FILE_INL_H_ #include "base/bit_utils.h" #include "base/casts.h" @@ -518,4 +518,4 @@ inline const uint8_t* DexFile::GetCatchHandlerData(const DexInstructionIterator& } // namespace art -#endif // ART_RUNTIME_DEX_DEX_FILE_INL_H_ +#endif // ART_LIBDEXFILE_DEX_DEX_FILE_INL_H_ diff --git a/runtime/dex/dex_file.cc b/libdexfile/dex/dex_file.cc index 18eb903551..18eb903551 100644 --- a/runtime/dex/dex_file.cc +++ b/libdexfile/dex/dex_file.cc diff --git a/runtime/dex/dex_file.h b/libdexfile/dex/dex_file.h index cf8c840b59..a38e76cfd0 100644 --- a/runtime/dex/dex_file.h +++ b/libdexfile/dex/dex_file.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_DEX_FILE_H_ -#define ART_RUNTIME_DEX_DEX_FILE_H_ +#ifndef ART_LIBDEXFILE_DEX_DEX_FILE_H_ +#define ART_LIBDEXFILE_DEX_DEX_FILE_H_ #include <memory> #include <string> @@ -1440,4 +1440,4 @@ std::ostream& operator<<(std::ostream& os, const CallSiteArrayValueIterator::Val } // namespace art -#endif // ART_RUNTIME_DEX_DEX_FILE_H_ +#endif // ART_LIBDEXFILE_DEX_DEX_FILE_H_ diff --git a/runtime/dex/dex_file_exception_helpers.cc b/libdexfile/dex/dex_file_exception_helpers.cc index 8e597fd3dd..8e597fd3dd 100644 --- a/runtime/dex/dex_file_exception_helpers.cc +++ b/libdexfile/dex/dex_file_exception_helpers.cc diff --git a/runtime/dex/dex_file_exception_helpers.h b/libdexfile/dex/dex_file_exception_helpers.h index bd6cb7e747..a05fd68e86 100644 --- a/runtime/dex/dex_file_exception_helpers.h +++ b/libdexfile/dex/dex_file_exception_helpers.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_DEX_FILE_EXCEPTION_HELPERS_H_ -#define ART_RUNTIME_DEX_DEX_FILE_EXCEPTION_HELPERS_H_ +#ifndef ART_LIBDEXFILE_DEX_DEX_FILE_EXCEPTION_HELPERS_H_ +#define ART_LIBDEXFILE_DEX_DEX_FILE_EXCEPTION_HELPERS_H_ #include "dex_file.h" @@ -65,4 +65,4 @@ class CatchHandlerIterator { } // namespace art -#endif // ART_RUNTIME_DEX_DEX_FILE_EXCEPTION_HELPERS_H_ +#endif // ART_LIBDEXFILE_DEX_DEX_FILE_EXCEPTION_HELPERS_H_ diff --git a/runtime/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc index 2c75c5b5d9..2c75c5b5d9 100644 --- a/runtime/dex/dex_file_loader.cc +++ b/libdexfile/dex/dex_file_loader.cc diff --git a/runtime/dex/dex_file_loader.h b/libdexfile/dex/dex_file_loader.h index 508397cb00..41d9b1691b 100644 --- a/runtime/dex/dex_file_loader.h +++ b/libdexfile/dex/dex_file_loader.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_DEX_FILE_LOADER_H_ -#define ART_RUNTIME_DEX_DEX_FILE_LOADER_H_ +#ifndef ART_LIBDEXFILE_DEX_DEX_FILE_LOADER_H_ +#define ART_LIBDEXFILE_DEX_DEX_FILE_LOADER_H_ #include <cstdint> #include <memory> @@ -195,4 +195,4 @@ class DexFileLoader { } // namespace art -#endif // ART_RUNTIME_DEX_DEX_FILE_LOADER_H_ +#endif // ART_LIBDEXFILE_DEX_DEX_FILE_LOADER_H_ diff --git a/runtime/dex/dex_file_test.cc b/libdexfile/dex/dex_file_loader_test.cc index 2bb86672dc..ab5c3f9a26 100644 --- a/runtime/dex/dex_file_test.cc +++ b/libdexfile/dex/dex_file_loader_test.cc @@ -16,33 +16,20 @@ #include "dex_file.h" -#include <sys/mman.h> - #include <memory> -#include "art_dex_file_loader.h" -#include "base/stl_util.h" -#include "base/unix_file/fd_file.h" #include "base64_test_util.h" #include "code_item_accessors-inl.h" -#include "common_runtime_test.h" #include "descriptors_names.h" #include "dex_file-inl.h" #include "dex_file_loader.h" -#include "mem_map.h" -#include "os.h" -#include "scoped_thread_state_change-inl.h" -#include "thread-current-inl.h" +#include "gtest/gtest.h" namespace art { -class DexFileTest : public CommonRuntimeTest {}; +class DexFileLoaderTest : public testing::Test {}; -TEST_F(DexFileTest, Open) { - ScopedObjectAccess soa(Thread::Current()); - std::unique_ptr<const DexFile> dex(OpenTestDexFile("Nested")); - ASSERT_TRUE(dex.get() != nullptr); -} +static constexpr char kLocationString[] = "/a/dex/file/location"; static inline std::vector<uint8_t> DecodeBase64Vec(const char* src) { std::vector<uint8_t> res; @@ -212,52 +199,41 @@ static const char kRawDexDebugInfoLocalNullType[] = "AAIAAAAEAAAAkAAAAAMAAAACAAAAoAAAAAUAAAADAAAAuAAAAAYAAAABAAAA0AAAAAEgAAACAAAA" "8AAAAAIgAAAIAAAAHAEAAAMgAAACAAAAVAEAAAAgAAABAAAAYwEAAAAQAAABAAAAdAEAAA=="; -static void DecodeAndWriteDexFile(const char* base64, const char* location) { +static void DecodeDexFile(const char* base64, std::vector<uint8_t>* dex_bytes) { // decode base64 CHECK(base64 != nullptr); - std::vector<uint8_t> dex_bytes = DecodeBase64Vec(base64); - CHECK_NE(dex_bytes.size(), 0u); - - // write to provided file - std::unique_ptr<File> file(OS::CreateEmptyFile(location)); - CHECK(file.get() != nullptr); - if (!file->WriteFully(dex_bytes.data(), dex_bytes.size())) { - PLOG(FATAL) << "Failed to write base64 as dex file"; - } - if (file->FlushCloseOrErase() != 0) { - PLOG(FATAL) << "Could not flush and close test file."; - } + *dex_bytes = DecodeBase64Vec(base64); + CHECK_NE(dex_bytes->size(), 0u); } static bool OpenDexFilesBase64(const char* base64, const char* location, + std::vector<uint8_t>* dex_bytes, std::vector<std::unique_ptr<const DexFile>>* dex_files, std::string* error_msg) { - DecodeAndWriteDexFile(base64, location); + DecodeDexFile(base64, dex_bytes); // read dex file(s) - ScopedObjectAccess soa(Thread::Current()); static constexpr bool kVerifyChecksum = true; std::vector<std::unique_ptr<const DexFile>> tmp; - const ArtDexFileLoader dex_file_loader; - bool success = dex_file_loader.Open( - location, location, /* verify */ true, kVerifyChecksum, error_msg, &tmp); - if (success) { - for (std::unique_ptr<const DexFile>& dex_file : tmp) { - EXPECT_EQ(PROT_READ, dex_file->GetPermissions()); - EXPECT_TRUE(dex_file->IsReadOnly()); - } - *dex_files = std::move(tmp); - } + const DexFileLoader dex_file_loader; + bool success = dex_file_loader.OpenAll(dex_bytes->data(), + dex_bytes->size(), + location, + /* verify */ true, + kVerifyChecksum, + error_msg, + dex_files); return success; } static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64, - const char* location) { + const char* location, + std::vector<uint8_t>* dex_bytes) { // read dex files. std::string error_msg; std::vector<std::unique_ptr<const DexFile>> dex_files; - bool success = OpenDexFilesBase64(base64, location, &dex_files, &error_msg); + bool success = OpenDexFilesBase64(base64, location, dex_bytes, &dex_files, &error_msg); CHECK(success) << error_msg; EXPECT_EQ(1U, dex_files.size()); return std::move(dex_files[0]); @@ -266,24 +242,17 @@ static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64, static std::unique_ptr<const DexFile> OpenDexFileInMemoryBase64(const char* base64, const char* location, uint32_t location_checksum, - bool expect_success) { - CHECK(base64 != nullptr); - std::vector<uint8_t> dex_bytes = DecodeBase64Vec(base64); - CHECK_NE(dex_bytes.size(), 0u); + bool expect_success, + std::vector<uint8_t>* dex_bytes) { + DecodeDexFile(base64, dex_bytes); std::string error_message; - std::unique_ptr<MemMap> region(MemMap::MapAnonymous("test-region", - nullptr, - dex_bytes.size(), - PROT_READ | PROT_WRITE, - /* low_4gb */ false, - /* reuse */ false, - &error_message)); - memcpy(region->Begin(), dex_bytes.data(), dex_bytes.size()); - const ArtDexFileLoader dex_file_loader; - std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open(location, + const DexFileLoader dex_file_loader; + std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open(dex_bytes->data(), + dex_bytes->size(), + location, location_checksum, - std::move(region), + /* oat_dex_file */ nullptr, /* verify */ true, /* verify_checksum */ true, &error_message)); @@ -332,323 +301,96 @@ static void ValidateDexFileHeader(std::unique_ptr<const DexFile> dex_file) { EXPECT_EQ(header.checksum_, dex_file->GetLocationChecksum()); } -TEST_F(DexFileTest, Header) { - ScratchFile tmp; - std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex, tmp.GetFilename().c_str())); +TEST_F(DexFileLoaderTest, Header) { + std::vector<uint8_t> dex_bytes; + std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex, kLocationString, &dex_bytes)); ValidateDexFileHeader(std::move(raw)); } -TEST_F(DexFileTest, HeaderInMemory) { - ScratchFile tmp; +TEST_F(DexFileLoaderTest, HeaderInMemory) { + std::vector<uint8_t> dex_bytes; std::unique_ptr<const DexFile> raw = - OpenDexFileInMemoryBase64(kRawDex, tmp.GetFilename().c_str(), 0x00d87910U, true); + OpenDexFileInMemoryBase64(kRawDex, kLocationString, 0x00d87910U, true, &dex_bytes); ValidateDexFileHeader(std::move(raw)); } -TEST_F(DexFileTest, Version38Accepted) { - ScratchFile tmp; - std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex38, tmp.GetFilename().c_str())); +TEST_F(DexFileLoaderTest, Version38Accepted) { + std::vector<uint8_t> dex_bytes; + std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex38, kLocationString, &dex_bytes)); ASSERT_TRUE(raw.get() != nullptr); const DexFile::Header& header = raw->GetHeader(); EXPECT_EQ(38u, header.GetVersion()); } -TEST_F(DexFileTest, Version39Accepted) { - ScratchFile tmp; - std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex39, tmp.GetFilename().c_str())); +TEST_F(DexFileLoaderTest, Version39Accepted) { + std::vector<uint8_t> dex_bytes; + std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex39, kLocationString, &dex_bytes)); ASSERT_TRUE(raw.get() != nullptr); const DexFile::Header& header = raw->GetHeader(); EXPECT_EQ(39u, header.GetVersion()); } -TEST_F(DexFileTest, Version40Rejected) { - ScratchFile tmp; - const char* location = tmp.GetFilename().c_str(); - DecodeAndWriteDexFile(kRawDex40, location); +TEST_F(DexFileLoaderTest, Version40Rejected) { + std::vector<uint8_t> dex_bytes; + DecodeDexFile(kRawDex40, &dex_bytes); - ScopedObjectAccess soa(Thread::Current()); static constexpr bool kVerifyChecksum = true; std::string error_msg; std::vector<std::unique_ptr<const DexFile>> dex_files; - const ArtDexFileLoader dex_file_loader; - ASSERT_FALSE(dex_file_loader.Open( - location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)); + const DexFileLoader dex_file_loader; + ASSERT_FALSE(dex_file_loader.OpenAll(dex_bytes.data(), + dex_bytes.size(), + kLocationString, + /* verify */ true, + kVerifyChecksum, + &error_msg, + &dex_files)); } -TEST_F(DexFileTest, Version41Rejected) { - ScratchFile tmp; - const char* location = tmp.GetFilename().c_str(); - DecodeAndWriteDexFile(kRawDex41, location); +TEST_F(DexFileLoaderTest, Version41Rejected) { + std::vector<uint8_t> dex_bytes; + DecodeDexFile(kRawDex41, &dex_bytes); - ScopedObjectAccess soa(Thread::Current()); static constexpr bool kVerifyChecksum = true; std::string error_msg; std::vector<std::unique_ptr<const DexFile>> dex_files; - const ArtDexFileLoader dex_file_loader; - ASSERT_FALSE(dex_file_loader.Open( - location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)); + const DexFileLoader dex_file_loader; + ASSERT_FALSE(dex_file_loader.OpenAll(dex_bytes.data(), + dex_bytes.size(), + kLocationString, + /* verify */ true, + kVerifyChecksum, + &error_msg, + &dex_files)); } -TEST_F(DexFileTest, ZeroLengthDexRejected) { - ScratchFile tmp; - const char* location = tmp.GetFilename().c_str(); - DecodeAndWriteDexFile(kRawDexZeroLength, location); +TEST_F(DexFileLoaderTest, ZeroLengthDexRejected) { + std::vector<uint8_t> dex_bytes; + DecodeDexFile(kRawDexZeroLength, &dex_bytes); - ScopedObjectAccess soa(Thread::Current()); static constexpr bool kVerifyChecksum = true; std::string error_msg; std::vector<std::unique_ptr<const DexFile>> dex_files; - const ArtDexFileLoader dex_file_loader; - ASSERT_FALSE(dex_file_loader.Open( - location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)); -} - -TEST_F(DexFileTest, GetLocationChecksum) { - ScopedObjectAccess soa(Thread::Current()); - std::unique_ptr<const DexFile> raw(OpenTestDexFile("Main")); - EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum()); -} - -TEST_F(DexFileTest, GetChecksum) { - std::vector<uint32_t> checksums; - ScopedObjectAccess soa(Thread::Current()); - std::string error_msg; - const ArtDexFileLoader dex_file_loader; - EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(), - &checksums, - &error_msg)) - << error_msg; - ASSERT_EQ(1U, checksums.size()); - EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksums[0]); -} - -TEST_F(DexFileTest, GetMultiDexChecksums) { - std::string error_msg; - std::vector<uint32_t> checksums; - std::string multidex_file = GetTestDexFileName("MultiDex"); - const ArtDexFileLoader dex_file_loader; - EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(multidex_file.c_str(), - &checksums, - &error_msg)) << error_msg; - - std::vector<std::unique_ptr<const DexFile>> dexes = OpenTestDexFiles("MultiDex"); - ASSERT_EQ(2U, dexes.size()); - ASSERT_EQ(2U, checksums.size()); - - EXPECT_EQ(dexes[0]->GetLocation(), DexFileLoader::GetMultiDexLocation(0, multidex_file.c_str())); - EXPECT_EQ(dexes[0]->GetLocationChecksum(), checksums[0]); - - EXPECT_EQ(dexes[1]->GetLocation(), DexFileLoader::GetMultiDexLocation(1, multidex_file.c_str())); - EXPECT_EQ(dexes[1]->GetLocationChecksum(), checksums[1]); -} - -TEST_F(DexFileTest, ClassDefs) { - ScopedObjectAccess soa(Thread::Current()); - std::unique_ptr<const DexFile> raw(OpenTestDexFile("Nested")); - ASSERT_TRUE(raw.get() != nullptr); - EXPECT_EQ(3U, raw->NumClassDefs()); - - const DexFile::ClassDef& c0 = raw->GetClassDef(0); - EXPECT_STREQ("LNested$1;", raw->GetClassDescriptor(c0)); - - const DexFile::ClassDef& c1 = raw->GetClassDef(1); - EXPECT_STREQ("LNested$Inner;", raw->GetClassDescriptor(c1)); - - const DexFile::ClassDef& c2 = raw->GetClassDef(2); - EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c2)); -} - -TEST_F(DexFileTest, GetMethodSignature) { - ScopedObjectAccess soa(Thread::Current()); - std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature")); - ASSERT_TRUE(raw.get() != nullptr); - EXPECT_EQ(1U, raw->NumClassDefs()); - - const DexFile::ClassDef& class_def = raw->GetClassDef(0); - ASSERT_STREQ("LGetMethodSignature;", raw->GetClassDescriptor(class_def)); - - const uint8_t* class_data = raw->GetClassData(class_def); - ASSERT_TRUE(class_data != nullptr); - ClassDataItemIterator it(*raw, class_data); - - EXPECT_EQ(1u, it.NumDirectMethods()); - - // Check the signature for the static initializer. - { - ASSERT_EQ(1U, it.NumDirectMethods()); - const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex()); - const char* name = raw->StringDataByIdx(method_id.name_idx_); - ASSERT_STREQ("<init>", name); - std::string signature(raw->GetMethodSignature(method_id).ToString()); - ASSERT_EQ("()V", signature); - } - - // Check all virtual methods. - struct Result { - const char* name; - const char* signature; - const char* pretty_method; - }; - static const Result results[] = { - { - "m1", - "(IDJLjava/lang/Object;)Ljava/lang/Float;", - "java.lang.Float GetMethodSignature.m1(int, double, long, java.lang.Object)" - }, - { - "m2", - "(ZSC)LGetMethodSignature;", - "GetMethodSignature GetMethodSignature.m2(boolean, short, char)" - }, - { - "m3", - "()V", - "void GetMethodSignature.m3()" - }, - { - "m4", - "(I)V", - "void GetMethodSignature.m4(int)" - }, - { - "m5", - "(II)V", - "void GetMethodSignature.m5(int, int)" - }, - { - "m6", - "(II[[I)V", - "void GetMethodSignature.m6(int, int, int[][])" - }, - { - "m7", - "(II[[ILjava/lang/Object;)V", - "void GetMethodSignature.m7(int, int, int[][], java.lang.Object)" - }, - { - "m8", - "(II[[ILjava/lang/Object;[[Ljava/lang/Object;)V", - "void GetMethodSignature.m8(int, int, int[][], java.lang.Object, java.lang.Object[][])" - }, - { - "m9", - "()I", - "int GetMethodSignature.m9()" - }, - { - "mA", - "()[[I", - "int[][] GetMethodSignature.mA()" - }, - { - "mB", - "()[[Ljava/lang/Object;", - "java.lang.Object[][] GetMethodSignature.mB()" - }, - }; - ASSERT_EQ(arraysize(results), it.NumVirtualMethods()); - for (const Result& r : results) { - it.Next(); - const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex()); - - const char* name = raw->StringDataByIdx(method_id.name_idx_); - ASSERT_STREQ(r.name, name); - - std::string signature(raw->GetMethodSignature(method_id).ToString()); - ASSERT_EQ(r.signature, signature); - - std::string plain_method = std::string("GetMethodSignature.") + r.name; - ASSERT_EQ(plain_method, raw->PrettyMethod(it.GetMemberIndex(), /* with_signature */ false)); - ASSERT_EQ(r.pretty_method, raw->PrettyMethod(it.GetMemberIndex(), /* with_signature */ true)); - } -} - -TEST_F(DexFileTest, FindStringId) { - ScopedObjectAccess soa(Thread::Current()); - std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature")); - ASSERT_TRUE(raw.get() != nullptr); - EXPECT_EQ(1U, raw->NumClassDefs()); - - const char* strings[] = { "LGetMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;", - "D", "I", "J", nullptr }; - for (size_t i = 0; strings[i] != nullptr; i++) { - const char* str = strings[i]; - const DexFile::StringId* str_id = raw->FindStringId(str); - const char* dex_str = raw->GetStringData(*str_id); - EXPECT_STREQ(dex_str, str); - } -} - -TEST_F(DexFileTest, FindTypeId) { - for (size_t i = 0; i < java_lang_dex_file_->NumTypeIds(); i++) { - const char* type_str = java_lang_dex_file_->StringByTypeIdx(dex::TypeIndex(i)); - const DexFile::StringId* type_str_id = java_lang_dex_file_->FindStringId(type_str); - ASSERT_TRUE(type_str_id != nullptr); - dex::StringIndex type_str_idx = java_lang_dex_file_->GetIndexForStringId(*type_str_id); - const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId(type_str_idx); - ASSERT_EQ(type_id, java_lang_dex_file_->FindTypeId(type_str)); - ASSERT_TRUE(type_id != nullptr); - EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id).index_, i); - } -} - -TEST_F(DexFileTest, FindProtoId) { - for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) { - const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i); - const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find); - std::vector<dex::TypeIndex> to_find_types; - if (to_find_tl != nullptr) { - for (size_t j = 0; j < to_find_tl->Size(); j++) { - to_find_types.push_back(to_find_tl->GetTypeItem(j).type_idx_); - } - } - const DexFile::ProtoId* found = - java_lang_dex_file_->FindProtoId(to_find.return_type_idx_, to_find_types); - ASSERT_TRUE(found != nullptr); - EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), i); - } -} - -TEST_F(DexFileTest, FindMethodId) { - for (size_t i = 0; i < java_lang_dex_file_->NumMethodIds(); i++) { - const DexFile::MethodId& to_find = java_lang_dex_file_->GetMethodId(i); - const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_); - const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_); - const DexFile::ProtoId& signature = java_lang_dex_file_->GetProtoId(to_find.proto_idx_); - const DexFile::MethodId* found = java_lang_dex_file_->FindMethodId(klass, name, signature); - ASSERT_TRUE(found != nullptr) << "Didn't find method " << i << ": " - << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "." - << java_lang_dex_file_->GetStringData(name) - << java_lang_dex_file_->GetMethodSignature(to_find); - EXPECT_EQ(java_lang_dex_file_->GetIndexForMethodId(*found), i); - } -} - -TEST_F(DexFileTest, FindFieldId) { - for (size_t i = 0; i < java_lang_dex_file_->NumFieldIds(); i++) { - const DexFile::FieldId& to_find = java_lang_dex_file_->GetFieldId(i); - const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_); - const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_); - const DexFile::TypeId& type = java_lang_dex_file_->GetTypeId(to_find.type_idx_); - const DexFile::FieldId* found = java_lang_dex_file_->FindFieldId(klass, name, type); - ASSERT_TRUE(found != nullptr) << "Didn't find field " << i << ": " - << java_lang_dex_file_->StringByTypeIdx(to_find.type_idx_) << " " - << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "." - << java_lang_dex_file_->GetStringData(name); - EXPECT_EQ(java_lang_dex_file_->GetIndexForFieldId(*found), i); - } + const DexFileLoader dex_file_loader; + ASSERT_FALSE(dex_file_loader.OpenAll(dex_bytes.data(), + dex_bytes.size(), + kLocationString, + /* verify */ true, + kVerifyChecksum, + &error_msg, + &dex_files)); } -TEST_F(DexFileTest, GetMultiDexClassesDexName) { +TEST_F(DexFileLoaderTest, GetMultiDexClassesDexName) { ASSERT_EQ("classes.dex", DexFileLoader::GetMultiDexClassesDexName(0)); ASSERT_EQ("classes2.dex", DexFileLoader::GetMultiDexClassesDexName(1)); ASSERT_EQ("classes3.dex", DexFileLoader::GetMultiDexClassesDexName(2)); ASSERT_EQ("classes100.dex", DexFileLoader::GetMultiDexClassesDexName(99)); } -TEST_F(DexFileTest, GetMultiDexLocation) { +TEST_F(DexFileLoaderTest, GetMultiDexLocation) { std::string dex_location_str = "/system/app/framework.jar"; const char* dex_location = dex_location_str.c_str(); ASSERT_EQ("/system/app/framework.jar", DexFileLoader::GetMultiDexLocation(0, dex_location)); @@ -658,28 +400,6 @@ TEST_F(DexFileTest, GetMultiDexLocation) { DexFileLoader::GetMultiDexLocation(100, dex_location)); } -TEST_F(DexFileTest, GetDexCanonicalLocation) { - ScratchFile file; - UniqueCPtr<const char[]> dex_location_real(realpath(file.GetFilename().c_str(), nullptr)); - std::string dex_location(dex_location_real.get()); - - ASSERT_EQ(dex_location, DexFileLoader::GetDexCanonicalLocation(dex_location.c_str())); - std::string multidex_location = DexFileLoader::GetMultiDexLocation(1, dex_location.c_str()); - ASSERT_EQ(multidex_location, DexFileLoader::GetDexCanonicalLocation(multidex_location.c_str())); - - std::string dex_location_sym = dex_location + "symlink"; - ASSERT_EQ(0, symlink(dex_location.c_str(), dex_location_sym.c_str())); - - ASSERT_EQ(dex_location, DexFileLoader::GetDexCanonicalLocation(dex_location_sym.c_str())); - - std::string multidex_location_sym = DexFileLoader::GetMultiDexLocation( - 1, dex_location_sym.c_str()); - ASSERT_EQ(multidex_location, - DexFileLoader::GetDexCanonicalLocation(multidex_location_sym.c_str())); - - ASSERT_EQ(0, unlink(dex_location_sym.c_str())); -} - TEST(DexFileUtilsTest, GetBaseLocationAndMultiDexSuffix) { EXPECT_EQ("/foo/bar/baz.jar", DexFileLoader::GetBaseLocation("/foo/bar/baz.jar")); EXPECT_EQ("/foo/bar/baz.jar", DexFileLoader::GetBaseLocation("/foo/bar/baz.jar!classes2.dex")); @@ -689,43 +409,56 @@ TEST(DexFileUtilsTest, GetBaseLocationAndMultiDexSuffix) { EXPECT_EQ("!classes8.dex", DexFileLoader::GetMultiDexSuffix("/foo/bar/baz.jar!classes8.dex")); } -TEST_F(DexFileTest, ZipOpenClassesPresent) { - ScratchFile tmp; +TEST_F(DexFileLoaderTest, ZipOpenClassesPresent) { + std::vector<uint8_t> dex_bytes; std::vector<std::unique_ptr<const DexFile>> dex_files; std::string error_msg; - ASSERT_TRUE(OpenDexFilesBase64(kRawZipClassesDexPresent, tmp.GetFilename().c_str(), &dex_files, + ASSERT_TRUE(OpenDexFilesBase64(kRawZipClassesDexPresent, + kLocationString, + &dex_bytes, + &dex_files, &error_msg)); EXPECT_EQ(dex_files.size(), 1u); } -TEST_F(DexFileTest, ZipOpenClassesAbsent) { - ScratchFile tmp; +TEST_F(DexFileLoaderTest, ZipOpenClassesAbsent) { + std::vector<uint8_t> dex_bytes; std::vector<std::unique_ptr<const DexFile>> dex_files; std::string error_msg; - ASSERT_FALSE(OpenDexFilesBase64(kRawZipClassesDexAbsent, tmp.GetFilename().c_str(), &dex_files, + ASSERT_FALSE(OpenDexFilesBase64(kRawZipClassesDexAbsent, + kLocationString, + &dex_bytes, + &dex_files, &error_msg)); EXPECT_EQ(dex_files.size(), 0u); } -TEST_F(DexFileTest, ZipOpenThreeDexFiles) { - ScratchFile tmp; +TEST_F(DexFileLoaderTest, ZipOpenThreeDexFiles) { + std::vector<uint8_t> dex_bytes; std::vector<std::unique_ptr<const DexFile>> dex_files; std::string error_msg; - ASSERT_TRUE(OpenDexFilesBase64(kRawZipThreeDexFiles, tmp.GetFilename().c_str(), &dex_files, + ASSERT_TRUE(OpenDexFilesBase64(kRawZipThreeDexFiles, + kLocationString, + &dex_bytes, + &dex_files, &error_msg)); EXPECT_EQ(dex_files.size(), 3u); } -TEST_F(DexFileTest, OpenDexBadMapOffset) { - ScratchFile tmp; +TEST_F(DexFileLoaderTest, OpenDexBadMapOffset) { + std::vector<uint8_t> dex_bytes; std::unique_ptr<const DexFile> raw = - OpenDexFileInMemoryBase64(kRawDexBadMapOffset, tmp.GetFilename().c_str(), 0xb3642819U, false); + OpenDexFileInMemoryBase64(kRawDexBadMapOffset, + kLocationString, + 0xb3642819U, + false, + &dex_bytes); EXPECT_EQ(raw, nullptr); } -TEST_F(DexFileTest, GetStringWithNoIndex) { - ScratchFile tmp; - std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex, tmp.GetFilename().c_str())); +TEST_F(DexFileLoaderTest, GetStringWithNoIndex) { + std::vector<uint8_t> dex_bytes; + std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex, kLocationString, &dex_bytes)); dex::TypeIndex idx; EXPECT_EQ(raw->StringByTypeIdx(idx), nullptr); } @@ -734,10 +467,13 @@ static void Callback(void* context ATTRIBUTE_UNUSED, const DexFile::LocalInfo& entry ATTRIBUTE_UNUSED) { } -TEST_F(DexFileTest, OpenDexDebugInfoLocalNullType) { - ScratchFile tmp; - std::unique_ptr<const DexFile> raw = OpenDexFileInMemoryBase64( - kRawDexDebugInfoLocalNullType, tmp.GetFilename().c_str(), 0xf25f2b38U, true); +TEST_F(DexFileLoaderTest, OpenDexDebugInfoLocalNullType) { + std::vector<uint8_t> dex_bytes; + std::unique_ptr<const DexFile> raw = OpenDexFileInMemoryBase64(kRawDexDebugInfoLocalNullType, + kLocationString, + 0xf25f2b38U, + true, + &dex_bytes); const DexFile::ClassDef& class_def = raw->GetClassDef(0); constexpr uint32_t kMethodIdx = 1; const DexFile::CodeItem* code_item = raw->GetCodeItem(raw->FindCodeItemOffset(class_def, diff --git a/runtime/dex/dex_file_reference.h b/libdexfile/dex/dex_file_reference.h index 6f882900c6..3ac778121a 100644 --- a/runtime/dex/dex_file_reference.h +++ b/libdexfile/dex/dex_file_reference.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_DEX_FILE_REFERENCE_H_ -#define ART_RUNTIME_DEX_DEX_FILE_REFERENCE_H_ +#ifndef ART_LIBDEXFILE_DEX_DEX_FILE_REFERENCE_H_ +#define ART_LIBDEXFILE_DEX_DEX_FILE_REFERENCE_H_ #include <cstdint> @@ -49,4 +49,4 @@ inline bool operator==(const DexFileReference& a, const DexFileReference& b) { } // namespace art -#endif // ART_RUNTIME_DEX_DEX_FILE_REFERENCE_H_ +#endif // ART_LIBDEXFILE_DEX_DEX_FILE_REFERENCE_H_ diff --git a/runtime/dex/dex_file_tracking_registrar.cc b/libdexfile/dex/dex_file_tracking_registrar.cc index 78ea9c16cb..78ea9c16cb 100644 --- a/runtime/dex/dex_file_tracking_registrar.cc +++ b/libdexfile/dex/dex_file_tracking_registrar.cc diff --git a/runtime/dex/dex_file_tracking_registrar.h b/libdexfile/dex/dex_file_tracking_registrar.h index 71b8ed7bde..8b7716e729 100644 --- a/runtime/dex/dex_file_tracking_registrar.h +++ b/libdexfile/dex/dex_file_tracking_registrar.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_DEX_FILE_TRACKING_REGISTRAR_H_ -#define ART_RUNTIME_DEX_DEX_FILE_TRACKING_REGISTRAR_H_ +#ifndef ART_LIBDEXFILE_DEX_DEX_FILE_TRACKING_REGISTRAR_H_ +#define ART_LIBDEXFILE_DEX_DEX_FILE_TRACKING_REGISTRAR_H_ #include <deque> #include <tuple> @@ -78,4 +78,4 @@ void RegisterDexFile(const DexFile* dex_file); } // namespace dex } // namespace art -#endif // ART_RUNTIME_DEX_DEX_FILE_TRACKING_REGISTRAR_H_ +#endif // ART_LIBDEXFILE_DEX_DEX_FILE_TRACKING_REGISTRAR_H_ diff --git a/runtime/dex/dex_file_types.h b/libdexfile/dex/dex_file_types.h index 2c508f9c99..2bb70ff261 100644 --- a/runtime/dex/dex_file_types.h +++ b/libdexfile/dex/dex_file_types.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_DEX_FILE_TYPES_H_ -#define ART_RUNTIME_DEX_DEX_FILE_TYPES_H_ +#ifndef ART_LIBDEXFILE_DEX_DEX_FILE_TYPES_H_ +#define ART_LIBDEXFILE_DEX_DEX_FILE_TYPES_H_ #include <limits> #include <ostream> @@ -114,4 +114,4 @@ template<> struct hash<art::dex::TypeIndex> { } // namespace std -#endif // ART_RUNTIME_DEX_DEX_FILE_TYPES_H_ +#endif // ART_LIBDEXFILE_DEX_DEX_FILE_TYPES_H_ diff --git a/runtime/dex/dex_file_verifier.cc b/libdexfile/dex/dex_file_verifier.cc index 62667052ad..62667052ad 100644 --- a/runtime/dex/dex_file_verifier.cc +++ b/libdexfile/dex/dex_file_verifier.cc diff --git a/runtime/dex/dex_file_verifier.h b/libdexfile/dex/dex_file_verifier.h index 6cb5d4c629..c4982c24c9 100644 --- a/runtime/dex/dex_file_verifier.h +++ b/libdexfile/dex/dex_file_verifier.h @@ -14,12 +14,11 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_DEX_FILE_VERIFIER_H_ -#define ART_RUNTIME_DEX_DEX_FILE_VERIFIER_H_ +#ifndef ART_LIBDEXFILE_DEX_DEX_FILE_VERIFIER_H_ +#define ART_LIBDEXFILE_DEX_DEX_FILE_VERIFIER_H_ #include <unordered_set> -#include "base/allocator.h" #include "base/hash_map.h" #include "dex_file.h" #include "dex_file_types.h" @@ -254,4 +253,4 @@ class DexFileVerifier { } // namespace art -#endif // ART_RUNTIME_DEX_DEX_FILE_VERIFIER_H_ +#endif // ART_LIBDEXFILE_DEX_DEX_FILE_VERIFIER_H_ diff --git a/runtime/dex/dex_file_verifier_test.cc b/libdexfile/dex/dex_file_verifier_test.cc index 1cd4b2c07b..1cd4b2c07b 100644 --- a/runtime/dex/dex_file_verifier_test.cc +++ b/libdexfile/dex/dex_file_verifier_test.cc diff --git a/runtime/dex/dex_instruction-inl.h b/libdexfile/dex/dex_instruction-inl.h index a6b8414e62..6bef18c85f 100644 --- a/runtime/dex/dex_instruction-inl.h +++ b/libdexfile/dex/dex_instruction-inl.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_DEX_INSTRUCTION_INL_H_ -#define ART_RUNTIME_DEX_DEX_INSTRUCTION_INL_H_ +#ifndef ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_INL_H_ +#define ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_INL_H_ #include "dex_instruction.h" @@ -555,4 +555,4 @@ inline void Instruction::GetVarArgs(uint32_t arg[kMaxVarArgRegs], uint16_t inst_ } // namespace art -#endif // ART_RUNTIME_DEX_DEX_INSTRUCTION_INL_H_ +#endif // ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_INL_H_ diff --git a/runtime/dex/dex_instruction.cc b/libdexfile/dex/dex_instruction.cc index b84791ffae..886218129e 100644 --- a/runtime/dex/dex_instruction.cc +++ b/libdexfile/dex/dex_instruction.cc @@ -558,4 +558,11 @@ uint32_t VarArgsInstructionOperands::GetOperand(size_t operand_index) const { return operands_[operand_index]; } +uint32_t NoReceiverInstructionOperands::GetOperand(size_t operand_index) const { + DCHECK_LT(GetNumberOfOperands(), inner_->GetNumberOfOperands()); + // The receiver is the first operand and since we're skipping it, we need to + // add 1 to the operand_index. + return inner_->GetOperand(operand_index + 1); +} + } // namespace art diff --git a/runtime/dex/dex_instruction.h b/libdexfile/dex/dex_instruction.h index 8b1a5ce670..c9533656d3 100644 --- a/runtime/dex/dex_instruction.h +++ b/libdexfile/dex/dex_instruction.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_DEX_INSTRUCTION_H_ -#define ART_RUNTIME_DEX_DEX_INSTRUCTION_H_ +#ifndef ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_H_ +#define ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_H_ #include <android-base/logging.h> @@ -701,7 +701,7 @@ class InstructionOperands { size_t GetNumberOfOperands() const { return num_operands_; } private: - size_t num_operands_; + const size_t num_operands_; DISALLOW_IMPLICIT_CONSTRUCTORS(InstructionOperands); }; @@ -737,6 +737,21 @@ class VarArgsInstructionOperands FINAL : public InstructionOperands { DISALLOW_IMPLICIT_CONSTRUCTORS(VarArgsInstructionOperands); }; +// Class for accessing operands without the receiver by wrapping an +// existing InstructionOperands instance. +class NoReceiverInstructionOperands FINAL : public InstructionOperands { + public: + explicit NoReceiverInstructionOperands(InstructionOperands* inner) + : InstructionOperands(inner->GetNumberOfOperands() - 1), inner_(inner) {} + ~NoReceiverInstructionOperands() {} + uint32_t GetOperand(size_t operand_index) const OVERRIDE; + + private: + const InstructionOperands* const inner_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(NoReceiverInstructionOperands); +}; + } // namespace art -#endif // ART_RUNTIME_DEX_DEX_INSTRUCTION_H_ +#endif // ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_H_ diff --git a/runtime/dex/dex_instruction_iterator.h b/libdexfile/dex/dex_instruction_iterator.h index c1b3118f85..db3ff95e02 100644 --- a/runtime/dex/dex_instruction_iterator.h +++ b/libdexfile/dex/dex_instruction_iterator.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_DEX_INSTRUCTION_ITERATOR_H_ -#define ART_RUNTIME_DEX_DEX_INSTRUCTION_ITERATOR_H_ +#ifndef ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_ITERATOR_H_ +#define ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_ITERATOR_H_ #include <iterator> @@ -234,4 +234,4 @@ class SafeDexInstructionIterator : public DexInstructionIteratorBase { } // namespace art -#endif // ART_RUNTIME_DEX_DEX_INSTRUCTION_ITERATOR_H_ +#endif // ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_ITERATOR_H_ diff --git a/runtime/dex/dex_instruction_list.h b/libdexfile/dex/dex_instruction_list.h index aa63fadb66..9f0aba421a 100644 --- a/runtime/dex/dex_instruction_list.h +++ b/libdexfile/dex/dex_instruction_list.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_DEX_INSTRUCTION_LIST_H_ -#define ART_RUNTIME_DEX_DEX_INSTRUCTION_LIST_H_ +#ifndef ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_LIST_H_ +#define ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_LIST_H_ // V(opcode, instruction_code, name, format, index, flags, extended_flags, verifier_flags); #define DEX_INSTRUCTION_LIST(V) \ @@ -304,5 +304,5 @@ V(k4rcc) \ V(k51l) -#endif // ART_RUNTIME_DEX_DEX_INSTRUCTION_LIST_H_ -#undef ART_RUNTIME_DEX_DEX_INSTRUCTION_LIST_H_ // the guard in this file is just for cpplint +#endif // ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_LIST_H_ +#undef ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_LIST_H_ // the guard in this file is just for cpplint diff --git a/runtime/dex/dex_instruction_test.cc b/libdexfile/dex/dex_instruction_test.cc index c944085b9e..c944085b9e 100644 --- a/runtime/dex/dex_instruction_test.cc +++ b/libdexfile/dex/dex_instruction_test.cc diff --git a/runtime/dex/dex_instruction_utils.h b/libdexfile/dex/dex_instruction_utils.h index 27501927e7..e7614ada31 100644 --- a/runtime/dex/dex_instruction_utils.h +++ b/libdexfile/dex/dex_instruction_utils.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_DEX_INSTRUCTION_UTILS_H_ -#define ART_RUNTIME_DEX_DEX_INSTRUCTION_UTILS_H_ +#ifndef ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_UTILS_H_ +#define ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_UTILS_H_ #include "dex_instruction.h" @@ -216,4 +216,4 @@ constexpr DexMemAccessType AGetOrAPutMemAccessType(Instruction::Code code) { } // namespace art -#endif // ART_RUNTIME_DEX_DEX_INSTRUCTION_UTILS_H_ +#endif // ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_UTILS_H_ diff --git a/runtime/dex/invoke_type.h b/libdexfile/dex/invoke_type.h index 726d269a3e..9b3af673a8 100644 --- a/runtime/dex/invoke_type.h +++ b/libdexfile/dex/invoke_type.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_INVOKE_TYPE_H_ -#define ART_RUNTIME_DEX_INVOKE_TYPE_H_ +#ifndef ART_LIBDEXFILE_DEX_INVOKE_TYPE_H_ +#define ART_LIBDEXFILE_DEX_INVOKE_TYPE_H_ #include <iosfwd> @@ -35,4 +35,4 @@ std::ostream& operator<<(std::ostream& os, const InvokeType& rhs); } // namespace art -#endif // ART_RUNTIME_DEX_INVOKE_TYPE_H_ +#endif // ART_LIBDEXFILE_DEX_INVOKE_TYPE_H_ diff --git a/runtime/dex/modifiers.cc b/libdexfile/dex/modifiers.cc index 30daefb172..30daefb172 100644 --- a/runtime/dex/modifiers.cc +++ b/libdexfile/dex/modifiers.cc diff --git a/runtime/dex/modifiers.h b/libdexfile/dex/modifiers.h index 2998f602d4..2425a588df 100644 --- a/runtime/dex/modifiers.h +++ b/libdexfile/dex/modifiers.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_MODIFIERS_H_ -#define ART_RUNTIME_DEX_MODIFIERS_H_ +#ifndef ART_LIBDEXFILE_DEX_MODIFIERS_H_ +#define ART_LIBDEXFILE_DEX_MODIFIERS_H_ #include <stdint.h> @@ -144,5 +144,5 @@ std::string PrettyJavaAccessFlags(uint32_t access_flags); } // namespace art -#endif // ART_RUNTIME_DEX_MODIFIERS_H_ +#endif // ART_LIBDEXFILE_DEX_MODIFIERS_H_ diff --git a/runtime/dex/standard_dex_file.cc b/libdexfile/dex/standard_dex_file.cc index f7317eb997..f7317eb997 100644 --- a/runtime/dex/standard_dex_file.cc +++ b/libdexfile/dex/standard_dex_file.cc diff --git a/runtime/dex/standard_dex_file.h b/libdexfile/dex/standard_dex_file.h index e0e9f2f11c..9b13caa2be 100644 --- a/runtime/dex/standard_dex_file.h +++ b/libdexfile/dex/standard_dex_file.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_STANDARD_DEX_FILE_H_ -#define ART_RUNTIME_DEX_STANDARD_DEX_FILE_H_ +#ifndef ART_LIBDEXFILE_DEX_STANDARD_DEX_FILE_H_ +#define ART_LIBDEXFILE_DEX_STANDARD_DEX_FILE_H_ #include <iosfwd> @@ -115,4 +115,4 @@ class StandardDexFile : public DexFile { } // namespace art -#endif // ART_RUNTIME_DEX_STANDARD_DEX_FILE_H_ +#endif // ART_LIBDEXFILE_DEX_STANDARD_DEX_FILE_H_ diff --git a/runtime/dex/utf-inl.h b/libdexfile/dex/utf-inl.h index 4f626a8580..5355766aae 100644 --- a/runtime/dex/utf-inl.h +++ b/libdexfile/dex/utf-inl.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_UTF_INL_H_ -#define ART_RUNTIME_DEX_UTF_INL_H_ +#ifndef ART_LIBDEXFILE_DEX_UTF_INL_H_ +#define ART_LIBDEXFILE_DEX_UTF_INL_H_ #include "utf.h" @@ -96,4 +96,4 @@ inline int CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(const char* u } // namespace art -#endif // ART_RUNTIME_DEX_UTF_INL_H_ +#endif // ART_LIBDEXFILE_DEX_UTF_INL_H_ diff --git a/runtime/dex/utf.cc b/libdexfile/dex/utf.cc index 772a610140..772a610140 100644 --- a/runtime/dex/utf.cc +++ b/libdexfile/dex/utf.cc diff --git a/runtime/dex/utf.h b/libdexfile/dex/utf.h index 4adfc4af8c..c86b389175 100644 --- a/runtime/dex/utf.h +++ b/libdexfile/dex/utf.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_UTF_H_ -#define ART_RUNTIME_DEX_UTF_H_ +#ifndef ART_LIBDEXFILE_DEX_UTF_H_ +#define ART_LIBDEXFILE_DEX_UTF_H_ #include "base/macros.h" @@ -132,4 +132,4 @@ std::string PrintableString(const char* utf8); } // namespace art -#endif // ART_RUNTIME_DEX_UTF_H_ +#endif // ART_LIBDEXFILE_DEX_UTF_H_ diff --git a/runtime/dex/utf_test.cc b/libdexfile/dex/utf_test.cc index d2f22d16ef..d2f22d16ef 100644 --- a/runtime/dex/utf_test.cc +++ b/libdexfile/dex/utf_test.cc diff --git a/libdexfile/generate-operator-out.py b/libdexfile/generate-operator-out.py new file mode 120000 index 0000000000..cc291d20c1 --- /dev/null +++ b/libdexfile/generate-operator-out.py @@ -0,0 +1 @@ +../tools/generate-operator-out.py
\ No newline at end of file diff --git a/oatdump/Android.bp b/oatdump/Android.bp index c93c172eb4..012100d470 100644 --- a/oatdump/Android.bp +++ b/oatdump/Android.bp @@ -51,7 +51,7 @@ art_cc_binary { "libartd", "libartd-compiler", "libartd-disassembler", - "libdexfile", + "libdexfiled", "libbase", ], } @@ -76,6 +76,7 @@ art_cc_binary { ], static_libs: [ "libart", + "libdexfile", "libart-compiler", "libart-disassembler", "libvixl-arm", @@ -106,6 +107,7 @@ art_cc_binary { ], static_libs: [ "libartd", + "libdexfiled", "libartd-compiler", "libartd-disassembler", "libvixld-arm", diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 6c9f569b19..82bb88a5d5 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -2394,9 +2394,11 @@ class ImageDumper { } else if (obj->IsClass()) { ObjPtr<mirror::Class> klass = obj->AsClass(); - os << "SUBTYPE_CHECK_BITS: "; - SubtypeCheck<ObjPtr<mirror::Class>>::Dump(klass, os); - os << "\n"; + if (kBitstringSubtypeCheckEnabled) { + os << "SUBTYPE_CHECK_BITS: "; + SubtypeCheck<ObjPtr<mirror::Class>>::Dump(klass, os); + os << "\n"; + } if (klass->NumStaticFields() != 0) { os << "STATICS:\n"; diff --git a/openjdkjvmti/Android.bp b/openjdkjvmti/Android.bp index 1500bcae24..1553b78f46 100644 --- a/openjdkjvmti/Android.bp +++ b/openjdkjvmti/Android.bp @@ -58,7 +58,6 @@ cc_defaults { "libopenjdkjvmti_headers", ], shared_libs: [ - "libdexfile", "libbase", ], } @@ -70,6 +69,7 @@ art_cc_library { "libart", "libart-compiler", "libart-dexlayout", + "libdexfile", ], } @@ -83,5 +83,6 @@ art_cc_library { "libartd", "libartd-compiler", "libartd-dexlayout", + "libdexfiled", ], } diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc index a0c7f40b6f..ef5151990c 100644 --- a/openjdkjvmti/OpenjdkJvmTi.cc +++ b/openjdkjvmti/OpenjdkJvmTi.cc @@ -73,8 +73,10 @@ namespace openjdkjvmti { -EventHandler gEventHandler; -DeoptManager gDeoptManager; +// NB These are heap allocated to avoid the static destructors being run if an agent calls exit(3). +// These should never be null. +EventHandler* gEventHandler; +DeoptManager* gDeoptManager; #define ENSURE_NON_NULL(n) \ do { \ @@ -776,7 +778,7 @@ class JvmtiFunctions { ENSURE_HAS_CAP(env, can_retransform_classes); std::string error_msg; jvmtiError res = Transformer::RetransformClasses(ArtJvmTiEnv::AsArtJvmTiEnv(env), - &gEventHandler, + gEventHandler, art::Runtime::Current(), art::Thread::Current(), class_count, @@ -795,7 +797,7 @@ class JvmtiFunctions { ENSURE_HAS_CAP(env, can_redefine_classes); std::string error_msg; jvmtiError res = Redefiner::RedefineClasses(ArtJvmTiEnv::AsArtJvmTiEnv(env), - &gEventHandler, + gEventHandler, art::Runtime::Current(), art::Thread::Current(), class_count, @@ -1061,7 +1063,10 @@ class JvmtiFunctions { } ArtJvmTiEnv* art_env = ArtJvmTiEnv::AsArtJvmTiEnv(env); - return gEventHandler.SetEvent(art_env, art_thread, GetArtJvmtiEvent(art_env, event_type), mode); + return gEventHandler->SetEvent(art_env, + art_thread, + GetArtJvmtiEvent(art_env, event_type), + mode); } static jvmtiError GenerateEvents(jvmtiEnv* env, @@ -1095,7 +1100,7 @@ class JvmtiFunctions { return ExtensionUtil::SetExtensionEventCallback(env, extension_event_index, callback, - &gEventHandler); + gEventHandler); } #define FOR_ALL_CAPABILITIES(FUN) \ @@ -1186,9 +1191,9 @@ class JvmtiFunctions { FOR_ALL_CAPABILITIES(ADD_CAPABILITY); #undef ADD_CAPABILITY - gEventHandler.HandleChangedCapabilities(ArtJvmTiEnv::AsArtJvmTiEnv(env), - changed, - /*added*/true); + gEventHandler->HandleChangedCapabilities(ArtJvmTiEnv::AsArtJvmTiEnv(env), + changed, + /*added*/true); return ret; } @@ -1210,9 +1215,9 @@ class JvmtiFunctions { FOR_ALL_CAPABILITIES(DEL_CAPABILITY); #undef DEL_CAPABILITY - gEventHandler.HandleChangedCapabilities(ArtJvmTiEnv::AsArtJvmTiEnv(env), - changed, - /*added*/false); + gEventHandler->HandleChangedCapabilities(ArtJvmTiEnv::AsArtJvmTiEnv(env), + changed, + /*added*/false); return OK; } @@ -1302,7 +1307,7 @@ class JvmtiFunctions { static jvmtiError DisposeEnvironment(jvmtiEnv* env) { ENSURE_VALID_ENV(env); ArtJvmTiEnv* tienv = ArtJvmTiEnv::AsArtJvmTiEnv(env); - gEventHandler.RemoveArtJvmTiEnv(tienv); + gEventHandler->RemoveArtJvmTiEnv(tienv); art::Runtime::Current()->RemoveSystemWeakHolder(tienv->object_tag_table.get()); ThreadUtil::RemoveEnvironment(tienv); delete tienv; @@ -1490,10 +1495,10 @@ ArtJvmTiEnv::ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler, j // Creates a jvmtiEnv and returns it with the art::ti::Env that is associated with it. new_art_ti // is a pointer to the uninitialized memory for an art::ti::Env. static void CreateArtJvmTiEnv(art::JavaVMExt* vm, jint version, /*out*/void** new_jvmtiEnv) { - struct ArtJvmTiEnv* env = new ArtJvmTiEnv(vm, &gEventHandler, version); + struct ArtJvmTiEnv* env = new ArtJvmTiEnv(vm, gEventHandler, version); *new_jvmtiEnv = env; - gEventHandler.RegisterArtJvmTiEnv(env); + gEventHandler->RegisterArtJvmTiEnv(env); art::Runtime::Current()->AddSystemWeakHolder( ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get()); @@ -1522,17 +1527,20 @@ static jint GetEnvHandler(art::JavaVMExt* vm, /*out*/void** env, jint version) { extern "C" bool ArtPlugin_Initialize() { art::Runtime* runtime = art::Runtime::Current(); - gDeoptManager.Setup(); + gDeoptManager = new DeoptManager; + gEventHandler = new EventHandler; + + gDeoptManager->Setup(); if (runtime->IsStarted()) { PhaseUtil::SetToLive(); } else { PhaseUtil::SetToOnLoad(); } - PhaseUtil::Register(&gEventHandler); - ThreadUtil::Register(&gEventHandler); - ClassUtil::Register(&gEventHandler); - DumpUtil::Register(&gEventHandler); - MethodUtil::Register(&gEventHandler); + PhaseUtil::Register(gEventHandler); + ThreadUtil::Register(gEventHandler); + ClassUtil::Register(gEventHandler); + DumpUtil::Register(gEventHandler); + MethodUtil::Register(gEventHandler); SearchUtil::Register(); HeapUtil::Register(); Transformer::Setup(); @@ -1540,7 +1548,7 @@ extern "C" bool ArtPlugin_Initialize() { { // Make sure we can deopt anything we need to. art::ScopedObjectAccess soa(art::Thread::Current()); - gDeoptManager.FinishSetup(); + gDeoptManager->FinishSetup(); } runtime->GetJavaVM()->AddEnvironmentHook(GetEnvHandler); @@ -1549,8 +1557,8 @@ extern "C" bool ArtPlugin_Initialize() { } extern "C" bool ArtPlugin_Deinitialize() { - gEventHandler.Shutdown(); - gDeoptManager.Shutdown(); + gEventHandler->Shutdown(); + gDeoptManager->Shutdown(); PhaseUtil::Unregister(); ThreadUtil::Unregister(); ClassUtil::Unregister(); @@ -1559,6 +1567,11 @@ extern "C" bool ArtPlugin_Deinitialize() { SearchUtil::Unregister(); HeapUtil::Unregister(); + // TODO It would be good to delete the gEventHandler and gDeoptManager here but we cannot since + // daemon threads might be suspended and we want to make sure that even if they wake up briefly + // they won't hit deallocated memory. By this point none of the functions will do anything since + // they have already shutdown. + return true; } diff --git a/openjdkjvmti/deopt_manager.cc b/openjdkjvmti/deopt_manager.cc index 9e11a25e58..6d84ffa53f 100644 --- a/openjdkjvmti/deopt_manager.cc +++ b/openjdkjvmti/deopt_manager.cc @@ -277,7 +277,7 @@ void DeoptManager::AddDeoptimizeAllMethodsLocked(art::Thread* self) { } void DeoptManager::RemoveDeoptimizeAllMethodsLocked(art::Thread* self) { - DCHECK_GT(global_deopt_count_, 0u) << "Request to remove non-existant global deoptimization!"; + DCHECK_GT(global_deopt_count_, 0u) << "Request to remove non-existent global deoptimization!"; global_deopt_count_--; if (global_deopt_count_ == 0) { PerformGlobalUndeoptimization(self); @@ -343,9 +343,9 @@ void DeoptManager::DeoptimizeThread(art::Thread* target) { art::Runtime::Current()->GetInstrumentation()->InstrumentThreadStack(target); } -extern DeoptManager gDeoptManager; +extern DeoptManager* gDeoptManager; DeoptManager* DeoptManager::Get() { - return &gDeoptManager; + return gDeoptManager; } } // namespace openjdkjvmti diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc index 62b73c08c0..8b40a7e072 100644 --- a/openjdkjvmti/events.cc +++ b/openjdkjvmti/events.cc @@ -1186,8 +1186,9 @@ void EventHandler::Shutdown() { art::Runtime::Current()->GetInstrumentation()->RemoveListener(method_trace_listener_.get(), ~0); } -EventHandler::EventHandler() : envs_lock_("JVMTI Environment List Lock", - art::LockLevel::kTopLockLevel) { +EventHandler::EventHandler() + : envs_lock_("JVMTI Environment List Lock", art::LockLevel::kTopLockLevel), + frame_pop_enabled(false) { alloc_listener_.reset(new JvmtiAllocationListener(this)); ddm_listener_.reset(new JvmtiDdmChunkListener(this)); gc_pause_listener_.reset(new JvmtiGcPauseListener(this)); diff --git a/openjdkjvmti/transform.cc b/openjdkjvmti/transform.cc index dc9f69a96a..43b8fe94f4 100644 --- a/openjdkjvmti/transform.cc +++ b/openjdkjvmti/transform.cc @@ -124,7 +124,7 @@ class TransformationFaultHandler FINAL : public art::FaultHandler { return std::find_if(initialized_class_definitions_.begin(), initialized_class_definitions_.end(), [&](const auto op) { return op->ContainsAddress(ptr); }) != - uninitialized_class_definitions_.end(); + initialized_class_definitions_.end(); } } diff --git a/profman/Android.bp b/profman/Android.bp index 6592b9dec0..163be2b64f 100644 --- a/profman/Android.bp +++ b/profman/Android.bp @@ -31,7 +31,6 @@ cc_defaults { }, shared_libs: [ - "libdexfile", "libbase", ], } @@ -41,6 +40,7 @@ art_cc_binary { defaults: ["profman-defaults"], shared_libs: [ "libart", + "libdexfile", ], } @@ -52,6 +52,7 @@ art_cc_binary { ], shared_libs: [ "libartd", + "libdexfiled", ], } diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc index 79310ac166..188d0b0a24 100644 --- a/profman/profile_assistant_test.cc +++ b/profman/profile_assistant_test.cc @@ -31,6 +31,8 @@ namespace art { +using Hotness = ProfileCompilationInfo::MethodHotness; + static constexpr size_t kMaxMethodIds = 65535; class ProfileAssistantTest : public CommonRuntimeTest { @@ -80,12 +82,17 @@ class ProfileAssistantTest : public CommonRuntimeTest { ProfileCompilationInfo::OfflineProfileMethodInfo pmi = GetOfflineProfileMethodInfo(dex_location1, dex_location_checksum1, dex_location2, dex_location_checksum2); + Hotness::Flag flags = Hotness::kFlagPostStartup; if (reverse_dex_write_order) { - ASSERT_TRUE(info->AddMethod(dex_location2, dex_location_checksum2, i, kMaxMethodIds, pmi)); - ASSERT_TRUE(info->AddMethod(dex_location1, dex_location_checksum1, i, kMaxMethodIds, pmi)); + ASSERT_TRUE(info->AddMethod( + dex_location2, dex_location_checksum2, i, kMaxMethodIds, pmi, flags)); + ASSERT_TRUE(info->AddMethod( + dex_location1, dex_location_checksum1, i, kMaxMethodIds, pmi, flags)); } else { - ASSERT_TRUE(info->AddMethod(dex_location1, dex_location_checksum1, i, kMaxMethodIds, pmi)); - ASSERT_TRUE(info->AddMethod(dex_location2, dex_location_checksum2, i, kMaxMethodIds, pmi)); + ASSERT_TRUE(info->AddMethod( + dex_location1, dex_location_checksum1, i, kMaxMethodIds, pmi, flags)); + ASSERT_TRUE(info->AddMethod( + dex_location2, dex_location_checksum2, i, kMaxMethodIds, pmi, flags)); } } for (uint16_t i = 0; i < number_of_classes; i++) { @@ -109,7 +116,6 @@ class ProfileAssistantTest : public CommonRuntimeTest { const ScratchFile& profile, ProfileCompilationInfo* info) { std::string dex_location = "location1" + id; - using Hotness = ProfileCompilationInfo::MethodHotness; for (uint32_t idx : hot_methods) { info->AddMethodIndex(Hotness::kFlagHot, dex_location, checksum, idx, number_of_methods); } @@ -1086,10 +1092,10 @@ TEST_F(ProfileAssistantTest, TestProfileCreateWithInvalidData) { ASSERT_EQ(1u, classes.size()); ASSERT_TRUE(classes.find(invalid_class_index) != classes.end()); - // Verify that the invalid method is in the profile. - ASSERT_EQ(2u, hot_methods.size()); + // Verify that the invalid method did not get in the profile. + ASSERT_EQ(1u, hot_methods.size()); uint16_t invalid_method_index = std::numeric_limits<uint16_t>::max() - 1; - ASSERT_TRUE(hot_methods.find(invalid_method_index) != hot_methods.end()); + ASSERT_FALSE(hot_methods.find(invalid_method_index) != hot_methods.end()); } TEST_F(ProfileAssistantTest, DumpOnly) { diff --git a/profman/profman.cc b/profman/profman.cc index 387ce8dfae..efb7fcfec6 100644 --- a/profman/profman.cc +++ b/profman/profman.cc @@ -895,6 +895,17 @@ class ProfMan FINAL { method_str = line.substr(method_sep_index + kMethodSep.size()); } + uint32_t flags = 0; + if (is_hot) { + flags |= ProfileCompilationInfo::MethodHotness::kFlagHot; + } + if (is_startup) { + flags |= ProfileCompilationInfo::MethodHotness::kFlagStartup; + } + if (is_post_startup) { + flags |= ProfileCompilationInfo::MethodHotness::kFlagPostStartup; + } + TypeReference class_ref(/* dex_file */ nullptr, dex::TypeIndex()); if (!FindClass(dex_files, klass, &class_ref)) { LOG(WARNING) << "Could not find class: " << klass; @@ -930,7 +941,7 @@ class ProfMan FINAL { } } // TODO: Check return values? - profile->AddMethods(methods); + profile->AddMethods(methods, static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags)); profile->AddClasses(resolved_class_set); return true; } @@ -982,18 +993,12 @@ class ProfMan FINAL { } MethodReference ref(class_ref.dex_file, method_index); if (is_hot) { - profile->AddMethod(ProfileMethodInfo(ref, inline_caches)); - } - uint32_t flags = 0; - using Hotness = ProfileCompilationInfo::MethodHotness; - if (is_startup) { - flags |= Hotness::kFlagStartup; - } - if (is_post_startup) { - flags |= Hotness::kFlagPostStartup; + profile->AddMethod(ProfileMethodInfo(ref, inline_caches), + static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags)); } if (flags != 0) { - if (!profile->AddMethodIndex(static_cast<Hotness::Flag>(flags), ref)) { + if (!profile->AddMethodIndex( + static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags), ref)) { return false; } DCHECK(profile->GetMethodHotness(ref).IsInProfile()); diff --git a/runtime/Android.bp b/runtime/Android.bp index db9bceaf29..1ac770fd06 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -14,83 +14,6 @@ // limitations under the License. // -cc_defaults { - name: "libdexfile_defaults", - defaults: ["art_defaults"], - host_supported: true, - srcs: [ - "dex/compact_dex_debug_info.cc", - "dex/compact_dex_file.cc", - "dex/descriptors_names.cc", - "dex/dex_file.cc", - "dex/dex_file_exception_helpers.cc", - "dex/dex_file_loader.cc", - "dex/dex_file_tracking_registrar.cc", - "dex/dex_file_verifier.cc", - "dex/dex_instruction.cc", - "dex/modifiers.cc", - "dex/standard_dex_file.cc", - "dex/utf.cc", - ], - - target: { - android: { - static_libs: [ - "libziparchive", - "libz", - "libbase", - ], - shared_libs: [ - "libutils", - ], - }, - host: { - shared_libs: [ - "libziparchive", - "libz", - ], - }, - }, - generated_sources: ["dexfile_operator_srcs"], - include_dirs: [ - "external/zlib", - ], - shared_libs: [ - "liblog", - // For common macros. - "libbase", - "libz", - ], - - // Exporting "." would shadow the system elf.h with our elf.h, - // which in turn breaks any tools that reference this library. - // export_include_dirs: ["."], -} - -gensrcs { - name: "dexfile_operator_srcs", - cmd: "$(location generate-operator-out.py) art/runtime $(in) > $(out)", - tool_files: ["generate-operator-out.py"], - srcs: [ - "dex/dex_file.h", - "dex/dex_file_layout.h", - "dex/dex_instruction.h", - "dex/dex_instruction_utils.h", - "dex/invoke_type.h", - ], - output_extension: "operator_out.cc", -} - -art_cc_library { - name: "libdexfile", - defaults: ["libdexfile_defaults"], - // Leave the symbols in the shared library so that stack unwinders can - // produce meaningful name resolution. - strip: { - keep_symbols: true, - }, -} - // Keep the __jit_debug_register_code symbol as a unique symbol during ICF for architectures where // we use gold as the linker (arm, x86, x86_64). The symbol is used by the debuggers to detect when // new jit code is generated. We don't want it to be called when a different function with the same @@ -133,9 +56,9 @@ cc_defaults { "common_throws.cc", "compiler_filter.cc", "debugger.cc", + "dex/art_dex_file_loader.cc", "dex/dex_file_annotations.cc", "dex/dex_file_layout.cc", - "dex/art_dex_file_loader.cc", "dex_to_dex_decompiler.cc", "elf_file.cc", "exec_utils.cc", @@ -244,7 +167,6 @@ cc_defaults { "native/java_lang_Thread.cc", "native/java_lang_Throwable.cc", "native/java_lang_VMClassLoader.cc", - "native/java_lang_Void.cc", "native/java_lang_invoke_MethodHandleImpl.cc", "native/java_lang_ref_FinalizerReference.cc", "native/java_lang_ref_Reference.cc", @@ -487,7 +409,6 @@ cc_defaults { "jni_platform_headers", ], shared_libs: [ - "libdexfile", "libnativebridge", "libnativeloader", "libbacktrace", @@ -521,9 +442,9 @@ gensrcs { "base/callee_save_type.h", "base/enums.h", "base/mutex.h", - "debugger.h", "base/unix_file/fd_file.h", "class_status.h", + "debugger.h", "dex/dex_file_layout.h", "gc_root.h", "gc/allocator_type.h", @@ -565,6 +486,8 @@ art_cc_library { strip: { keep_symbols: true, }, + shared_libs: ["libdexfile"], + export_shared_lib_headers: ["libdexfile"], } art_cc_library { @@ -573,6 +496,8 @@ art_cc_library { "art_debug_defaults", "libart_defaults", ], + shared_libs: ["libdexfiled"], + export_shared_lib_headers: ["libdexfiled"], } art_cc_library { @@ -637,13 +562,7 @@ art_cc_test { "class_loader_context_test.cc", "class_table_test.cc", "compiler_filter_test.cc", - "dex/code_item_accessors_test.cc", - "dex/compact_dex_debug_info_test.cc", - "dex/compact_dex_file_test.cc", - "dex/dex_file_test.cc", - "dex/dex_file_verifier_test.cc", - "dex/dex_instruction_test.cc", - "dex/utf_test.cc", + "dex/art_dex_file_loader_test.cc", "entrypoints/math_entrypoints_test.cc", "entrypoints/quick/quick_trampoline_entrypoints_test.cc", "entrypoints_order_test.cc", diff --git a/runtime/arch/memcmp16_test.cc b/runtime/arch/memcmp16_test.cc index 2f3639c4b1..37aad21a40 100644 --- a/runtime/arch/memcmp16_test.cc +++ b/runtime/arch/memcmp16_test.cc @@ -100,7 +100,7 @@ static void CheckSeparate(size_t max_length, size_t min_length) { } size_t min = count1 < count2 ? count1 : count2; - bool fill_same = r.next() % 1 == 1; + bool fill_same = r.next() % 2 == 1; if (fill_same) { for (size_t i = 0; i < min; ++i) { diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index e6e35c89c9..8b48aa27f9 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -328,6 +328,7 @@ inline mirror::DexCache* ArtMethod::GetDexCache() { } inline bool ArtMethod::IsProxyMethod() { + DCHECK(!IsRuntimeMethod()) << "ArtMethod::IsProxyMethod called on a runtime method"; // Avoid read barrier since the from-space version of the class will have the correct proxy class // flags since they are constant for the lifetime of the class. return GetDeclaringClass<kWithoutReadBarrier>()->IsProxyClass(); diff --git a/runtime/art_method.h b/runtime/art_method.h index cec2ec4df2..21ee8f19e5 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -551,7 +551,7 @@ class ArtMethod FINAL { // Is this a CalleSaveMethod or ResolutionMethod and therefore doesn't adhere to normal // conventions for a method of managed code. Returns false for Proxy methods. ALWAYS_INLINE bool IsRuntimeMethod() { - return dex_method_index_ == kRuntimeMethodDexMethodIndex;; + return dex_method_index_ == kRuntimeMethodDexMethodIndex; } // Is this a hand crafted method used for something like describing callee saves? diff --git a/runtime/base/bit_vector.cc b/runtime/base/bit_vector.cc index 5e97a63c0d..c706c7ebf2 100644 --- a/runtime/base/bit_vector.cc +++ b/runtime/base/bit_vector.cc @@ -223,7 +223,7 @@ void BitVector::Subtract(const BitVector *src) { // Difference until max, we know both accept it: // There is no need to do more: // If we are bigger than src, the upper bits are unchanged. - // If we are smaller than src, the non-existant upper bits are 0 and thus can't get subtracted. + // If we are smaller than src, the nonexistent upper bits are 0 and thus can't get subtracted. for (uint32_t idx = 0; idx < min_size; idx++) { storage_[idx] &= (~(src->GetRawStorageWord(idx))); } diff --git a/runtime/base/stringpiece.cc b/runtime/base/stringpiece.cc index 672431cf9d..aea4e74bb1 100644 --- a/runtime/base/stringpiece.cc +++ b/runtime/base/stringpiece.cc @@ -23,13 +23,6 @@ namespace art { -#if !defined(NDEBUG) -char StringPiece::operator[](size_type i) const { - CHECK_LT(i, length_); - return ptr_[i]; -} -#endif - void StringPiece::CopyToString(std::string* target) const { target->assign(ptr_, length_); } diff --git a/runtime/base/stringpiece.h b/runtime/base/stringpiece.h index 46743e9643..e7109dc18a 100644 --- a/runtime/base/stringpiece.h +++ b/runtime/base/stringpiece.h @@ -20,6 +20,8 @@ #include <string.h> #include <string> +#include <android-base/logging.h> + namespace art { // A string-like object that points to a sized piece of memory. @@ -84,13 +86,10 @@ class StringPiece { length_ = len; } -#if defined(NDEBUG) char operator[](size_type i) const { + DCHECK_LT(i, length_); return ptr_[i]; } -#else - char operator[](size_type i) const; -#endif void remove_prefix(size_type n) { ptr_ += n; diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc index 5549122c34..05f099f3b2 100644 --- a/runtime/check_jni.cc +++ b/runtime/check_jni.cc @@ -46,6 +46,7 @@ #include "well_known_classes.h" namespace art { +namespace { using android::base::StringAppendF; using android::base::StringPrintf; @@ -1211,7 +1212,7 @@ class ScopedCheck { // this particular instance of JNIEnv. if (env != threadEnv) { // Get the thread owning the JNIEnv that's being used. - Thread* envThread = reinterpret_cast<JNIEnvExt*>(env)->self_; + Thread* envThread = reinterpret_cast<JNIEnvExt*>(env)->GetSelf(); AbortF("thread %s using JNIEnv* from thread %s", ToStr<Thread>(*self).c_str(), ToStr<Thread>(*envThread).c_str()); return false; @@ -1223,7 +1224,7 @@ class ScopedCheck { case kFlag_CritOkay: // okay to call this method break; case kFlag_CritBad: // not okay to call - if (threadEnv->critical_ > 0) { + if (threadEnv->GetCritical() > 0) { AbortF("thread %s using JNI after critical get", ToStr<Thread>(*self).c_str()); return false; @@ -1231,25 +1232,25 @@ class ScopedCheck { break; case kFlag_CritGet: // this is a "get" call // Don't check here; we allow nested gets. - if (threadEnv->critical_ == 0) { - threadEnv->critical_start_us_ = self->GetCpuMicroTime(); + if (threadEnv->GetCritical() == 0) { + threadEnv->SetCriticalStartUs(self->GetCpuMicroTime()); } - threadEnv->critical_++; + threadEnv->SetCritical(threadEnv->GetCritical() + 1); break; case kFlag_CritRelease: // this is a "release" call - if (threadEnv->critical_ == 0) { + if (threadEnv->GetCritical() == 0) { AbortF("thread %s called too many critical releases", ToStr<Thread>(*self).c_str()); return false; - } else if (threadEnv->critical_ == 1) { + } else if (threadEnv->GetCritical() == 1) { // Leaving the critical region, possibly warn about long critical regions. - uint64_t critical_duration_us = self->GetCpuMicroTime() - threadEnv->critical_start_us_; + uint64_t critical_duration_us = self->GetCpuMicroTime() - threadEnv->GetCriticalStartUs(); if (critical_duration_us > kCriticalWarnTimeUs) { LOG(WARNING) << "JNI critical lock held for " << PrettyDuration(UsToNs(critical_duration_us)) << " on " << *self; } } - threadEnv->critical_--; + threadEnv->SetCritical(threadEnv->GetCritical() - 1); break; default: LOG(FATAL) << "Bad flags (internal error): " << flags_; @@ -2621,7 +2622,7 @@ class CheckJNI { } static const JNINativeInterface* baseEnv(JNIEnv* env) { - return reinterpret_cast<JNIEnvExt*>(env)->unchecked_functions_; + return reinterpret_cast<JNIEnvExt*>(env)->GetUncheckedFunctions(); } static jobject NewRef(const char* function_name, JNIEnv* env, jobject obj, IndirectRefKind kind) { @@ -3847,10 +3848,6 @@ const JNINativeInterface gCheckNativeInterface = { CheckJNI::GetObjectRefType, }; -const JNINativeInterface* GetCheckJniNativeInterface() { - return &gCheckNativeInterface; -} - class CheckJII { public: static jint DestroyJavaVM(JavaVM* vm) { @@ -3922,6 +3919,12 @@ const JNIInvokeInterface gCheckInvokeInterface = { CheckJII::AttachCurrentThreadAsDaemon }; +} // anonymous namespace + +const JNINativeInterface* GetCheckJniNativeInterface() { + return &gCheckNativeInterface; +} + const JNIInvokeInterface* GetCheckJniInvokeInterface() { return &gCheckInvokeInterface; } diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index cd6e8d59e8..ae06f8f9bc 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -226,14 +226,7 @@ inline ArtMethod* ClassLinker::LookupResolvedMethod(uint32_t method_idx, const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); ObjPtr<mirror::Class> klass = LookupResolvedType(method_id.class_idx_, dex_cache, class_loader); if (klass != nullptr) { - if (klass->IsInterface()) { - resolved = klass->FindInterfaceMethod(dex_cache, method_idx, pointer_size); - } else { - resolved = klass->FindClassMethod(dex_cache, method_idx, pointer_size); - } - if (resolved != nullptr) { - dex_cache->SetResolvedMethod(method_idx, resolved, pointer_size); - } + resolved = FindResolvedMethod(klass, dex_cache, class_loader, method_idx); } } return resolved; diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 800427d6ab..62627287b0 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -457,7 +457,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b VoidFunctor())); // Initialize the SubtypeCheck bitstring for java.lang.Object and java.lang.Class. - { + if (kBitstringSubtypeCheckEnabled) { // It might seem the lock here is unnecessary, however all the SubtypeCheck // functions are annotated to require locks all the way down. // @@ -1856,7 +1856,7 @@ bool ClassLinker::AddImageSpace( visitor(root.Read()); } - { + if (kBitstringSubtypeCheckEnabled) { // Every class in the app image has initially SubtypeCheckInfo in the // Uninitialized state. // @@ -4484,6 +4484,14 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& Runtime::Current()->GetRuntimeCallbacks()->ClassPrepare(temp_klass, klass); + // SubtypeCheckInfo::Initialized must happen-before any new-instance for that type. + // See also ClassLinker::EnsureInitialized(). + if (kBitstringSubtypeCheckEnabled) { + MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_); + SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(klass.Get()); + // TODO: Avoid taking subtype_check_lock_ if SubtypeCheck for j.l.r.Proxy is already assigned. + } + { // Lock on klass is released. Lock new class object. ObjectLock<mirror::Class> initialization_lock(self, klass); @@ -5231,7 +5239,7 @@ bool ClassLinker::EnsureInitialized(Thread* self, // can be used as a source for the IsSubClass check, and that all ancestors // of the class are Assigned (can be used as a target for IsSubClass check) // or Overflowed (can be used as a source for IsSubClass check). - { + if (kBitstringSubtypeCheckEnabled) { MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_); SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(c.Get()); // TODO: Avoid taking subtype_check_lock_ if SubtypeCheck is already initialized. @@ -7931,6 +7939,38 @@ std::string DescribeLoaders(ObjPtr<mirror::ClassLoader> loader, const char* clas return oss.str(); } +ArtMethod* ClassLinker::FindResolvedMethod(ObjPtr<mirror::Class> klass, + ObjPtr<mirror::DexCache> dex_cache, + ObjPtr<mirror::ClassLoader> class_loader, + uint32_t method_idx) { + // Search for the method using dex_cache and method_idx. The Class::Find*Method() + // functions can optimize the search if the dex_cache is the same as the DexCache + // of the class, with fall-back to name and signature search otherwise. + ArtMethod* resolved = nullptr; + if (klass->IsInterface()) { + resolved = klass->FindInterfaceMethod(dex_cache, method_idx, image_pointer_size_); + } else { + resolved = klass->FindClassMethod(dex_cache, method_idx, image_pointer_size_); + } + DCHECK(resolved == nullptr || resolved->GetDeclaringClassUnchecked() != nullptr); + if (resolved != nullptr) { + // In case of jmvti, the dex file gets verified before being registered, so first + // check if it's registered before checking class tables. + const DexFile& dex_file = *dex_cache->GetDexFile(); + CHECK(!IsDexFileRegistered(Thread::Current(), dex_file) || + FindClassTable(Thread::Current(), dex_cache) == ClassTableForClassLoader(class_loader)) + << "DexFile referrer: " << dex_file.GetLocation() + << " ClassLoader: " << DescribeLoaders(class_loader, ""); + // Be a good citizen and update the dex cache to speed subsequent calls. + dex_cache->SetResolvedMethod(method_idx, resolved, image_pointer_size_); + const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); + CHECK(LookupResolvedType(method_id.class_idx_, dex_cache, class_loader) != nullptr) + << "Class: " << klass->PrettyClass() << ", " + << "DexFile referrer: " << dex_file.GetLocation(); + } + return resolved; +} + template <ClassLinker::ResolveMode kResolveMode> ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx, Handle<mirror::DexCache> dex_cache, @@ -7963,6 +8003,7 @@ ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx, << resolved->PrettyMethod() << ";" << resolved << "/0x" << std::hex << resolved->GetAccessFlags() << " ReferencedClass: " << descriptor + << " DexFile referrer: " << dex_file.GetLocation() << " ClassLoader: " << DescribeLoaders(class_loader.Get(), descriptor); } } else { @@ -7983,19 +8024,7 @@ ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx, } if (!valid_dex_cache_method) { - // Search for the method using dex_cache and method_idx. The Class::Find*Method() - // functions can optimize the search if the dex_cache is the same as the DexCache - // of the class, with fall-back to name and signature search otherwise. - if (klass->IsInterface()) { - resolved = klass->FindInterfaceMethod(dex_cache.Get(), method_idx, pointer_size); - } else { - resolved = klass->FindClassMethod(dex_cache.Get(), method_idx, pointer_size); - } - DCHECK(resolved == nullptr || resolved->GetDeclaringClassUnchecked() != nullptr); - if (resolved != nullptr) { - // Be a good citizen and update the dex cache to speed subsequent calls. - dex_cache->SetResolvedMethod(method_idx, resolved, pointer_size); - } + resolved = FindResolvedMethod(klass, dex_cache.Get(), class_loader.Get(), method_idx); } // Note: We can check for IllegalAccessError only if we have a referrer. diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 16fa1ce801..6bb924fc7d 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -312,6 +312,13 @@ class ClassLinker { ObjPtr<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_); + // Find a method with the given index from class `klass`, and update the dex cache. + ArtMethod* FindResolvedMethod(ObjPtr<mirror::Class> klass, + ObjPtr<mirror::DexCache> dex_cache, + ObjPtr<mirror::ClassLoader> class_loader, + uint32_t method_idx) + REQUIRES_SHARED(Locks::mutator_lock_); + // Resolve a method with a given ID from the DexFile associated with the given DexCache // and ClassLoader, storing the result in DexCache. The ClassLinker and ClassLoader are // used as in ResolveType. What is unique is the method type argument which is used to diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc index 1b6f317053..8f65c66441 100644 --- a/runtime/common_throws.cc +++ b/runtime/common_throws.cc @@ -53,6 +53,11 @@ static void AddReferrerLocation(std::ostream& os, ObjPtr<mirror::Class> referrer } } +static void ThrowException(const char* exception_descriptor) REQUIRES_SHARED(Locks::mutator_lock_) { + Thread* self = Thread::Current(); + self->ThrowNewException(exception_descriptor, nullptr); +} + static void ThrowException(const char* exception_descriptor, ObjPtr<mirror::Class> referrer, const char* fmt, @@ -243,6 +248,11 @@ void ThrowIllegalArgumentException(const char* msg) { ThrowException("Ljava/lang/IllegalArgumentException;", nullptr, msg); } +// IllegalStateException + +void ThrowIllegalStateException(const char* msg) { + ThrowException("Ljava/lang/IllegalStateException;", nullptr, msg); +} // IncompatibleClassChangeError @@ -314,6 +324,13 @@ void ThrowIncompatibleClassChangeErrorForMethodConflict(ArtMethod* method) { ArtMethod::PrettyMethod(method).c_str()).c_str()); } +// IndexOutOfBoundsException + +void ThrowIndexOutOfBoundsException(int index, int length) { + ThrowException("Ljava/lang/IndexOutOfBoundsException;", nullptr, + StringPrintf("length=%d; index=%d", length, index).c_str()); +} + // InternalError void ThrowInternalError(const char* fmt, ...) { @@ -721,6 +738,12 @@ void ThrowNullPointerException(const char* msg) { ThrowException("Ljava/lang/NullPointerException;", nullptr, msg); } +// ReadOnlyBufferException + +void ThrowReadOnlyBufferException() { + Thread::Current()->ThrowNewException("Ljava/nio/ReadOnlyBufferException;", nullptr); +} + // RuntimeException void ThrowRuntimeException(const char* fmt, ...) { @@ -844,6 +867,12 @@ void ThrowStringIndexOutOfBoundsException(int index, int length) { StringPrintf("length=%d; index=%d", length, index).c_str()); } +// UnsupportedOperationException + +void ThrowUnsupportedOperationException() { + ThrowException("Ljava/lang/UnsupportedOperationException;"); +} + // VerifyError void ThrowVerifyError(ObjPtr<mirror::Class> referrer, const char* fmt, ...) { @@ -855,13 +884,13 @@ void ThrowVerifyError(ObjPtr<mirror::Class> referrer, const char* fmt, ...) { // WrongMethodTypeException -void ThrowWrongMethodTypeException(mirror::MethodType* callee_type, - mirror::MethodType* callsite_type) { +void ThrowWrongMethodTypeException(mirror::MethodType* expected_type, + mirror::MethodType* actual_type) { ThrowException("Ljava/lang/invoke/WrongMethodTypeException;", nullptr, StringPrintf("Expected %s but was %s", - callee_type->PrettyDescriptor().c_str(), - callsite_type->PrettyDescriptor().c_str()).c_str()); + expected_type->PrettyDescriptor().c_str(), + actual_type->PrettyDescriptor().c_str()).c_str()); } } // namespace art diff --git a/runtime/common_throws.h b/runtime/common_throws.h index 3512b2b5bf..e9baa4fef0 100644 --- a/runtime/common_throws.h +++ b/runtime/common_throws.h @@ -120,6 +120,11 @@ void ThrowIllegalAccessException(const char* msg) void ThrowIllegalArgumentException(const char* msg) REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR; +// IllegalAccessException + +void ThrowIllegalStateException(const char* msg) + REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR; + // IncompatibleClassChangeError void ThrowIncompatibleClassChangeError(InvokeType expected_type, @@ -151,6 +156,11 @@ void ThrowIncompatibleClassChangeError(ObjPtr<mirror::Class> referrer, const cha void ThrowIncompatibleClassChangeErrorForMethodConflict(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR; +// IndexOutOfBoundsException + +void ThrowIndexOutOfBoundsException(int index, int length) + REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR; + // InternalError void ThrowInternalError(const char* fmt, ...) @@ -223,6 +233,10 @@ void ThrowNullPointerExceptionFromDexPC(bool check_address = false, uintptr_t ad void ThrowNullPointerException(const char* msg) REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR; +// ReadOnlyBufferException + +void ThrowReadOnlyBufferException() REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR; + // RuntimeException void ThrowRuntimeException(const char* fmt, ...) @@ -244,6 +258,10 @@ void ThrowStackOverflowError(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) void ThrowStringIndexOutOfBoundsException(int index, int length) REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR; +// UnsupportedOperationException + +void ThrowUnsupportedOperationException() REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR; + // VerifyError void ThrowVerifyError(ObjPtr<mirror::Class> referrer, const char* fmt, ...) @@ -251,6 +269,7 @@ void ThrowVerifyError(ObjPtr<mirror::Class> referrer, const char* fmt, ...) REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR; // WrongMethodTypeException + void ThrowWrongMethodTypeException(mirror::MethodType* callee_type, mirror::MethodType* callsite_type) REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR; diff --git a/runtime/dex/art_dex_file_loader.cc b/runtime/dex/art_dex_file_loader.cc index 08cf30d5bf..0817cb4b6a 100644 --- a/runtime/dex/art_dex_file_loader.cc +++ b/runtime/dex/art_dex_file_loader.cc @@ -25,10 +25,10 @@ #include "base/stl_util.h" #include "base/systrace.h" #include "base/unix_file/fd_file.h" -#include "compact_dex_file.h" -#include "dex_file.h" -#include "dex_file_verifier.h" -#include "standard_dex_file.h" +#include "dex/compact_dex_file.h" +#include "dex/dex_file.h" +#include "dex/dex_file_verifier.h" +#include "dex/standard_dex_file.h" #include "zip_archive.h" namespace art { diff --git a/runtime/dex/art_dex_file_loader.h b/runtime/dex/art_dex_file_loader.h index b31d1e94e0..3585381f9b 100644 --- a/runtime/dex/art_dex_file_loader.h +++ b/runtime/dex/art_dex_file_loader.h @@ -22,8 +22,8 @@ #include <string> #include <vector> -#include "dex_file_loader.h" #include "base/macros.h" +#include "dex/dex_file_loader.h" namespace art { diff --git a/runtime/dex/art_dex_file_loader_test.cc b/runtime/dex/art_dex_file_loader_test.cc new file mode 100644 index 0000000000..25d4dd0875 --- /dev/null +++ b/runtime/dex/art_dex_file_loader_test.cc @@ -0,0 +1,307 @@ +/* + * 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. + */ + +#include <sys/mman.h> + +#include <memory> + +#include "art_dex_file_loader.h" +#include "base/stl_util.h" +#include "base/unix_file/fd_file.h" +#include "common_runtime_test.h" +#include "dex/base64_test_util.h" +#include "dex/code_item_accessors-inl.h" +#include "dex/descriptors_names.h" +#include "dex/dex_file.h" +#include "dex/dex_file-inl.h" +#include "dex/dex_file_loader.h" +#include "mem_map.h" +#include "os.h" +#include "scoped_thread_state_change-inl.h" +#include "thread-current-inl.h" + +namespace art { + +class ArtDexFileLoaderTest : public CommonRuntimeTest {}; + +// TODO: Port OpenTestDexFile(s) need to be ported to use non-ART utilities, and +// the tests that depend upon them should be moved to dex_file_loader_test.cc + +TEST_F(ArtDexFileLoaderTest, Open) { + ScopedObjectAccess soa(Thread::Current()); + std::unique_ptr<const DexFile> dex(OpenTestDexFile("Nested")); + ASSERT_TRUE(dex.get() != nullptr); +} + +TEST_F(ArtDexFileLoaderTest, GetLocationChecksum) { + ScopedObjectAccess soa(Thread::Current()); + std::unique_ptr<const DexFile> raw(OpenTestDexFile("Main")); + EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum()); +} + +TEST_F(ArtDexFileLoaderTest, GetChecksum) { + std::vector<uint32_t> checksums; + ScopedObjectAccess soa(Thread::Current()); + std::string error_msg; + const ArtDexFileLoader dex_file_loader; + EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(), + &checksums, + &error_msg)) + << error_msg; + ASSERT_EQ(1U, checksums.size()); + EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksums[0]); +} + +TEST_F(ArtDexFileLoaderTest, GetMultiDexChecksums) { + std::string error_msg; + std::vector<uint32_t> checksums; + std::string multidex_file = GetTestDexFileName("MultiDex"); + const ArtDexFileLoader dex_file_loader; + EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(multidex_file.c_str(), + &checksums, + &error_msg)) << error_msg; + + std::vector<std::unique_ptr<const DexFile>> dexes = OpenTestDexFiles("MultiDex"); + ASSERT_EQ(2U, dexes.size()); + ASSERT_EQ(2U, checksums.size()); + + EXPECT_EQ(dexes[0]->GetLocation(), DexFileLoader::GetMultiDexLocation(0, multidex_file.c_str())); + EXPECT_EQ(dexes[0]->GetLocationChecksum(), checksums[0]); + + EXPECT_EQ(dexes[1]->GetLocation(), DexFileLoader::GetMultiDexLocation(1, multidex_file.c_str())); + EXPECT_EQ(dexes[1]->GetLocationChecksum(), checksums[1]); +} + +TEST_F(ArtDexFileLoaderTest, ClassDefs) { + ScopedObjectAccess soa(Thread::Current()); + std::unique_ptr<const DexFile> raw(OpenTestDexFile("Nested")); + ASSERT_TRUE(raw.get() != nullptr); + EXPECT_EQ(3U, raw->NumClassDefs()); + + const DexFile::ClassDef& c0 = raw->GetClassDef(0); + EXPECT_STREQ("LNested$1;", raw->GetClassDescriptor(c0)); + + const DexFile::ClassDef& c1 = raw->GetClassDef(1); + EXPECT_STREQ("LNested$Inner;", raw->GetClassDescriptor(c1)); + + const DexFile::ClassDef& c2 = raw->GetClassDef(2); + EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c2)); +} + +TEST_F(ArtDexFileLoaderTest, GetMethodSignature) { + ScopedObjectAccess soa(Thread::Current()); + std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature")); + ASSERT_TRUE(raw.get() != nullptr); + EXPECT_EQ(1U, raw->NumClassDefs()); + + const DexFile::ClassDef& class_def = raw->GetClassDef(0); + ASSERT_STREQ("LGetMethodSignature;", raw->GetClassDescriptor(class_def)); + + const uint8_t* class_data = raw->GetClassData(class_def); + ASSERT_TRUE(class_data != nullptr); + ClassDataItemIterator it(*raw, class_data); + + EXPECT_EQ(1u, it.NumDirectMethods()); + + // Check the signature for the static initializer. + { + ASSERT_EQ(1U, it.NumDirectMethods()); + const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex()); + const char* name = raw->StringDataByIdx(method_id.name_idx_); + ASSERT_STREQ("<init>", name); + std::string signature(raw->GetMethodSignature(method_id).ToString()); + ASSERT_EQ("()V", signature); + } + + // Check all virtual methods. + struct Result { + const char* name; + const char* signature; + const char* pretty_method; + }; + static const Result results[] = { + { + "m1", + "(IDJLjava/lang/Object;)Ljava/lang/Float;", + "java.lang.Float GetMethodSignature.m1(int, double, long, java.lang.Object)" + }, + { + "m2", + "(ZSC)LGetMethodSignature;", + "GetMethodSignature GetMethodSignature.m2(boolean, short, char)" + }, + { + "m3", + "()V", + "void GetMethodSignature.m3()" + }, + { + "m4", + "(I)V", + "void GetMethodSignature.m4(int)" + }, + { + "m5", + "(II)V", + "void GetMethodSignature.m5(int, int)" + }, + { + "m6", + "(II[[I)V", + "void GetMethodSignature.m6(int, int, int[][])" + }, + { + "m7", + "(II[[ILjava/lang/Object;)V", + "void GetMethodSignature.m7(int, int, int[][], java.lang.Object)" + }, + { + "m8", + "(II[[ILjava/lang/Object;[[Ljava/lang/Object;)V", + "void GetMethodSignature.m8(int, int, int[][], java.lang.Object, java.lang.Object[][])" + }, + { + "m9", + "()I", + "int GetMethodSignature.m9()" + }, + { + "mA", + "()[[I", + "int[][] GetMethodSignature.mA()" + }, + { + "mB", + "()[[Ljava/lang/Object;", + "java.lang.Object[][] GetMethodSignature.mB()" + }, + }; + ASSERT_EQ(arraysize(results), it.NumVirtualMethods()); + for (const Result& r : results) { + it.Next(); + const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex()); + + const char* name = raw->StringDataByIdx(method_id.name_idx_); + ASSERT_STREQ(r.name, name); + + std::string signature(raw->GetMethodSignature(method_id).ToString()); + ASSERT_EQ(r.signature, signature); + + std::string plain_method = std::string("GetMethodSignature.") + r.name; + ASSERT_EQ(plain_method, raw->PrettyMethod(it.GetMemberIndex(), /* with_signature */ false)); + ASSERT_EQ(r.pretty_method, raw->PrettyMethod(it.GetMemberIndex(), /* with_signature */ true)); + } +} + +TEST_F(ArtDexFileLoaderTest, FindStringId) { + ScopedObjectAccess soa(Thread::Current()); + std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature")); + ASSERT_TRUE(raw.get() != nullptr); + EXPECT_EQ(1U, raw->NumClassDefs()); + + const char* strings[] = { "LGetMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;", + "D", "I", "J", nullptr }; + for (size_t i = 0; strings[i] != nullptr; i++) { + const char* str = strings[i]; + const DexFile::StringId* str_id = raw->FindStringId(str); + const char* dex_str = raw->GetStringData(*str_id); + EXPECT_STREQ(dex_str, str); + } +} + +TEST_F(ArtDexFileLoaderTest, FindTypeId) { + for (size_t i = 0; i < java_lang_dex_file_->NumTypeIds(); i++) { + const char* type_str = java_lang_dex_file_->StringByTypeIdx(dex::TypeIndex(i)); + const DexFile::StringId* type_str_id = java_lang_dex_file_->FindStringId(type_str); + ASSERT_TRUE(type_str_id != nullptr); + dex::StringIndex type_str_idx = java_lang_dex_file_->GetIndexForStringId(*type_str_id); + const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId(type_str_idx); + ASSERT_EQ(type_id, java_lang_dex_file_->FindTypeId(type_str)); + ASSERT_TRUE(type_id != nullptr); + EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id).index_, i); + } +} + +TEST_F(ArtDexFileLoaderTest, FindProtoId) { + for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) { + const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i); + const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find); + std::vector<dex::TypeIndex> to_find_types; + if (to_find_tl != nullptr) { + for (size_t j = 0; j < to_find_tl->Size(); j++) { + to_find_types.push_back(to_find_tl->GetTypeItem(j).type_idx_); + } + } + const DexFile::ProtoId* found = + java_lang_dex_file_->FindProtoId(to_find.return_type_idx_, to_find_types); + ASSERT_TRUE(found != nullptr); + EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), i); + } +} + +TEST_F(ArtDexFileLoaderTest, FindMethodId) { + for (size_t i = 0; i < java_lang_dex_file_->NumMethodIds(); i++) { + const DexFile::MethodId& to_find = java_lang_dex_file_->GetMethodId(i); + const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_); + const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_); + const DexFile::ProtoId& signature = java_lang_dex_file_->GetProtoId(to_find.proto_idx_); + const DexFile::MethodId* found = java_lang_dex_file_->FindMethodId(klass, name, signature); + ASSERT_TRUE(found != nullptr) << "Didn't find method " << i << ": " + << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "." + << java_lang_dex_file_->GetStringData(name) + << java_lang_dex_file_->GetMethodSignature(to_find); + EXPECT_EQ(java_lang_dex_file_->GetIndexForMethodId(*found), i); + } +} + +TEST_F(ArtDexFileLoaderTest, FindFieldId) { + for (size_t i = 0; i < java_lang_dex_file_->NumFieldIds(); i++) { + const DexFile::FieldId& to_find = java_lang_dex_file_->GetFieldId(i); + const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_); + const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_); + const DexFile::TypeId& type = java_lang_dex_file_->GetTypeId(to_find.type_idx_); + const DexFile::FieldId* found = java_lang_dex_file_->FindFieldId(klass, name, type); + ASSERT_TRUE(found != nullptr) << "Didn't find field " << i << ": " + << java_lang_dex_file_->StringByTypeIdx(to_find.type_idx_) << " " + << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "." + << java_lang_dex_file_->GetStringData(name); + EXPECT_EQ(java_lang_dex_file_->GetIndexForFieldId(*found), i); + } +} + +TEST_F(ArtDexFileLoaderTest, GetDexCanonicalLocation) { + ScratchFile file; + UniqueCPtr<const char[]> dex_location_real(realpath(file.GetFilename().c_str(), nullptr)); + std::string dex_location(dex_location_real.get()); + + ASSERT_EQ(dex_location, DexFileLoader::GetDexCanonicalLocation(dex_location.c_str())); + std::string multidex_location = DexFileLoader::GetMultiDexLocation(1, dex_location.c_str()); + ASSERT_EQ(multidex_location, DexFileLoader::GetDexCanonicalLocation(multidex_location.c_str())); + + std::string dex_location_sym = dex_location + "symlink"; + ASSERT_EQ(0, symlink(dex_location.c_str(), dex_location_sym.c_str())); + + ASSERT_EQ(dex_location, DexFileLoader::GetDexCanonicalLocation(dex_location_sym.c_str())); + + std::string multidex_location_sym = DexFileLoader::GetMultiDexLocation( + 1, dex_location_sym.c_str()); + ASSERT_EQ(multidex_location, + DexFileLoader::GetDexCanonicalLocation(multidex_location_sym.c_str())); + + ASSERT_EQ(0, unlink(dex_location_sym.c_str())); +} + +} // namespace art diff --git a/runtime/dex/code_item_accessors-no_art-inl.h b/runtime/dex/code_item_accessors-no_art-inl.h deleted file mode 100644 index 8082be3818..0000000000 --- a/runtime/dex/code_item_accessors-no_art-inl.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2017 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_DEX_CODE_ITEM_ACCESSORS_NO_ART_INL_H_ -#define ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_NO_ART_INL_H_ - -// TODO: delete this file once system/core is updated. -#include "code_item_accessors-inl.h" - -#endif // ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_NO_ART_INL_H_ diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc index e01890f541..3431bb7efb 100644 --- a/runtime/dex/dex_file_annotations.cc +++ b/runtime/dex/dex_file_annotations.cc @@ -23,7 +23,7 @@ #include "art_field-inl.h" #include "art_method-inl.h" #include "class_linker-inl.h" -#include "dex_file-inl.h" +#include "dex/dex_file-inl.h" #include "jni_internal.h" #include "jvalue-inl.h" #include "mirror/field.h" diff --git a/runtime/dex/dex_file_annotations.h b/runtime/dex/dex_file_annotations.h index 26773729c2..d7ebf84b1c 100644 --- a/runtime/dex/dex_file_annotations.h +++ b/runtime/dex/dex_file_annotations.h @@ -17,7 +17,7 @@ #ifndef ART_RUNTIME_DEX_DEX_FILE_ANNOTATIONS_H_ #define ART_RUNTIME_DEX_DEX_FILE_ANNOTATIONS_H_ -#include "dex_file.h" +#include "dex/dex_file.h" #include "handle.h" #include "mirror/dex_cache.h" diff --git a/runtime/dex/dex_file_layout.cc b/runtime/dex/dex_file_layout.cc index 312898d82f..d85d61d56b 100644 --- a/runtime/dex/dex_file_layout.cc +++ b/runtime/dex/dex_file_layout.cc @@ -19,8 +19,7 @@ #include <sys/mman.h> #include "base/file_utils.h" -#include "descriptors_names.h" -#include "dex_file.h" +#include "dex/dex_file.h" namespace art { diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc index 037d1fb49c..8ce7921287 100644 --- a/runtime/dexopt_test.cc +++ b/runtime/dexopt_test.cc @@ -49,7 +49,8 @@ void DexoptTest::GenerateOatForTest(const std::string& dex_location, CompilerFilter::Filter filter, bool relocate, bool pic, - bool with_alternate_image) { + bool with_alternate_image, + const char* compilation_reason) { std::string dalvik_cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA)); std::string dalvik_cache_tmp = dalvik_cache + ".redirected"; std::string oat_location = oat_location_in; @@ -89,6 +90,10 @@ void DexoptTest::GenerateOatForTest(const std::string& dex_location, args.push_back("--boot-image=" + GetImageLocation2()); } + if (compilation_reason != nullptr) { + args.push_back("--compilation-reason=" + std::string(compilation_reason)); + } + std::string error_msg; ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg; @@ -155,13 +160,15 @@ void DexoptTest::GenerateOdexForTest(const std::string& dex_location, void DexoptTest::GeneratePicOdexForTest(const std::string& dex_location, const std::string& odex_location, - CompilerFilter::Filter filter) { + CompilerFilter::Filter filter, + const char* compilation_reason) { GenerateOatForTest(dex_location, odex_location, filter, /*relocate*/false, /*pic*/true, - /*with_alternate_image*/false); + /*with_alternate_image*/false, + compilation_reason); } void DexoptTest::GenerateOatForTest(const char* dex_location, diff --git a/runtime/dexopt_test.h b/runtime/dexopt_test.h index 5f0eafd8eb..6e8dc097d5 100644 --- a/runtime/dexopt_test.h +++ b/runtime/dexopt_test.h @@ -46,7 +46,8 @@ class DexoptTest : public Dex2oatEnvironmentTest { CompilerFilter::Filter filter, bool relocate, bool pic, - bool with_alternate_image); + bool with_alternate_image, + const char* compilation_reason = nullptr); // Generate a non-PIC odex file for the purposes of test. // The generated odex file will be un-relocated. @@ -56,7 +57,8 @@ class DexoptTest : public Dex2oatEnvironmentTest { void GeneratePicOdexForTest(const std::string& dex_location, const std::string& odex_location, - CompilerFilter::Filter filter); + CompilerFilter::Filter filter, + const char* compilation_reason = nullptr); // Generate an oat file for the given dex location in its oat location (under // the dalvik cache). diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index 9ef7d426df..404c5357bf 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -99,14 +99,13 @@ inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method, << "This must be due to playing wrongly with class loaders"; } - inlined_method = klass->FindClassMethod(dex_cache, method_index, kRuntimePointerSize); + inlined_method = class_linker->FindResolvedMethod(klass, dex_cache, class_loader, method_index); if (inlined_method == nullptr) { LOG(FATAL) << "Could not find an inlined method from an .oat file: the class " << descriptor << " does not have " << dex_file->GetMethodName(method_id) << dex_file->GetMethodSignature(method_id) << " declared. " << "This must be due to duplicate classes or playing wrongly with class loaders"; } - dex_cache->SetResolvedMethod(method_index, inlined_method, kRuntimePointerSize); return inlined_method; } diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index c5157ce9f4..a8c328fbc7 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -319,7 +319,7 @@ class QuickArgumentVisitor { // 'this' object is the 1st argument. They also have the same frame layout as the // kRefAndArgs runtime method. Since 'this' is a reference, it is located in the // 1st GPR. - static mirror::Object* GetProxyThisObject(ArtMethod** sp) + static StackReference<mirror::Object>* GetProxyThisObjectReference(ArtMethod** sp) REQUIRES_SHARED(Locks::mutator_lock_) { CHECK((*sp)->IsProxyMethod()); CHECK_GT(kNumQuickGprArgs, 0u); @@ -327,7 +327,7 @@ class QuickArgumentVisitor { size_t this_arg_offset = kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset + GprIndexToGprOffset(kThisGprIndex); uint8_t* this_arg_address = reinterpret_cast<uint8_t*>(sp) + this_arg_offset; - return reinterpret_cast<StackReference<mirror::Object>*>(this_arg_address)->AsMirrorPtr(); + return reinterpret_cast<StackReference<mirror::Object>*>(this_arg_address); } static ArtMethod* GetCallingMethod(ArtMethod** sp) REQUIRES_SHARED(Locks::mutator_lock_) { @@ -647,7 +647,11 @@ class QuickArgumentVisitor { // allows to use the QuickArgumentVisitor constants without moving all the code in its own module. extern "C" mirror::Object* artQuickGetProxyThisObject(ArtMethod** sp) REQUIRES_SHARED(Locks::mutator_lock_) { - return QuickArgumentVisitor::GetProxyThisObject(sp); + return QuickArgumentVisitor::GetProxyThisObjectReference(sp)->AsMirrorPtr(); +} +extern "C" StackReference<mirror::Object>* artQuickGetProxyThisObjectReference(ArtMethod** sp) + REQUIRES_SHARED(Locks::mutator_lock_) { + return QuickArgumentVisitor::GetProxyThisObjectReference(sp); } // Visits arguments on the stack placing them into the shadow frame. diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h index 72eb8274c8..f8d8271335 100644 --- a/runtime/gc/accounting/atomic_stack.h +++ b/runtime/gc/accounting/atomic_stack.h @@ -41,7 +41,7 @@ namespace art { namespace gc { namespace accounting { -// Internal representation is StackReference<T>, so this only works with mirror::Object or it's +// Internal representation is StackReference<T>, so this only works with mirror::Object or its // subclasses. template <typename T> class AtomicStack { diff --git a/runtime/gc/accounting/space_bitmap-inl.h b/runtime/gc/accounting/space_bitmap-inl.h index df9ee8c219..354b9e1dbd 100644 --- a/runtime/gc/accounting/space_bitmap-inl.h +++ b/runtime/gc/accounting/space_bitmap-inl.h @@ -62,7 +62,8 @@ inline bool SpaceBitmap<kAlignment>::Test(const mirror::Object* obj) const { return (bitmap_begin_[OffsetToIndex(offset)].LoadRelaxed() & OffsetToMask(offset)) != 0; } -template<size_t kAlignment> template<typename Visitor> +template<size_t kAlignment> +template<typename Visitor> inline void SpaceBitmap<kAlignment>::VisitMarkedRange(uintptr_t visit_begin, uintptr_t visit_end, Visitor&& visitor) const { @@ -121,6 +122,7 @@ inline void SpaceBitmap<kAlignment>::VisitMarkedRange(uintptr_t visit_begin, uintptr_t w = bitmap_begin_[i].LoadRelaxed(); if (w != 0) { const uintptr_t ptr_base = IndexToOffset(i) + heap_begin_; + // Iterate on the bits set in word `w`, from the least to the most significant bit. do { const size_t shift = CTZ(w); mirror::Object* obj = reinterpret_cast<mirror::Object*>(ptr_base + shift * kAlignment); @@ -147,6 +149,7 @@ inline void SpaceBitmap<kAlignment>::VisitMarkedRange(uintptr_t visit_begin, right_edge &= ((static_cast<uintptr_t>(1) << bit_end) - 1); if (right_edge != 0) { const uintptr_t ptr_base = IndexToOffset(index_end) + heap_begin_; + // Iterate on the bits set in word `right_edge`, from the least to the most significant bit. do { const size_t shift = CTZ(right_edge); mirror::Object* obj = reinterpret_cast<mirror::Object*>(ptr_base + shift * kAlignment); @@ -157,7 +160,8 @@ inline void SpaceBitmap<kAlignment>::VisitMarkedRange(uintptr_t visit_begin, #endif } -template<size_t kAlignment> template<typename Visitor> +template<size_t kAlignment> +template<typename Visitor> void SpaceBitmap<kAlignment>::Walk(Visitor&& visitor) { CHECK(bitmap_begin_ != nullptr); @@ -177,7 +181,8 @@ void SpaceBitmap<kAlignment>::Walk(Visitor&& visitor) { } } -template<size_t kAlignment> template<bool kSetBit> +template<size_t kAlignment> +template<bool kSetBit> inline bool SpaceBitmap<kAlignment>::Modify(const mirror::Object* obj) { uintptr_t addr = reinterpret_cast<uintptr_t>(obj); DCHECK_GE(addr, heap_begin_); diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc index 237ee80ba0..0247564a8c 100644 --- a/runtime/gc/accounting/space_bitmap.cc +++ b/runtime/gc/accounting/space_bitmap.cc @@ -33,7 +33,12 @@ using android::base::StringPrintf; template<size_t kAlignment> size_t SpaceBitmap<kAlignment>::ComputeBitmapSize(uint64_t capacity) { + // Number of space (heap) bytes covered by one bitmap word. + // (Word size in bytes = `sizeof(intptr_t)`, which is expected to be + // 4 on a 32-bit architecture and 8 on a 64-bit one.) const uint64_t kBytesCoveredPerWord = kAlignment * kBitsPerIntPtrT; + // Calculate the number of words required to cover a space (heap) + // having a size of `capacity` bytes. return (RoundUp(capacity, kBytesCoveredPerWord) / kBytesCoveredPerWord) * sizeof(intptr_t); } @@ -74,7 +79,8 @@ SpaceBitmap<kAlignment>::~SpaceBitmap() {} template<size_t kAlignment> SpaceBitmap<kAlignment>* SpaceBitmap<kAlignment>::Create( const std::string& name, uint8_t* heap_begin, size_t heap_capacity) { - // Round up since heap_capacity is not necessarily a multiple of kAlignment * kBitsPerWord. + // Round up since `heap_capacity` is not necessarily a multiple of `kAlignment * kBitsPerIntPtrT` + // (we represent one word as an `intptr_t`). const size_t bitmap_size = ComputeBitmapSize(heap_capacity); std::string error_msg; std::unique_ptr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), nullptr, bitmap_size, @@ -116,7 +122,7 @@ template<size_t kAlignment> void SpaceBitmap<kAlignment>::ClearRange(const mirror::Object* begin, const mirror::Object* end) { uintptr_t begin_offset = reinterpret_cast<uintptr_t>(begin) - heap_begin_; uintptr_t end_offset = reinterpret_cast<uintptr_t>(end) - heap_begin_; - // Align begin and end to word boundaries. + // Align begin and end to bitmap word boundaries. while (begin_offset < end_offset && OffsetBitIndex(begin_offset) != 0) { Clear(reinterpret_cast<mirror::Object*>(heap_begin_ + begin_offset)); begin_offset += kAlignment; @@ -125,6 +131,7 @@ void SpaceBitmap<kAlignment>::ClearRange(const mirror::Object* begin, const mirr end_offset -= kAlignment; Clear(reinterpret_cast<mirror::Object*>(heap_begin_ + end_offset)); } + // Bitmap word boundaries. const uintptr_t start_index = OffsetToIndex(begin_offset); const uintptr_t end_index = OffsetToIndex(end_offset); ZeroAndReleasePages(reinterpret_cast<uint8_t*>(&bitmap_begin_[start_index]), diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h index 2f33bac902..437aecc2b1 100644 --- a/runtime/gc/accounting/space_bitmap.h +++ b/runtime/gc/accounting/space_bitmap.h @@ -55,6 +55,10 @@ class SpaceBitmap { ~SpaceBitmap(); + // Return the bitmap word index corresponding to memory offset (relative to + // `HeapBegin()`) `offset`. + // See also SpaceBitmap::OffsetBitIndex. + // // <offset> is the difference from .base to a pointer address. // <index> is the index of .bits that contains the bit representing // <offset>. @@ -62,24 +66,32 @@ class SpaceBitmap { return offset / kAlignment / kBitsPerIntPtrT; } + // Return the memory offset (relative to `HeapBegin()`) corresponding to + // bitmap word index `index`. template<typename T> static constexpr T IndexToOffset(T index) { return static_cast<T>(index * kAlignment * kBitsPerIntPtrT); } + // Return the bit within the bitmap word index corresponding to + // memory offset (relative to `HeapBegin()`) `offset`. + // See also SpaceBitmap::OffsetToIndex. ALWAYS_INLINE static constexpr uintptr_t OffsetBitIndex(uintptr_t offset) { return (offset / kAlignment) % kBitsPerIntPtrT; } + // Return the word-wide bit mask corresponding to `OffsetBitIndex(offset)`. // Bits are packed in the obvious way. static constexpr uintptr_t OffsetToMask(uintptr_t offset) { return static_cast<size_t>(1) << OffsetBitIndex(offset); } + // Set the bit corresponding to `obj` in the bitmap and return the previous value of that bit. bool Set(const mirror::Object* obj) ALWAYS_INLINE { return Modify<true>(obj); } + // Clear the bit corresponding to `obj` in the bitmap and return the previous value of that bit. bool Clear(const mirror::Object* obj) ALWAYS_INLINE { return Modify<false>(obj); } @@ -90,9 +102,14 @@ class SpaceBitmap { // Fill the bitmap with zeroes. Returns the bitmap's memory to the system as a side-effect. void Clear(); - // Clear a covered by the bitmap using madvise if possible. + // Clear a range covered by the bitmap using madvise if possible. void ClearRange(const mirror::Object* begin, const mirror::Object* end); + // Test whether `obj` is part of the bitmap (i.e. return whether the bit + // corresponding to `obj` has been set in the bitmap). + // + // Precondition: `obj` is within the range of pointers that this bitmap could + // potentially cover (i.e. `this->HasAddress(obj)` is true) bool Test(const mirror::Object* obj) const; // Return true iff <obj> is within the range of pointers that this bitmap could potentially cover, @@ -204,6 +221,8 @@ class SpaceBitmap { const void* heap_begin, size_t heap_capacity); + // Change the value of the bit corresponding to `obj` in the bitmap + // to `kSetBit` and return the previous value of that bit. template<bool kSetBit> bool Modify(const mirror::Object* obj); diff --git a/runtime/gc/accounting/space_bitmap_test.cc b/runtime/gc/accounting/space_bitmap_test.cc index bd5f77ebb1..1ca3fd6d12 100644 --- a/runtime/gc/accounting/space_bitmap_test.cc +++ b/runtime/gc/accounting/space_bitmap_test.cc @@ -74,7 +74,7 @@ TEST_F(SpaceBitmapTest, ScanRange) { } } // Try every possible starting bit in the first word. Then for each starting bit, try each - // possible length up to a maximum of kBitsPerWord * 2 - 1 bits. + // possible length up to a maximum of `kBitsPerIntPtrT * 2 - 1` bits. // This handles all the cases, having runs which start and end on the same word, and different // words. for (size_t i = 0; i < static_cast<size_t>(kBitsPerIntPtrT); ++i) { diff --git a/runtime/gc/collector/concurrent_copying-inl.h b/runtime/gc/collector/concurrent_copying-inl.h index 85a656ec51..d739ed2867 100644 --- a/runtime/gc/collector/concurrent_copying-inl.h +++ b/runtime/gc/collector/concurrent_copying-inl.h @@ -52,7 +52,8 @@ inline mirror::Object* ConcurrentCopying::MarkUnevacFromSpaceRegion( // we can avoid an expensive CAS. // For the baker case, an object is marked if either the mark bit marked or the bitmap bit is // set. - success = ref->AtomicSetReadBarrierState(ReadBarrier::WhiteState(), ReadBarrier::GrayState()); + success = ref->AtomicSetReadBarrierState(/* expected_rb_state */ ReadBarrier::WhiteState(), + /* rb_state */ ReadBarrier::GrayState()); } else { success = !bitmap->AtomicTestAndSet(ref); } @@ -86,8 +87,8 @@ inline mirror::Object* ConcurrentCopying::MarkImmuneSpace(mirror::Object* ref) { return ref; } // This may or may not succeed, which is ok because the object may already be gray. - bool success = ref->AtomicSetReadBarrierState(ReadBarrier::WhiteState(), - ReadBarrier::GrayState()); + bool success = ref->AtomicSetReadBarrierState(/* expected_rb_state */ ReadBarrier::WhiteState(), + /* rb_state */ ReadBarrier::GrayState()); if (success) { MutexLock mu(Thread::Current(), immune_gray_stack_lock_); immune_gray_stack_.push_back(ref); @@ -133,6 +134,8 @@ inline mirror::Object* ConcurrentCopying::Mark(mirror::Object* from_ref, // It isn't marked yet. Mark it by copying it to the to-space. to_ref = Copy(from_ref, holder, offset); } + // The copy should either be in a to-space region, or in the + // non-moving space, if it could not fit in a to-space region. DCHECK(region_space_->IsInToSpace(to_ref) || heap_->non_moving_space_->HasAddress(to_ref)) << "from_ref=" << from_ref << " to_ref=" << to_ref; return to_ref; diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc index 1e0c0b16e4..3770085c07 100644 --- a/runtime/gc/collector/concurrent_copying.cc +++ b/runtime/gc/collector/concurrent_copying.cc @@ -347,8 +347,9 @@ class ConcurrentCopying::ThreadFlipVisitor : public Closure, public RootVisitor // This must come before the revoke. size_t thread_local_objects = thread->GetThreadLocalObjectsAllocated(); concurrent_copying_->region_space_->RevokeThreadLocalBuffers(thread); - reinterpret_cast<Atomic<size_t>*>(&concurrent_copying_->from_space_num_objects_at_first_pause_)-> - FetchAndAddSequentiallyConsistent(thread_local_objects); + reinterpret_cast<Atomic<size_t>*>( + &concurrent_copying_->from_space_num_objects_at_first_pause_)-> + FetchAndAddSequentiallyConsistent(thread_local_objects); } else { concurrent_copying_->region_space_->RevokeThreadLocalBuffers(thread); } @@ -440,7 +441,7 @@ class ConcurrentCopying::FlipCallback : public Closure { if (kUseBakerReadBarrier && kGrayDirtyImmuneObjects) { cc->GrayAllNewlyDirtyImmuneObjects(); if (kIsDebugBuild) { - // Check that all non-gray immune objects only refernce immune objects. + // Check that all non-gray immune objects only reference immune objects. cc->VerifyGrayImmuneObjects(); } } @@ -1534,7 +1535,8 @@ inline void ConcurrentCopying::ProcessMarkStackRef(mirror::Object* to_ref) { !IsInToSpace(referent)))) { // Leave this reference gray in the queue so that GetReferent() will trigger a read barrier. We // will change it to white later in ReferenceQueue::DequeuePendingReference(). - DCHECK(to_ref->AsReference()->GetPendingNext() != nullptr) << "Left unenqueued ref gray " << to_ref; + DCHECK(to_ref->AsReference()->GetPendingNext() != nullptr) + << "Left unenqueued ref gray " << to_ref; } else { // We may occasionally leave a reference white in the queue if its referent happens to be // concurrently marked after the Scan() call above has enqueued the Reference, in which case the @@ -1552,7 +1554,7 @@ inline void ConcurrentCopying::ProcessMarkStackRef(mirror::Object* to_ref) { #endif if (add_to_live_bytes) { - // Add to the live bytes per unevacuated from space. Note this code is always run by the + // Add to the live bytes per unevacuated from-space. Note this code is always run by the // GC-running thread (no synchronization required). DCHECK(region_space_bitmap_->Test(to_ref)); size_t obj_size = to_ref->SizeOf<kDefaultVerifyFlags>(); @@ -1759,13 +1761,14 @@ void ConcurrentCopying::ReclaimPhase() { } CHECK_LE(to_objects, from_objects); CHECK_LE(to_bytes, from_bytes); - // cleared_bytes and cleared_objects may be greater than the from space equivalents since - // ClearFromSpace may clear empty unevac regions. + // Cleared bytes and objects, populated by the call to RegionSpace::ClearFromSpace below. uint64_t cleared_bytes; uint64_t cleared_objects; { TimingLogger::ScopedTiming split4("ClearFromSpace", GetTimings()); region_space_->ClearFromSpace(&cleared_bytes, &cleared_objects); + // `cleared_bytes` and `cleared_objects` may be greater than the from space equivalents since + // RegionSpace::ClearFromSpace may clear empty unevac regions. CHECK_GE(cleared_bytes, from_bytes); CHECK_GE(cleared_objects, from_objects); } @@ -1774,17 +1777,20 @@ void ConcurrentCopying::ReclaimPhase() { if (kVerboseMode) { LOG(INFO) << "RecordFree:" << " from_bytes=" << from_bytes << " from_objects=" << from_objects - << " unevac_from_bytes=" << unevac_from_bytes << " unevac_from_objects=" << unevac_from_objects + << " unevac_from_bytes=" << unevac_from_bytes + << " unevac_from_objects=" << unevac_from_objects << " to_bytes=" << to_bytes << " to_objects=" << to_objects << " freed_bytes=" << freed_bytes << " freed_objects=" << freed_objects << " from_space size=" << region_space_->FromSpaceSize() << " unevac_from_space size=" << region_space_->UnevacFromSpaceSize() << " to_space size=" << region_space_->ToSpaceSize(); - LOG(INFO) << "(before) num_bytes_allocated=" << heap_->num_bytes_allocated_.LoadSequentiallyConsistent(); + LOG(INFO) << "(before) num_bytes_allocated=" + << heap_->num_bytes_allocated_.LoadSequentiallyConsistent(); } RecordFree(ObjectBytePair(freed_objects, freed_bytes)); if (kVerboseMode) { - LOG(INFO) << "(after) num_bytes_allocated=" << heap_->num_bytes_allocated_.LoadSequentiallyConsistent(); + LOG(INFO) << "(after) num_bytes_allocated=" + << heap_->num_bytes_allocated_.LoadSequentiallyConsistent(); } } @@ -1806,27 +1812,82 @@ void ConcurrentCopying::ReclaimPhase() { } } -// Assert the to-space invariant. +std::string ConcurrentCopying::DumpReferenceInfo(mirror::Object* ref, + const char* ref_name, + std::string indent) { + std::ostringstream oss; + oss << indent << heap_->GetVerification()->DumpObjectInfo(ref, ref_name) << '\n'; + if (ref != nullptr) { + if (kUseBakerReadBarrier) { + oss << indent << ref_name << "->GetMarkBit()=" << ref->GetMarkBit() << '\n'; + oss << indent << ref_name << "->GetReadBarrierState()=" << ref->GetReadBarrierState() << '\n'; + } + } + if (region_space_->HasAddress(ref)) { + oss << indent << "Region containing " << ref_name << ":" << '\n'; + region_space_->DumpRegionForObject(oss, ref); + if (region_space_bitmap_ != nullptr) { + oss << indent << "region_space_bitmap_->Test(" << ref_name << ")=" + << std::boolalpha << region_space_bitmap_->Test(ref) << std::noboolalpha; + } + } + return oss.str(); +} + +std::string ConcurrentCopying::DumpHeapReference(mirror::Object* obj, + MemberOffset offset, + mirror::Object* ref) { + std::ostringstream oss; + std::string indent = " "; + oss << indent << "Invalid reference: ref=" << ref + << " referenced from: object=" << obj << " offset= " << offset << '\n'; + // Information about `obj`. + oss << DumpReferenceInfo(obj, "obj", indent) << '\n'; + // Information about `ref`. + oss << DumpReferenceInfo(ref, "ref", indent); + return oss.str(); +} + void ConcurrentCopying::AssertToSpaceInvariant(mirror::Object* obj, MemberOffset offset, mirror::Object* ref) { - CHECK_EQ(heap_->collector_type_, kCollectorTypeCC); + CHECK_EQ(heap_->collector_type_, kCollectorTypeCC) << static_cast<size_t>(heap_->collector_type_); if (is_asserting_to_space_invariant_) { - using RegionType = space::RegionSpace::RegionType; - space::RegionSpace::RegionType type = region_space_->GetRegionType(ref); - if (type == RegionType::kRegionTypeToSpace) { - // OK. - return; - } else if (type == RegionType::kRegionTypeUnevacFromSpace) { - CHECK(IsMarkedInUnevacFromSpace(ref)) << ref; - } else if (UNLIKELY(type == RegionType::kRegionTypeFromSpace)) { - // Not OK. Do extra logging. - if (obj != nullptr) { - LogFromSpaceRefHolder(obj, offset); + if (region_space_->HasAddress(ref)) { + // Check to-space invariant in region space (moving space). + using RegionType = space::RegionSpace::RegionType; + space::RegionSpace::RegionType type = region_space_->GetRegionType(ref); + if (type == RegionType::kRegionTypeToSpace) { + // OK. + return; + } else if (type == RegionType::kRegionTypeUnevacFromSpace) { + if (!IsMarkedInUnevacFromSpace(ref)) { + LOG(FATAL_WITHOUT_ABORT) << "Found unmarked reference in unevac from-space:"; + LOG(FATAL_WITHOUT_ABORT) << DumpHeapReference(obj, offset, ref); + } + CHECK(IsMarkedInUnevacFromSpace(ref)) << ref; + } else { + // Not OK: either a from-space ref or a reference in an unused region. + // Do extra logging. + if (type == RegionType::kRegionTypeFromSpace) { + LOG(FATAL_WITHOUT_ABORT) << "Found from-space reference:"; + } else { + LOG(FATAL_WITHOUT_ABORT) << "Found reference in region with type " << type << ":"; + } + LOG(FATAL_WITHOUT_ABORT) << DumpHeapReference(obj, offset, ref); + if (obj != nullptr) { + LogFromSpaceRefHolder(obj, offset); + } + ref->GetLockWord(false).Dump(LOG_STREAM(FATAL_WITHOUT_ABORT)); + LOG(FATAL_WITHOUT_ABORT) << "Non-free regions:"; + region_space_->DumpNonFreeRegions(LOG_STREAM(FATAL_WITHOUT_ABORT)); + PrintFileToLog("/proc/self/maps", LogSeverity::FATAL_WITHOUT_ABORT); + MemMap::DumpMaps(LOG_STREAM(FATAL_WITHOUT_ABORT), true); + LOG(FATAL) << "Invalid reference " << ref + << " referenced from object " << obj << " at offset " << offset; } - ref->GetLockWord(false).Dump(LOG_STREAM(FATAL_WITHOUT_ABORT)); - CHECK(false) << "Found from-space ref " << ref << " " << ref->PrettyTypeOf(); } else { + // Check to-space invariant in non-moving space. AssertToSpaceInvariantInNonMovingSpace(obj, ref); } } @@ -1857,39 +1918,66 @@ class RootPrinter { } }; +std::string ConcurrentCopying::DumpGcRoot(mirror::Object* ref) { + std::ostringstream oss; + std::string indent = " "; + oss << indent << "Invalid GC root: ref=" << ref << '\n'; + // Information about `ref`. + oss << DumpReferenceInfo(ref, "ref", indent); + return oss.str(); +} + void ConcurrentCopying::AssertToSpaceInvariant(GcRootSource* gc_root_source, mirror::Object* ref) { - CHECK(heap_->collector_type_ == kCollectorTypeCC) << static_cast<size_t>(heap_->collector_type_); + CHECK_EQ(heap_->collector_type_, kCollectorTypeCC) << static_cast<size_t>(heap_->collector_type_); if (is_asserting_to_space_invariant_) { - if (region_space_->IsInToSpace(ref)) { - // OK. - return; - } else if (region_space_->IsInUnevacFromSpace(ref)) { - CHECK(IsMarkedInUnevacFromSpace(ref)) << ref; - } else if (region_space_->IsInFromSpace(ref)) { - // Not OK. Do extra logging. - if (gc_root_source == nullptr) { - // No info. - } else if (gc_root_source->HasArtField()) { - ArtField* field = gc_root_source->GetArtField(); - LOG(FATAL_WITHOUT_ABORT) << "gc root in field " << field << " " - << ArtField::PrettyField(field); - RootPrinter root_printer; - field->VisitRoots(root_printer); - } else if (gc_root_source->HasArtMethod()) { - ArtMethod* method = gc_root_source->GetArtMethod(); - LOG(FATAL_WITHOUT_ABORT) << "gc root in method " << method << " " - << ArtMethod::PrettyMethod(method); - RootPrinter root_printer; - method->VisitRoots(root_printer, kRuntimePointerSize); + if (region_space_->HasAddress(ref)) { + // Check to-space invariant in region space (moving space). + using RegionType = space::RegionSpace::RegionType; + space::RegionSpace::RegionType type = region_space_->GetRegionType(ref); + if (type == RegionType::kRegionTypeToSpace) { + // OK. + return; + } else if (type == RegionType::kRegionTypeUnevacFromSpace) { + if (!IsMarkedInUnevacFromSpace(ref)) { + LOG(FATAL_WITHOUT_ABORT) << "Found unmarked reference in unevac from-space:"; + LOG(FATAL_WITHOUT_ABORT) << DumpGcRoot(ref); + } + CHECK(IsMarkedInUnevacFromSpace(ref)) << ref; + } else { + // Not OK: either a from-space ref or a reference in an unused region. + // Do extra logging. + if (type == RegionType::kRegionTypeFromSpace) { + LOG(FATAL_WITHOUT_ABORT) << "Found from-space reference:"; + } else { + LOG(FATAL_WITHOUT_ABORT) << "Found reference in region with type " << type << ":"; + } + LOG(FATAL_WITHOUT_ABORT) << DumpGcRoot(ref); + if (gc_root_source == nullptr) { + // No info. + } else if (gc_root_source->HasArtField()) { + ArtField* field = gc_root_source->GetArtField(); + LOG(FATAL_WITHOUT_ABORT) << "gc root in field " << field << " " + << ArtField::PrettyField(field); + RootPrinter root_printer; + field->VisitRoots(root_printer); + } else if (gc_root_source->HasArtMethod()) { + ArtMethod* method = gc_root_source->GetArtMethod(); + LOG(FATAL_WITHOUT_ABORT) << "gc root in method " << method << " " + << ArtMethod::PrettyMethod(method); + RootPrinter root_printer; + method->VisitRoots(root_printer, kRuntimePointerSize); + } + ref->GetLockWord(false).Dump(LOG_STREAM(FATAL_WITHOUT_ABORT)); + LOG(FATAL_WITHOUT_ABORT) << "Non-free regions:"; + region_space_->DumpNonFreeRegions(LOG_STREAM(FATAL_WITHOUT_ABORT)); + PrintFileToLog("/proc/self/maps", LogSeverity::FATAL_WITHOUT_ABORT); + MemMap::DumpMaps(LOG_STREAM(FATAL_WITHOUT_ABORT), true); + LOG(FATAL) << "Invalid reference " << ref; } - ref->GetLockWord(false).Dump(LOG_STREAM(FATAL_WITHOUT_ABORT)); - region_space_->DumpNonFreeRegions(LOG_STREAM(FATAL_WITHOUT_ABORT)); - PrintFileToLog("/proc/self/maps", LogSeverity::FATAL_WITHOUT_ABORT); - MemMap::DumpMaps(LOG_STREAM(FATAL_WITHOUT_ABORT), true); - CHECK(false) << "Found from-space ref " << ref << " " << ref->PrettyTypeOf(); } else { - AssertToSpaceInvariantInNonMovingSpace(nullptr, ref); + // Check to-space invariant in non-moving space. + AssertToSpaceInvariantInNonMovingSpace(/* obj */ nullptr, ref); } } } @@ -1944,7 +2032,8 @@ void ConcurrentCopying::LogFromSpaceRefHolder(mirror::Object* obj, MemberOffset void ConcurrentCopying::AssertToSpaceInvariantInNonMovingSpace(mirror::Object* obj, mirror::Object* ref) { - // In a non-moving spaces. Check that the ref is marked. + CHECK(!region_space_->HasAddress(ref)) << "obj=" << obj << " ref=" << ref; + // In a non-moving space. Check that the ref is marked. if (immune_spaces_.ContainsObject(ref)) { if (kUseBakerReadBarrier) { // Immune object may not be gray if called from the GC. @@ -1968,11 +2057,13 @@ void ConcurrentCopying::AssertToSpaceInvariantInNonMovingSpace(mirror::Object* o (is_los && los_bitmap->Test(ref))) { // OK. } else { - // If ref is on the allocation stack, then it may not be + // If `ref` is on the allocation stack, then it may not be // marked live, but considered marked/alive (but not // necessarily on the live stack). - CHECK(IsOnAllocStack(ref)) << "Unmarked ref that's not on the allocation stack. " - << "obj=" << obj << " ref=" << ref; + CHECK(IsOnAllocStack(ref)) << "Unmarked ref that's not on the allocation stack." + << " obj=" << obj + << " ref=" << ref + << " is_los=" << std::boolalpha << is_los << std::noboolalpha; } } } @@ -2013,7 +2104,6 @@ class ConcurrentCopying::RefFieldsVisitor { ConcurrentCopying* const collector_; }; -// Scan ref fields of an object. inline void ConcurrentCopying::Scan(mirror::Object* to_ref) { if (kDisallowReadBarrierDuringScan && !Runtime::Current()->IsActiveTransaction()) { // Avoid all read barriers during visit references to help performance. @@ -2032,7 +2122,6 @@ inline void ConcurrentCopying::Scan(mirror::Object* to_ref) { } } -// Process a field. inline void ConcurrentCopying::Process(mirror::Object* obj, MemberOffset offset) { DCHECK_EQ(Thread::Current(), thread_running_gc_); mirror::Object* ref = obj->GetFieldObject< @@ -2053,7 +2142,7 @@ inline void ConcurrentCopying::Process(mirror::Object* obj, MemberOffset offset) // It was updated by the mutator. break; } - // Use release cas to make sure threads reading the reference see contents of copied objects. + // Use release CAS to make sure threads reading the reference see contents of copied objects. } while (!obj->CasFieldWeakReleaseObjectWithoutWriteBarrier<false, false, kVerifyNone>( offset, expected_ref, @@ -2428,6 +2517,9 @@ mirror::Object* ConcurrentCopying::IsMarked(mirror::Object* from_ref) { to_ref = nullptr; } } else { + // At this point, `from_ref` should not be in the region space + // (i.e. within an "unused" region). + DCHECK(!region_space_->HasAddress(from_ref)) << from_ref; // from_ref is in a non-moving space. if (immune_spaces_.ContainsObject(from_ref)) { // An immune object is alive. @@ -2598,7 +2690,12 @@ void ConcurrentCopying::FinishPhase() { DCHECK(rb_mark_bit_stack_ != nullptr); const auto* limit = rb_mark_bit_stack_->End(); for (StackReference<mirror::Object>* it = rb_mark_bit_stack_->Begin(); it != limit; ++it) { - CHECK(it->AsMirrorPtr()->AtomicSetMarkBit(1, 0)); + CHECK(it->AsMirrorPtr()->AtomicSetMarkBit(1, 0)) + << "rb_mark_bit_stack_->Begin()" << rb_mark_bit_stack_->Begin() << '\n' + << "rb_mark_bit_stack_->End()" << rb_mark_bit_stack_->End() << '\n' + << "rb_mark_bit_stack_->IsFull()" + << std::boolalpha << rb_mark_bit_stack_->IsFull() << std::noboolalpha << '\n' + << DumpReferenceInfo(it->AsMirrorPtr(), "*it"); } rb_mark_bit_stack_->Reset(); } diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h index 8b4b58e7b1..c58dd44648 100644 --- a/runtime/gc/collector/concurrent_copying.h +++ b/runtime/gc/collector/concurrent_copying.h @@ -100,8 +100,10 @@ class ConcurrentCopying : public GarbageCollector { space::RegionSpace* RegionSpace() { return region_space_; } + // Assert the to-space invariant for a heap reference `ref` held in `obj` at offset `offset`. void AssertToSpaceInvariant(mirror::Object* obj, MemberOffset offset, mirror::Object* ref) REQUIRES_SHARED(Locks::mutator_lock_); + // Assert the to-space invariant for a GC root reference `ref`. void AssertToSpaceInvariant(GcRootSource* gc_root_source, mirror::Object* ref) REQUIRES_SHARED(Locks::mutator_lock_); bool IsInToSpace(mirror::Object* ref) REQUIRES_SHARED(Locks::mutator_lock_) { @@ -109,6 +111,7 @@ class ConcurrentCopying : public GarbageCollector { return IsMarked(ref) == ref; } template<bool kGrayImmuneObject = true, bool kFromGCThread = false> + // Mark object `from_ref`, copying it to the to-space if needed. ALWAYS_INLINE mirror::Object* Mark(mirror::Object* from_ref, mirror::Object* holder = nullptr, MemberOffset offset = MemberOffset(0)) @@ -148,8 +151,10 @@ class ConcurrentCopying : public GarbageCollector { MemberOffset offset) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_); + // Scan the reference fields of object `to_ref`. void Scan(mirror::Object* to_ref) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!mark_stack_lock_); + // Process a field. void Process(mirror::Object* obj, MemberOffset offset) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!mark_stack_lock_ , !skipped_blocks_lock_, !immune_gray_stack_lock_); @@ -232,6 +237,16 @@ class ConcurrentCopying : public GarbageCollector { void ComputeUnevacFromSpaceLiveRatio(); void LogFromSpaceRefHolder(mirror::Object* obj, MemberOffset offset) REQUIRES_SHARED(Locks::mutator_lock_); + // Dump information about reference `ref` and return it as a string. + // Use `ref_name` to name the reference in messages. Each message is prefixed with `indent`. + std::string DumpReferenceInfo(mirror::Object* ref, const char* ref_name, std::string indent = "") + REQUIRES_SHARED(Locks::mutator_lock_); + // Dump information about heap reference `ref`, referenced from object `obj` at offset `offset`, + // and return it as a string. + std::string DumpHeapReference(mirror::Object* obj, MemberOffset offset, mirror::Object* ref) + REQUIRES_SHARED(Locks::mutator_lock_); + // Dump information about GC root `ref` and return it as a string. + std::string DumpGcRoot(mirror::Object* ref) REQUIRES_SHARED(Locks::mutator_lock_); void AssertToSpaceInvariantInNonMovingSpace(mirror::Object* obj, mirror::Object* ref) REQUIRES_SHARED(Locks::mutator_lock_); void ReenableWeakRefAccess(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_); @@ -266,8 +281,20 @@ class ConcurrentCopying : public GarbageCollector { space::RegionSpace* region_space_; // The underlying region space. std::unique_ptr<Barrier> gc_barrier_; std::unique_ptr<accounting::ObjectStack> gc_mark_stack_; + + // The read-barrier mark-bit stack. Stores object references whose + // mark bit has been set by ConcurrentCopying::MarkFromReadBarrier, + // so that this bit can be reset at the end of the collection in + // ConcurrentCopying::FinishPhase. The mark bit of an object can be + // used by mutator read barrier code to quickly test whether that + // object has been already marked. std::unique_ptr<accounting::ObjectStack> rb_mark_bit_stack_; + // Thread-unsafe Boolean value hinting that `rb_mark_bit_stack_` is + // full. A thread-safe test of whether the read-barrier mark-bit + // stack is full is implemented by `rb_mark_bit_stack_->AtomicPushBack(ref)` + // (see use case in ConcurrentCopying::MarkFromReadBarrier). bool rb_mark_bit_stack_full_; + std::vector<mirror::Object*> false_gray_stack_ GUARDED_BY(mark_stack_lock_); Mutex mark_stack_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; std::vector<accounting::ObjectStack*> revoked_mark_stacks_ diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc index fdfe949265..9ab965ec78 100644 --- a/runtime/gc/collector/mark_sweep.cc +++ b/runtime/gc/collector/mark_sweep.cc @@ -191,7 +191,7 @@ void MarkSweep::PausePhase() { WriterMutexLock mu(self, *Locks::heap_bitmap_lock_); // Re-mark root set. ReMarkRoots(); - // Scan dirty objects, this is only required if we are not doing concurrent GC. + // Scan dirty objects, this is only required if we are doing concurrent GC. RecursiveMarkDirtyObjects(true, accounting::CardTable::kCardDirty); } { @@ -259,8 +259,30 @@ void MarkSweep::MarkingPhase() { BindBitmaps(); FindDefaultSpaceBitmap(); // Process dirty cards and add dirty cards to mod union tables. - // If the GC type is non sticky, then we just clear the cards instead of ageing them. - heap_->ProcessCards(GetTimings(), false, true, GetGcType() != kGcTypeSticky); + // If the GC type is non sticky, then we just clear the cards of the + // alloc space instead of aging them. + // + // Note that it is fine to clear the cards of the alloc space here, + // in the case of a concurrent (non-sticky) mark-sweep GC (whose + // marking phase _is_ performed concurrently with mutator threads + // running and possibly dirtying cards), as the whole alloc space + // will be traced in that case, starting *after* this call to + // Heap::ProcessCards (see calls to MarkSweep::MarkRoots and + // MarkSweep::MarkReachableObjects). References held by objects on + // cards that became dirty *after* the actual marking work started + // will be marked in the pause (see MarkSweep::PausePhase), in a + // *non-concurrent* way to prevent races with mutator threads. + // + // TODO: Do we need some sort of fence between the call to + // Heap::ProcessCard and the calls to MarkSweep::MarkRoot / + // MarkSweep::MarkReachableObjects below to make sure write + // operations in the card table clearing the alloc space's dirty + // cards (during the call to Heap::ProcessCard) are not reordered + // *after* marking actually starts? + heap_->ProcessCards(GetTimings(), + /* use_rem_sets */ false, + /* process_alloc_space_cards */ true, + /* clear_alloc_space_cards */ GetGcType() != kGcTypeSticky); WriterMutexLock mu(self, *Locks::heap_bitmap_lock_); MarkRoots(self); MarkReachableObjects(); @@ -1287,7 +1309,7 @@ void MarkSweep::Sweep(bool swap_bitmaps) { CHECK_GE(live_stack_freeze_size_, GetHeap()->GetLiveStack()->Size()); { TimingLogger::ScopedTiming t2("MarkAllocStackAsLive", GetTimings()); - // Mark everything allocated since the last as GC live so that we can sweep concurrently, + // Mark everything allocated since the last GC as live so that we can sweep concurrently, // knowing that new allocations won't be marked as live. accounting::ObjectStack* live_stack = heap_->GetLiveStack(); heap_->MarkAllocStackAsLive(live_stack); diff --git a/runtime/gc/collector/sticky_mark_sweep.cc b/runtime/gc/collector/sticky_mark_sweep.cc index b66095fc2a..d93bd89835 100644 --- a/runtime/gc/collector/sticky_mark_sweep.cc +++ b/runtime/gc/collector/sticky_mark_sweep.cc @@ -63,7 +63,7 @@ void StickyMarkSweep::MarkReachableObjects() { void StickyMarkSweep::MarkConcurrentRoots(VisitRootFlags flags) { TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings()); // Visit all runtime roots and clear dirty flags including class loader. This is done to prevent - // incorrect class unloading since the GC does not card mark when storing store the class during + // incorrect class unloading since the GC does not card mark when storing the class during // object allocation. Doing this for each allocation would be slow. // Since the card is not dirty, it means the object may not get scanned. This can cause class // unloading to occur even though the class and class loader are reachable through the object's diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 84671c34b5..17913fc2dc 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -434,6 +434,7 @@ Heap::Heap(size_t initial_size, // Create other spaces based on whether or not we have a moving GC. if (foreground_collector_type_ == kCollectorTypeCC) { CHECK(separate_non_moving_space); + // Reserve twice the capacity, to allow evacuating every region for explicit GCs. MemMap* region_space_mem_map = space::RegionSpace::CreateMemMap(kRegionSpaceName, capacity_ * 2, request_begin); @@ -517,7 +518,7 @@ Heap::Heap(size_t initial_size, // Since we don't know where in the low_4gb the app image will be located, make the card table // cover the whole low_4gb. TODO: Extend the card table in AddSpace. UNUSED(heap_capacity); - // Start at 64 KB, we can be sure there are no spaces mapped this low since the address range is + // Start at 4 KB, we can be sure there are no spaces mapped this low since the address range is // reserved by the kernel. static constexpr size_t kMinHeapAddress = 4 * KB; card_table_.reset(accounting::CardTable::Create(reinterpret_cast<uint8_t*>(kMinHeapAddress), @@ -1536,7 +1537,7 @@ void Heap::RecordFree(uint64_t freed_objects, int64_t freed_bytes) { void Heap::RecordFreeRevoke() { // Subtract num_bytes_freed_revoke_ from num_bytes_allocated_ to cancel out the - // the ahead-of-time, bulk counting of bytes allocated in rosalloc thread-local buffers. + // ahead-of-time, bulk counting of bytes allocated in rosalloc thread-local buffers. // If there's a concurrent revoke, ok to not necessarily reset num_bytes_freed_revoke_ // all the way to zero exactly as the remainder will be subtracted at the next GC. size_t bytes_freed = num_bytes_freed_revoke_.LoadSequentiallyConsistent(); @@ -1758,7 +1759,7 @@ void Heap::SetTargetHeapUtilization(float target) { size_t Heap::GetObjectsAllocated() const { Thread* const self = Thread::Current(); ScopedThreadStateChange tsc(self, kWaitingForGetObjectsAllocated); - // Prevent GC running during GetObjectsALlocated since we may get a checkpoint request that tells + // Prevent GC running during GetObjectsAllocated since we may get a checkpoint request that tells // us to suspend while we are doing SuspendAll. b/35232978 gc::ScopedGCCriticalSection gcs(Thread::Current(), gc::kGcCauseGetObjectsAllocated, @@ -1899,10 +1900,10 @@ HomogeneousSpaceCompactResult Heap::PerformHomogeneousSpaceCompact() { MutexLock mu(self, *gc_complete_lock_); // Ensure there is only one GC at a time. WaitForGcToCompleteLocked(kGcCauseHomogeneousSpaceCompact, self); - // Homogeneous space compaction is a copying transition, can't run it if the moving GC disable count - // is non zero. - // If the collector type changed to something which doesn't benefit from homogeneous space compaction, - // exit. + // Homogeneous space compaction is a copying transition, can't run it if the moving GC disable + // count is non zero. + // If the collector type changed to something which doesn't benefit from homogeneous space + // compaction, exit. if (disable_moving_gc_count_ != 0 || IsMovingGc(collector_type_) || !main_space_->CanMoveObjects()) { return kErrorReject; @@ -3445,8 +3446,8 @@ void Heap::GrowForUtilization(collector::GarbageCollector* collector_ran, TraceHeapSize(bytes_allocated); uint64_t target_size; collector::GcType gc_type = collector_ran->GetGcType(); - const double multiplier = HeapGrowthMultiplier(); // Use the multiplier to grow more for - // foreground. + // Use the multiplier to grow more for foreground. + const double multiplier = HeapGrowthMultiplier(); const uint64_t adjusted_min_free = static_cast<uint64_t>(min_free_ * multiplier); const uint64_t adjusted_max_free = static_cast<uint64_t>(max_free_ * multiplier); if (gc_type != collector::kGcTypeSticky) { diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index faa6195259..7fb634fcf7 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -551,7 +551,7 @@ class Heap { return total_memory - std::min(total_memory, byte_allocated); } - // get the space that corresponds to an object's address. Current implementation searches all + // Get the space that corresponds to an object's address. Current implementation searches all // spaces in turn. If fail_ok is false then failing to find a space will cause an abort. // TODO: consider using faster data structure like binary tree. space::ContinuousSpace* FindContinuousSpaceFromObject(ObjPtr<mirror::Object>, bool fail_ok) const @@ -1293,8 +1293,9 @@ class Heap { // Parallel GC data structures. std::unique_ptr<ThreadPool> thread_pool_; - // For a GC cycle, a bitmap that is set corresponding to the + // A bitmap that is set corresponding to the known live objects since the last GC cycle. std::unique_ptr<accounting::HeapBitmap> live_bitmap_ GUARDED_BY(Locks::heap_bitmap_lock_); + // A bitmap that is set corresponding to the marked objects in the current GC cycle. std::unique_ptr<accounting::HeapBitmap> mark_bitmap_ GUARDED_BY(Locks::heap_bitmap_lock_); // Mark stack that we reuse to avoid re-allocating the mark stack. @@ -1312,7 +1313,7 @@ class Heap { AllocatorType current_allocator_; const AllocatorType current_non_moving_allocator_; - // Which GCs we run in order when we an allocation fails. + // Which GCs we run in order when an allocation fails. std::vector<collector::GcType> gc_plan_; // Bump pointer spaces. @@ -1320,6 +1321,7 @@ class Heap { // Temp space is the space which the semispace collector copies to. space::BumpPointerSpace* temp_space_; + // Region space, used by the concurrent collector. space::RegionSpace* region_space_; // Minimum free guarantees that you always have at least min_free_ free bytes after growing for diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc index 9d8e5d23eb..6d426c2dd0 100644 --- a/runtime/gc/heap_test.cc +++ b/runtime/gc/heap_test.cc @@ -81,7 +81,6 @@ class ZygoteHeapTest : public CommonRuntimeTest { void SetUpRuntimeOptions(RuntimeOptions* options) { CommonRuntimeTest::SetUpRuntimeOptions(options); options->push_back(std::make_pair("-Xzygote", nullptr)); - options->push_back(std::make_pair("-Xno-hidden-api-checks", nullptr)); } }; diff --git a/runtime/gc/space/region_space-inl.h b/runtime/gc/space/region_space-inl.h index e74e9b169f..410931cbe5 100644 --- a/runtime/gc/space/region_space-inl.h +++ b/runtime/gc/space/region_space-inl.h @@ -24,26 +24,30 @@ namespace art { namespace gc { namespace space { -inline mirror::Object* RegionSpace::Alloc(Thread*, size_t num_bytes, size_t* bytes_allocated, - size_t* usable_size, - size_t* bytes_tl_bulk_allocated) { +inline mirror::Object* RegionSpace::Alloc(Thread* self ATTRIBUTE_UNUSED, + size_t num_bytes, + /* out */ size_t* bytes_allocated, + /* out */ size_t* usable_size, + /* out */ size_t* bytes_tl_bulk_allocated) { num_bytes = RoundUp(num_bytes, kAlignment); return AllocNonvirtual<false>(num_bytes, bytes_allocated, usable_size, bytes_tl_bulk_allocated); } -inline mirror::Object* RegionSpace::AllocThreadUnsafe(Thread* self, size_t num_bytes, - size_t* bytes_allocated, - size_t* usable_size, - size_t* bytes_tl_bulk_allocated) { +inline mirror::Object* RegionSpace::AllocThreadUnsafe(Thread* self, + size_t num_bytes, + /* out */ size_t* bytes_allocated, + /* out */ size_t* usable_size, + /* out */ size_t* bytes_tl_bulk_allocated) { Locks::mutator_lock_->AssertExclusiveHeld(self); return Alloc(self, num_bytes, bytes_allocated, usable_size, bytes_tl_bulk_allocated); } template<bool kForEvac> -inline mirror::Object* RegionSpace::AllocNonvirtual(size_t num_bytes, size_t* bytes_allocated, - size_t* usable_size, - size_t* bytes_tl_bulk_allocated) { +inline mirror::Object* RegionSpace::AllocNonvirtual(size_t num_bytes, + /* out */ size_t* bytes_allocated, + /* out */ size_t* usable_size, + /* out */ size_t* bytes_tl_bulk_allocated) { DCHECK_ALIGNED(num_bytes, kAlignment); mirror::Object* obj; if (LIKELY(num_bytes <= kRegionSize)) { @@ -79,8 +83,7 @@ inline mirror::Object* RegionSpace::AllocNonvirtual(size_t num_bytes, size_t* by } } else { // Large object. - obj = AllocLarge<kForEvac>(num_bytes, bytes_allocated, usable_size, - bytes_tl_bulk_allocated); + obj = AllocLarge<kForEvac>(num_bytes, bytes_allocated, usable_size, bytes_tl_bulk_allocated); if (LIKELY(obj != nullptr)) { return obj; } @@ -88,9 +91,10 @@ inline mirror::Object* RegionSpace::AllocNonvirtual(size_t num_bytes, size_t* by return nullptr; } -inline mirror::Object* RegionSpace::Region::Alloc(size_t num_bytes, size_t* bytes_allocated, - size_t* usable_size, - size_t* bytes_tl_bulk_allocated) { +inline mirror::Object* RegionSpace::Region::Alloc(size_t num_bytes, + /* out */ size_t* bytes_allocated, + /* out */ size_t* usable_size, + /* out */ size_t* bytes_tl_bulk_allocated) { DCHECK(IsAllocated() && IsInToSpace()); DCHECK_ALIGNED(num_bytes, kAlignment); uint8_t* old_top; @@ -238,9 +242,9 @@ inline mirror::Object* RegionSpace::GetNextObject(mirror::Object* obj) { template<bool kForEvac> inline mirror::Object* RegionSpace::AllocLarge(size_t num_bytes, - size_t* bytes_allocated, - size_t* usable_size, - size_t* bytes_tl_bulk_allocated) { + /* out */ size_t* bytes_allocated, + /* out */ size_t* usable_size, + /* out */ size_t* bytes_tl_bulk_allocated) { DCHECK_ALIGNED(num_bytes, kAlignment); DCHECK_GT(num_bytes, kRegionSize); size_t num_regs = RoundUp(num_bytes, kRegionSize) / kRegionSize; @@ -254,7 +258,7 @@ inline mirror::Object* RegionSpace::AllocLarge(size_t num_bytes, return nullptr; } } - // Find a large enough contiguous free regions. + // Find a large enough set of contiguous free regions. size_t left = 0; while (left + num_regs - 1 < num_regions_) { bool found = true; @@ -270,7 +274,7 @@ inline mirror::Object* RegionSpace::AllocLarge(size_t num_bytes, } } if (found) { - // right points to the one region past the last free region. + // `right` points to the one region past the last free region. DCHECK_EQ(left + num_regs, right); Region* first_reg = ®ions_[left]; DCHECK(first_reg->IsFree()); @@ -345,7 +349,7 @@ inline size_t RegionSpace::Region::BytesAllocated() const { DCHECK_EQ(begin_, Top()); return 0; } else { - DCHECK(IsAllocated()) << static_cast<uint>(state_); + DCHECK(IsAllocated()) << "state=" << state_; DCHECK_LE(begin_, Top()); size_t bytes; if (is_a_tlab_) { @@ -358,6 +362,20 @@ inline size_t RegionSpace::Region::BytesAllocated() const { } } +inline size_t RegionSpace::Region::ObjectsAllocated() const { + if (IsLarge()) { + DCHECK_LT(begin_ + kRegionSize, Top()); + DCHECK_EQ(objects_allocated_.LoadRelaxed(), 0U); + return 1; + } else if (IsLargeTail()) { + DCHECK_EQ(begin_, Top()); + DCHECK_EQ(objects_allocated_.LoadRelaxed(), 0U); + return 0; + } else { + DCHECK(IsAllocated()) << "state=" << state_; + return objects_allocated_; + } +} } // namespace space } // namespace gc diff --git a/runtime/gc/space/region_space.cc b/runtime/gc/space/region_space.cc index a505f32c49..8d94c86701 100644 --- a/runtime/gc/space/region_space.cc +++ b/runtime/gc/space/region_space.cc @@ -27,7 +27,7 @@ namespace space { // If a region has live objects whose size is less than this percent // value of the region size, evaculate the region. -static constexpr uint kEvaculateLivePercentThreshold = 75U; +static constexpr uint kEvacuateLivePercentThreshold = 75U; // If we protect the cleared regions. // Only protect for target builds to prevent flaky test failures (b/63131961). @@ -158,14 +158,14 @@ size_t RegionSpace::ToSpaceSize() { inline bool RegionSpace::Region::ShouldBeEvacuated() { DCHECK((IsAllocated() || IsLarge()) && IsInToSpace()); - // if the region was allocated after the start of the - // previous GC or the live ratio is below threshold, evacuate - // it. + // The region should be evacuated if: + // - the region was allocated after the start of the previous GC (newly allocated region); or + // - the live ratio is below threshold (`kEvacuateLivePercentThreshold`). bool result; if (is_newly_allocated_) { result = true; } else { - bool is_live_percent_valid = live_bytes_ != static_cast<size_t>(-1); + bool is_live_percent_valid = (live_bytes_ != static_cast<size_t>(-1)); if (is_live_percent_valid) { DCHECK(IsInToSpace()); DCHECK(!IsLargeTail()); @@ -177,10 +177,10 @@ inline bool RegionSpace::Region::ShouldBeEvacuated() { // Side node: live_percent == 0 does not necessarily mean // there's no live objects due to rounding (there may be a // few). - result = live_bytes_ * 100U < kEvaculateLivePercentThreshold * bytes_allocated; + result = (live_bytes_ * 100U < kEvacuateLivePercentThreshold * bytes_allocated); } else { DCHECK(IsLarge()); - result = live_bytes_ == 0U; + result = (live_bytes_ == 0U); } } else { result = false; @@ -198,7 +198,10 @@ void RegionSpace::SetFromSpace(accounting::ReadBarrierTable* rb_table, bool forc rb_table->SetAll(); } MutexLock mu(Thread::Current(), region_lock_); - size_t num_expected_large_tails = 0; + // Counter for the number of expected large tail regions following a large region. + size_t num_expected_large_tails = 0U; + // Flag to store whether the previously seen large region has been evacuated. + // This is used to apply the same evacuation policy to related large tail regions. bool prev_large_evacuated = false; VerifyNonFreeRegionLimit(); const size_t iter_limit = kUseTableLookupReadBarrier @@ -260,7 +263,8 @@ static void ZeroAndProtectRegion(uint8_t* begin, uint8_t* end) { } } -void RegionSpace::ClearFromSpace(uint64_t* cleared_bytes, uint64_t* cleared_objects) { +void RegionSpace::ClearFromSpace(/* out */ uint64_t* cleared_bytes, + /* out */ uint64_t* cleared_objects) { DCHECK(cleared_bytes != nullptr); DCHECK(cleared_objects != nullptr); *cleared_bytes = 0; @@ -272,18 +276,32 @@ void RegionSpace::ClearFromSpace(uint64_t* cleared_bytes, uint64_t* cleared_obje // Update max of peak non free region count before reclaiming evacuated regions. max_peak_num_non_free_regions_ = std::max(max_peak_num_non_free_regions_, num_non_free_regions_); - // Combine zeroing and releasing pages to reduce how often madvise is called. This helps - // reduce contention on the mmap semaphore. b/62194020 - // clear_region adds a region to the current block. If the region is not adjacent, the - // clear block is zeroed, released, and a new block begins. + + // Lambda expression `clear_region` clears a region and adds a region to the + // "clear block". + // + // As we sweep regions to clear them, we maintain a "clear block", composed of + // adjacent cleared regions and whose bounds are `clear_block_begin` and + // `clear_block_end`. When processing a new region which is not adjacent to + // the clear block (discontinuity in cleared regions), the clear block + // is zeroed and released and the clear block is reset (to the most recent + // cleared region). + // + // This is done in order to combine zeroing and releasing pages to reduce how + // often madvise is called. This helps reduce contention on the mmap semaphore + // (see b/62194020). uint8_t* clear_block_begin = nullptr; uint8_t* clear_block_end = nullptr; auto clear_region = [&clear_block_begin, &clear_block_end](Region* r) { r->Clear(/*zero_and_release_pages*/false); if (clear_block_end != r->Begin()) { + // Region `r` is not adjacent to the current clear block; zero and release + // pages within the current block and restart a new clear block at the + // beginning of region `r`. ZeroAndProtectRegion(clear_block_begin, clear_block_end); clear_block_begin = r->Begin(); } + // Add region `r` to the clear block. clear_block_end = r->End(); }; for (size_t i = 0; i < std::min(num_regions_, non_free_region_index_limit_); ++i) { @@ -334,12 +352,22 @@ void RegionSpace::ClearFromSpace(uint64_t* cleared_bytes, uint64_t* cleared_obje ++regions_to_clear_bitmap; } + // Optimization: If the live bytes are *all* live in a region + // then the live-bit information for these objects is superfluous: + // - We can determine that these objects are all live by using + // Region::AllAllocatedBytesAreLive (which just checks whether + // `LiveBytes() == static_cast<size_t>(Top() - Begin())`. + // - We can visit the objects in this region using + // RegionSpace::GetNextObject, i.e. without resorting to the + // live bits (see RegionSpace::WalkInternal). + // Therefore, we can clear the bits for these objects in the + // (live) region space bitmap (and release the corresponding pages). GetLiveBitmap()->ClearRange( reinterpret_cast<mirror::Object*>(r->Begin()), reinterpret_cast<mirror::Object*>(r->Begin() + regions_to_clear_bitmap * kRegionSize)); - // Skip over extra regions we cleared the bitmaps: we don't need to clear them, as they - // are unevac region sthat are live. - // Subtract one for the for loop. + // Skip over extra regions for which we cleared the bitmaps: we shall not clear them, + // as they are unevac regions that are live. + // Subtract one for the for-loop. i += regions_to_clear_bitmap - 1; } } @@ -432,7 +460,13 @@ void RegionSpace::ClampGrowthLimit(size_t new_capacity) { void RegionSpace::Dump(std::ostream& os) const { os << GetName() << " " - << reinterpret_cast<void*>(Begin()) << "-" << reinterpret_cast<void*>(Limit()); + << reinterpret_cast<void*>(Begin()) << "-" << reinterpret_cast<void*>(Limit()); +} + +void RegionSpace::DumpRegionForObject(std::ostream& os, mirror::Object* obj) { + CHECK(HasAddress(obj)); + MutexLock mu(Thread::Current(), region_lock_); + RefToRegionUnlocked(obj)->Dump(os); } void RegionSpace::DumpRegions(std::ostream& os) { @@ -526,13 +560,18 @@ void RegionSpace::AssertAllThreadLocalBuffersAreRevoked() { } void RegionSpace::Region::Dump(std::ostream& os) const { - os << "Region[" << idx_ << "]=" << reinterpret_cast<void*>(begin_) << "-" - << reinterpret_cast<void*>(Top()) + os << "Region[" << idx_ << "]=" + << reinterpret_cast<void*>(begin_) + << "-" << reinterpret_cast<void*>(Top()) << "-" << reinterpret_cast<void*>(end_) - << " state=" << static_cast<uint>(state_) << " type=" << static_cast<uint>(type_) + << " state=" << state_ + << " type=" << type_ << " objects_allocated=" << objects_allocated_ - << " alloc_time=" << alloc_time_ << " live_bytes=" << live_bytes_ - << " is_newly_allocated=" << is_newly_allocated_ << " is_a_tlab=" << is_a_tlab_ << " thread=" << thread_ << "\n"; + << " alloc_time=" << alloc_time_ + << " live_bytes=" << live_bytes_ + << " is_newly_allocated=" << std::boolalpha << is_newly_allocated_ << std::noboolalpha + << " is_a_tlab=" << std::boolalpha << is_a_tlab_ << std::noboolalpha + << " thread=" << thread_ << '\n'; } size_t RegionSpace::AllocationSizeNonvirtual(mirror::Object* obj, size_t* usable_size) { diff --git a/runtime/gc/space/region_space.h b/runtime/gc/space/region_space.h index 55c2772129..c3b7ff72ef 100644 --- a/runtime/gc/space/region_space.h +++ b/runtime/gc/space/region_space.h @@ -46,24 +46,33 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace { static MemMap* CreateMemMap(const std::string& name, size_t capacity, uint8_t* requested_begin); static RegionSpace* Create(const std::string& name, MemMap* mem_map); - // Allocate num_bytes, returns null if the space is full. - mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated, - size_t* usable_size, size_t* bytes_tl_bulk_allocated) + // Allocate `num_bytes`, returns null if the space is full. + mirror::Object* Alloc(Thread* self, + size_t num_bytes, + /* out */ size_t* bytes_allocated, + /* out */ size_t* usable_size, + /* out */ size_t* bytes_tl_bulk_allocated) OVERRIDE REQUIRES(!region_lock_); // Thread-unsafe allocation for when mutators are suspended, used by the semispace collector. - mirror::Object* AllocThreadUnsafe(Thread* self, size_t num_bytes, size_t* bytes_allocated, - size_t* usable_size, size_t* bytes_tl_bulk_allocated) + mirror::Object* AllocThreadUnsafe(Thread* self, + size_t num_bytes, + /* out */ size_t* bytes_allocated, + /* out */ size_t* usable_size, + /* out */ size_t* bytes_tl_bulk_allocated) OVERRIDE REQUIRES(Locks::mutator_lock_) REQUIRES(!region_lock_); // The main allocation routine. template<bool kForEvac> - ALWAYS_INLINE mirror::Object* AllocNonvirtual(size_t num_bytes, size_t* bytes_allocated, - size_t* usable_size, - size_t* bytes_tl_bulk_allocated) + ALWAYS_INLINE mirror::Object* AllocNonvirtual(size_t num_bytes, + /* out */ size_t* bytes_allocated, + /* out */ size_t* usable_size, + /* out */ size_t* bytes_tl_bulk_allocated) REQUIRES(!region_lock_); - // Allocate/free large objects (objects that are larger than the region size.) + // Allocate/free large objects (objects that are larger than the region size). template<bool kForEvac> - mirror::Object* AllocLarge(size_t num_bytes, size_t* bytes_allocated, size_t* usable_size, - size_t* bytes_tl_bulk_allocated) REQUIRES(!region_lock_); + mirror::Object* AllocLarge(size_t num_bytes, + /* out */ size_t* bytes_allocated, + /* out */ size_t* usable_size, + /* out */ size_t* bytes_tl_bulk_allocated) REQUIRES(!region_lock_); template<bool kForEvac> void FreeLarge(mirror::Object* large_obj, size_t bytes_allocated) REQUIRES(!region_lock_); @@ -101,6 +110,8 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace { void Dump(std::ostream& os) const; void DumpRegions(std::ostream& os) REQUIRES(!region_lock_); + // Dump region containing object `obj`. Precondition: `obj` is in the region space. + void DumpRegionForObject(std::ostream& os, mirror::Object* obj) REQUIRES(!region_lock_); void DumpNonFreeRegions(std::ostream& os) REQUIRES(!region_lock_); size_t RevokeThreadLocalBuffers(Thread* thread) REQUIRES(!region_lock_); @@ -174,7 +185,7 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace { template <typename Visitor> ALWAYS_INLINE void WalkToSpace(Visitor&& visitor) REQUIRES(Locks::mutator_lock_) { - WalkInternal<true>(visitor); + WalkInternal<true /* kToSpaceOnly */>(visitor); } accounting::ContinuousSpaceBitmap::SweepCallback* GetSweepCallback() OVERRIDE { @@ -228,13 +239,16 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace { return RegionType::kRegionTypeNone; } + // Determine which regions to evacuate and tag them as + // from-space. Tag the rest as unevacuated from-space. void SetFromSpace(accounting::ReadBarrierTable* rb_table, bool force_evacuate_all) REQUIRES(!region_lock_); size_t FromSpaceSize() REQUIRES(!region_lock_); size_t UnevacFromSpaceSize() REQUIRES(!region_lock_); size_t ToSpaceSize() REQUIRES(!region_lock_); - void ClearFromSpace(uint64_t* cleared_bytes, uint64_t* cleared_objects) REQUIRES(!region_lock_); + void ClearFromSpace(/* out */ uint64_t* cleared_bytes, /* out */ uint64_t* cleared_objects) + REQUIRES(!region_lock_); void AddLiveBytes(mirror::Object* ref, size_t alloc_size) { Region* reg = RefToRegionUnlocked(ref); @@ -301,12 +315,13 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace { void Clear(bool zero_and_release_pages); - ALWAYS_INLINE mirror::Object* Alloc(size_t num_bytes, size_t* bytes_allocated, - size_t* usable_size, - size_t* bytes_tl_bulk_allocated); + ALWAYS_INLINE mirror::Object* Alloc(size_t num_bytes, + /* out */ size_t* bytes_allocated, + /* out */ size_t* usable_size, + /* out */ size_t* bytes_tl_bulk_allocated); bool IsFree() const { - bool is_free = state_ == RegionState::kRegionStateFree; + bool is_free = (state_ == RegionState::kRegionStateFree); if (is_free) { DCHECK(IsInNoSpace()); DCHECK_EQ(begin_, Top()); @@ -319,9 +334,11 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace { void Unfree(RegionSpace* region_space, uint32_t alloc_time) REQUIRES(region_space->region_lock_); + // Given a free region, declare it non-free (allocated) and large. void UnfreeLarge(RegionSpace* region_space, uint32_t alloc_time) REQUIRES(region_space->region_lock_); + // Given a free region, declare it non-free (allocated) and large tail. void UnfreeLargeTail(RegionSpace* region_space, uint32_t alloc_time) REQUIRES(region_space->region_lock_); @@ -339,7 +356,7 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace { // Large allocated. bool IsLarge() const { - bool is_large = state_ == RegionState::kRegionStateLarge; + bool is_large = (state_ == RegionState::kRegionStateLarge); if (is_large) { DCHECK_LT(begin_ + kRegionSize, Top()); } @@ -348,7 +365,7 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace { // Large-tail allocated. bool IsLargeTail() const { - bool is_large_tail = state_ == RegionState::kRegionStateLargeTail; + bool is_large_tail = (state_ == RegionState::kRegionStateLargeTail); if (is_large_tail) { DCHECK_EQ(begin_, Top()); } @@ -379,23 +396,33 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace { return type_ == RegionType::kRegionTypeNone; } + // Set this region as evacuated from-space. At the end of the + // collection, RegionSpace::ClearFromSpace will clear and reclaim + // the space used by this region, and tag it as unallocated/free. void SetAsFromSpace() { DCHECK(!IsFree() && IsInToSpace()); type_ = RegionType::kRegionTypeFromSpace; live_bytes_ = static_cast<size_t>(-1); } + // Set this region as unevacuated from-space. At the end of the + // collection, RegionSpace::ClearFromSpace will preserve the space + // used by this region, and tag it as to-space (see + // Region::SetUnevacFromSpaceAsToSpace below). void SetAsUnevacFromSpace() { DCHECK(!IsFree() && IsInToSpace()); type_ = RegionType::kRegionTypeUnevacFromSpace; live_bytes_ = 0U; } + // Set this region as to-space. Used by RegionSpace::ClearFromSpace. + // This is only valid if it is currently an unevac from-space region. void SetUnevacFromSpaceAsToSpace() { DCHECK(!IsFree() && IsInUnevacFromSpace()); type_ = RegionType::kRegionTypeToSpace; } + // Return whether this region should be evacuated. Used by RegionSpace::SetFromSpace. ALWAYS_INLINE bool ShouldBeEvacuated(); void AddLiveBytes(size_t live_bytes) { @@ -418,20 +445,7 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace { size_t BytesAllocated() const; - size_t ObjectsAllocated() const { - if (IsLarge()) { - DCHECK_LT(begin_ + kRegionSize, Top()); - DCHECK_EQ(objects_allocated_.LoadRelaxed(), 0U); - return 1; - } else if (IsLargeTail()) { - DCHECK_EQ(begin_, Top()); - DCHECK_EQ(objects_allocated_.LoadRelaxed(), 0U); - return 0; - } else { - DCHECK(IsAllocated()) << static_cast<uint>(state_); - return objects_allocated_; - } - } + size_t ObjectsAllocated() const; uint8_t* Begin() const { return begin_; @@ -467,12 +481,17 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace { private: size_t idx_; // The region's index in the region space. uint8_t* begin_; // The begin address of the region. + // Note that `top_` can be higher than `end_` in the case of a + // large region, where an allocated object spans multiple regions + // (large region + one or more large tail regions). Atomic<uint8_t*> top_; // The current position of the allocation. uint8_t* end_; // The end address of the region. RegionState state_; // The region state (see RegionState). RegionType type_; // The region type (see RegionType). Atomic<size_t> objects_allocated_; // The number of objects allocated. uint32_t alloc_time_; // The allocation time of the region. + // Note that newly allocated and evacuated regions use -1 as + // special value for `live_bytes_`. size_t live_bytes_; // The live bytes. Used to compute the live percent. bool is_newly_allocated_; // True if it's allocated after the last collection. bool is_a_tlab_; // True if it's a tlab. @@ -488,12 +507,12 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace { Region* RefToRegionUnlocked(mirror::Object* ref) NO_THREAD_SAFETY_ANALYSIS { // For a performance reason (this is frequently called via - // IsInFromSpace() etc.) we avoid taking a lock here. Note that - // since we only change a region from to-space to from-space only - // during a pause (SetFromSpace()) and from from-space to free - // (after GC is done) as long as ref is a valid reference into an - // allocated region, it's safe to access the region state without - // the lock. + // RegionSpace::IsInFromSpace, etc.) we avoid taking a lock here. + // Note that since we only change a region from to-space to (evac) + // from-space during a pause (in RegionSpace::SetFromSpace) and + // from (evac) from-space to free (after GC is done), as long as + // `ref` is a valid reference into an allocated region, it's safe + // to access the region state without the lock. return RefToRegionLocked(ref); } @@ -508,6 +527,13 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace { return reg; } + // Return the object location following `obj` in the region space + // (i.e., the object location at `obj + obj->SizeOf()`). + // + // Note that + // - unless the region containing `obj` is fully used; and + // - `obj` is not the last object of that region; + // the returned location is not guaranteed to be a valid object. mirror::Object* GetNextObject(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_); @@ -524,6 +550,8 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace { VerifyNonFreeRegionLimit(); } + // Implementation of this invariant: + // for all `i >= non_free_region_index_limit_`, `regions_[i].IsFree()` is true. void VerifyNonFreeRegionLimit() REQUIRES(region_lock_) { if (kIsDebugBuild && non_free_region_index_limit_ < num_regions_) { for (size_t i = non_free_region_index_limit_; i < num_regions_; ++i) { @@ -549,14 +577,18 @@ class RegionSpace FINAL : public ContinuousMemMapAllocSpace { // regions are in non-free. size_t max_peak_num_non_free_regions_; + // The pointer to the region array. std::unique_ptr<Region[]> regions_ GUARDED_BY(region_lock_); - // The pointer to the region array. + // The upper-bound index of the non-free regions. Used to avoid scanning all regions in - // SetFromSpace(). Invariant: for all i >= non_free_region_index_limit_, regions_[i].IsFree() is - // true. + // RegionSpace::SetFromSpace and RegionSpace::ClearFromSpace. + // + // Invariant (verified by RegionSpace::VerifyNonFreeRegionLimit): + // for all `i >= non_free_region_index_limit_`, `regions_[i].IsFree()` is true. size_t non_free_region_index_limit_ GUARDED_BY(region_lock_); - Region* current_region_; // The region that's being allocated currently. - Region* evac_region_; // The region that's being evacuated to currently. + + Region* current_region_; // The region currently used for allocation. + Region* evac_region_; // The region currently used for evacuation. Region full_region_; // The dummy/sentinel region that looks full. // Mark bitmap used by the GC. diff --git a/runtime/gc/space/space.cc b/runtime/gc/space/space.cc index 2c6afa7eb8..a8bd7b816e 100644 --- a/runtime/gc/space/space.cc +++ b/runtime/gc/space/space.cc @@ -107,7 +107,6 @@ collector::ObjectBytePair ContinuousMemMapAllocSpace::Sweep(bool swap_bitmaps) { return scc.freed; } -// Returns the old mark bitmap. void ContinuousMemMapAllocSpace::BindLiveToMarkBitmap() { CHECK(!HasBoundBitmaps()); accounting::ContinuousSpaceBitmap* live_bitmap = GetLiveBitmap(); @@ -125,7 +124,7 @@ bool ContinuousMemMapAllocSpace::HasBoundBitmaps() const { void ContinuousMemMapAllocSpace::UnBindBitmaps() { CHECK(HasBoundBitmaps()); - // At this point, the temp_bitmap holds our old mark bitmap. + // At this point, `temp_bitmap_` holds our old mark bitmap. accounting::ContinuousSpaceBitmap* new_bitmap = temp_bitmap_.release(); Runtime::Current()->GetHeap()->GetMarkBitmap()->ReplaceBitmap(mark_bitmap_.get(), new_bitmap); CHECK_EQ(mark_bitmap_.release(), live_bitmap_.get()); diff --git a/runtime/gc/space/space.h b/runtime/gc/space/space.h index 6b76048cb1..12bccb35e7 100644 --- a/runtime/gc/space/space.h +++ b/runtime/gc/space/space.h @@ -389,7 +389,11 @@ class MemMapSpace : public ContinuousSpace { } protected: - MemMapSpace(const std::string& name, MemMap* mem_map, uint8_t* begin, uint8_t* end, uint8_t* limit, + MemMapSpace(const std::string& name, + MemMap* mem_map, + uint8_t* begin, + uint8_t* end, + uint8_t* limit, GcRetentionPolicy gc_retention_policy) : ContinuousSpace(name, gc_retention_policy, begin, end, limit), mem_map_(mem_map) { @@ -420,7 +424,10 @@ class ContinuousMemMapAllocSpace : public MemMapSpace, public AllocSpace { } bool HasBoundBitmaps() const REQUIRES(Locks::heap_bitmap_lock_); + // Make the mark bitmap an alias of the live bitmap. Save the current mark bitmap into + // `temp_bitmap_`, so that we can restore it later in ContinuousMemMapAllocSpace::UnBindBitmaps. void BindLiveToMarkBitmap() REQUIRES(Locks::heap_bitmap_lock_); + // Unalias the mark bitmap from the live bitmap and restore the old mark bitmap. void UnBindBitmaps() REQUIRES(Locks::heap_bitmap_lock_); // Swap the live and mark bitmaps of this space. This is used by the GC for concurrent sweeping. void SwapBitmaps(); diff --git a/runtime/gc/space/zygote_space.h b/runtime/gc/space/zygote_space.h index 4d10de8237..08231017e7 100644 --- a/runtime/gc/space/zygote_space.h +++ b/runtime/gc/space/zygote_space.h @@ -26,7 +26,7 @@ namespace gc { namespace space { -// An zygote space is a space which you cannot allocate into or free from. +// A zygote space is a space which you cannot allocate into or free from. class ZygoteSpace FINAL : public ContinuousMemMapAllocSpace { public: // Returns the remaining storage in the out_map field. diff --git a/runtime/gc/verification.cc b/runtime/gc/verification.cc index d99b37762f..fb5db1147f 100644 --- a/runtime/gc/verification.cc +++ b/runtime/gc/verification.cc @@ -140,7 +140,7 @@ bool Verification::IsValidClass(const void* addr) const { if (!IsValidHeapObjectAddress(k1)) { return false; } - // k should be class class, take the class again to verify. + // `k1` should be class class, take the class again to verify. // Note that this check may not be valid for the no image space since the class class might move // around from moving GC. mirror::Class* k2 = k1->GetClass<kVerifyNone, kWithoutReadBarrier>(); diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h index 05e68e66dd..d7e5e18b9e 100644 --- a/runtime/hidden_api.h +++ b/runtime/hidden_api.h @@ -31,6 +31,23 @@ enum Action { kDeny }; +enum AccessMethod { + kReflection, + kJNI +}; + +inline std::ostream& operator<<(std::ostream& os, AccessMethod value) { + switch (value) { + case kReflection: + os << "reflection"; + break; + case kJNI: + os << "JNI"; + break; + } + return os; +} + inline Action GetMemberAction(uint32_t access_flags) { switch (HiddenApiAccessFlags::DecodeFromRuntime(access_flags)) { case HiddenApiAccessFlags::kWhitelist: @@ -45,19 +62,25 @@ inline Action GetMemberAction(uint32_t access_flags) { } // Issue a warning about field access. -inline void WarnAboutMemberAccess(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_) { +inline void WarnAboutMemberAccess(ArtField* field, AccessMethod access_method) + REQUIRES_SHARED(Locks::mutator_lock_) { std::string tmp; LOG(WARNING) << "Accessing hidden field " << field->GetDeclaringClass()->GetDescriptor(&tmp) << "->" - << field->GetName() << ":" << field->GetTypeDescriptor(); + << field->GetName() << ":" << field->GetTypeDescriptor() + << " (" << HiddenApiAccessFlags::DecodeFromRuntime(field->GetAccessFlags()) + << ", " << access_method << ")"; } // Issue a warning about method access. -inline void WarnAboutMemberAccess(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) { +inline void WarnAboutMemberAccess(ArtMethod* method, AccessMethod access_method) + REQUIRES_SHARED(Locks::mutator_lock_) { std::string tmp; LOG(WARNING) << "Accessing hidden method " << method->GetDeclaringClass()->GetDescriptor(&tmp) << "->" - << method->GetName() << method->GetSignature().ToString(); + << method->GetName() << method->GetSignature().ToString() + << " (" << HiddenApiAccessFlags::DecodeFromRuntime(method->GetAccessFlags()) + << ", " << access_method << ")"; } // Returns true if access to `member` should be denied to the caller of the @@ -69,7 +92,8 @@ inline void WarnAboutMemberAccess(ArtMethod* method) REQUIRES_SHARED(Locks::muta template<typename T> inline bool ShouldBlockAccessToMember(T* member, Thread* self, - std::function<bool(Thread*)> fn_caller_in_boot) + std::function<bool(Thread*)> fn_caller_in_boot, + AccessMethod access_method) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(member != nullptr); Runtime* runtime = Runtime::Current(); @@ -92,25 +116,33 @@ inline bool ShouldBlockAccessToMember(T* member, return false; } - // Member is hidden and we are not in the boot class path. Act accordingly. + // Member is hidden and we are not in the boot class path. + + // Print a log message with information about this class member access. + // We do this regardless of whether we block the access or not. + WarnAboutMemberAccess(member, access_method); + + // Block access if on blacklist. if (action == kDeny) { return true; - } else { - DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast); - - // Allow access to this member but print a warning. Depending on a runtime - // flag, we might move the member into whitelist and skip the warning the - // next time the member is used. - if (runtime->ShouldDedupeHiddenApiWarnings()) { - member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime( - member->GetAccessFlags(), HiddenApiAccessFlags::kWhitelist)); - } - WarnAboutMemberAccess(member); - if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) { - Runtime::Current()->SetPendingHiddenApiWarning(true); - } - return false; } + + // Allow access to this member but print a warning. + DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast); + + // Depending on a runtime flag, we might move the member into whitelist and + // skip the warning the next time the member is accessed. + if (runtime->ShouldDedupeHiddenApiWarnings()) { + member->SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime( + member->GetAccessFlags(), HiddenApiAccessFlags::kWhitelist)); + } + + // If this action requires a UI warning, set the appropriate flag. + if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) { + Runtime::Current()->SetPendingHiddenApiWarning(true); + } + + return false; } // Returns true if access to member with `access_flags` should be denied to `caller`. diff --git a/runtime/hidden_api_access_flags.h b/runtime/hidden_api_access_flags.h index c328f965d2..6a88c12be5 100644 --- a/runtime/hidden_api_access_flags.h +++ b/runtime/hidden_api_access_flags.h @@ -146,6 +146,24 @@ class HiddenApiAccessFlags { }; }; +inline std::ostream& operator<<(std::ostream& os, HiddenApiAccessFlags::ApiList value) { + switch (value) { + case HiddenApiAccessFlags::kWhitelist: + os << "whitelist"; + break; + case HiddenApiAccessFlags::kLightGreylist: + os << "light greylist"; + break; + case HiddenApiAccessFlags::kDarkGreylist: + os << "dark greylist"; + break; + case HiddenApiAccessFlags::kBlacklist: + os << "blacklist"; + break; + } + return os; +} + } // namespace art diff --git a/runtime/image.cc b/runtime/image.cc index 8e3615ffcf..99406229a5 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -26,7 +26,7 @@ namespace art { const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' }; -const uint8_t ImageHeader::kImageVersion[] = { '0', '5', '4', '\0' }; // Math.pow() intrinsic. +const uint8_t ImageHeader::kImageVersion[] = { '0', '5', '5', '\0' }; // Bitstring type check off. ImageHeader::ImageHeader(uint32_t image_begin, uint32_t image_size, diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index 24cedb093b..0ae6dbfa88 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -269,7 +269,20 @@ static void InstrumentationInstallStack(Thread* thread, void* arg) } } else { CHECK_NE(return_pc, 0U); - CHECK(!reached_existing_instrumentation_frames_); + if (UNLIKELY(reached_existing_instrumentation_frames_)) { + std::string thread_name; + GetThread()->GetThreadName(thread_name); + uint32_t dex_pc = dex::kDexNoIndex; + if (last_return_pc_ != 0 && + GetCurrentOatQuickMethodHeader() != nullptr) { + dex_pc = GetCurrentOatQuickMethodHeader()->ToDexPc(m, last_return_pc_); + } + LOG(FATAL) << "While walking " << thread_name << " found existing instrumentation frames." + << " method is " << GetMethod()->PrettyMethod() + << " return_pc is " << std::hex << return_pc + << " dex pc: " << dex_pc; + UNREACHABLE(); + } InstrumentationStackFrame instrumentation_frame( m->IsRuntimeMethod() ? nullptr : GetThisObject(), m, diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index 12b8c38bbb..a8ab626a62 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -31,6 +31,7 @@ #include "mirror/class.h" #include "mirror/emulated_stack_frame.h" #include "mirror/method_handle_impl-inl.h" +#include "mirror/var_handle.h" #include "reflection-inl.h" #include "reflection.h" #include "stack.h" @@ -723,263 +724,149 @@ bool DoMethodHandleInvoke(Thread* self, } } -static bool UnimplementedSignaturePolymorphicMethod(Thread* self ATTRIBUTE_UNUSED, - ShadowFrame& shadow_frame ATTRIBUTE_UNUSED, - const Instruction* inst ATTRIBUTE_UNUSED, - uint16_t inst_data ATTRIBUTE_UNUSED, - JValue* result ATTRIBUTE_UNUSED) +static bool DoVarHandleInvokeChecked(Thread* self, + Handle<mirror::VarHandle> var_handle, + Handle<mirror::MethodType> callsite_type, + mirror::VarHandle::AccessMode access_mode, + ShadowFrame& shadow_frame, + InstructionOperands* operands, + JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - UNIMPLEMENTED(FATAL) << "TODO(oth): b/65872996"; - return false; -} - -bool DoVarHandleCompareAndExchange(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleCompareAndExchangeAcquire(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleCompareAndExchangeRelease(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleCompareAndSet(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGet(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetAcquire(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetAndAdd(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetAndAddAcquire(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetAndAddRelease(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetAndBitwiseAnd(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetAndBitwiseAndAcquire(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetAndBitwiseAndRelease(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetAndBitwiseOr(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetAndBitwiseOrAcquire(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetAndBitwiseOrRelease(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetAndBitwiseXor(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetAndBitwiseXorAcquire(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetAndBitwiseXorRelease(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetAndSet(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetAndSetAcquire(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetAndSetRelease(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetOpaque(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} - -bool DoVarHandleGetVolatile(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); + // TODO(oth): GetMethodTypeForAccessMode() allocates a MethodType() + // which is only required if we need to convert argument and/or + // return types. + StackHandleScope<1> hs(self); + Handle<mirror::MethodType> accessor_type(hs.NewHandle( + var_handle->GetMethodTypeForAccessMode(self, access_mode))); + const size_t num_vregs = accessor_type->NumberOfVRegs(); + const int num_params = accessor_type->GetPTypes()->GetLength(); + ShadowFrameAllocaUniquePtr accessor_frame = + CREATE_SHADOW_FRAME(num_vregs, nullptr, shadow_frame.GetMethod(), shadow_frame.GetDexPC()); + ShadowFrameGetter getter(shadow_frame, operands); + static const uint32_t kFirstDestinationReg = 0; + ShadowFrameSetter setter(accessor_frame.get(), kFirstDestinationReg); + if (!PerformConversions(self, callsite_type, accessor_type, &getter, &setter, num_params)) { + return false; + } + RangeInstructionOperands accessor_operands(kFirstDestinationReg, + kFirstDestinationReg + num_vregs); + if (!var_handle->Access(access_mode, accessor_frame.get(), &accessor_operands, result)) { + return false; + } + return ConvertReturnValue(callsite_type, accessor_type, result); } -bool DoVarHandleSet(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} +static bool DoVarHandleInvokeCommon(Thread* self, + ShadowFrame& shadow_frame, + const Instruction* inst, + uint16_t inst_data, + JValue* result, + mirror::VarHandle::AccessMode access_mode) + REQUIRES_SHARED(Locks::mutator_lock_) { + // Make sure to check for async exceptions + if (UNLIKELY(self->ObserveAsyncException())) { + return false; + } -bool DoVarHandleSetOpaque(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} + bool is_var_args = inst->HasVarArgs(); + const uint32_t vRegC = is_var_args ? inst->VRegC_45cc() : inst->VRegC_4rcc(); + ObjPtr<mirror::Object> receiver(shadow_frame.GetVRegReference(vRegC)); + if (receiver.IsNull()) { + ThrowNullPointerExceptionFromDexPC(); + return false; + } -bool DoVarHandleSetRelease(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} + StackHandleScope<2> hs(self); + Handle<mirror::VarHandle> var_handle(hs.NewHandle(down_cast<mirror::VarHandle*>(receiver.Ptr()))); + if (!var_handle->IsAccessModeSupported(access_mode)) { + ThrowUnsupportedOperationException(); + return false; + } -bool DoVarHandleSetVolatile(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} + const uint32_t vRegH = is_var_args ? inst->VRegH_45cc() : inst->VRegH_4rcc(); + ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); + Handle<mirror::MethodType> callsite_type(hs.NewHandle( + class_linker->ResolveMethodType(self, vRegH, shadow_frame.GetMethod()))); + // This implies we couldn't resolve one or more types in this VarHandle. + if (UNLIKELY(callsite_type == nullptr)) { + CHECK(self->IsExceptionPending()); + return false; + } -bool DoVarHandleWeakCompareAndSet(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} + if (!var_handle->IsMethodTypeCompatible(access_mode, callsite_type.Get())) { + ThrowWrongMethodTypeException(var_handle->GetMethodTypeForAccessMode(self, access_mode), + callsite_type.Get()); + return false; + } -bool DoVarHandleWeakCompareAndSetAcquire(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); + if (is_var_args) { + uint32_t args[Instruction::kMaxVarArgRegs]; + inst->GetVarArgs(args, inst_data); + VarArgsInstructionOperands all_operands(args, inst->VRegA_45cc()); + NoReceiverInstructionOperands operands(&all_operands); + return DoVarHandleInvokeChecked(self, + var_handle, + callsite_type, + access_mode, + shadow_frame, + &operands, + result); + } else { + RangeInstructionOperands all_operands(inst->VRegC_4rcc(), inst->VRegA_4rcc()); + NoReceiverInstructionOperands operands(&all_operands); + return DoVarHandleInvokeChecked(self, + var_handle, + callsite_type, + access_mode, + shadow_frame, + &operands, + result); + } } -bool DoVarHandleWeakCompareAndSetPlain(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); +#define DO_VAR_HANDLE_ACCESSOR(_access_mode) \ +bool DoVarHandle ## _access_mode(Thread* self, \ + ShadowFrame& shadow_frame, \ + const Instruction* inst, \ + uint16_t inst_data, \ + JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { \ + const auto access_mode = mirror::VarHandle::AccessMode::k ## _access_mode; \ + return DoVarHandleInvokeCommon(self, shadow_frame, inst, inst_data, result, access_mode); \ } -bool DoVarHandleWeakCompareAndSetRelease(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result); -} +DO_VAR_HANDLE_ACCESSOR(CompareAndExchange) +DO_VAR_HANDLE_ACCESSOR(CompareAndExchangeAcquire) +DO_VAR_HANDLE_ACCESSOR(CompareAndExchangeRelease) +DO_VAR_HANDLE_ACCESSOR(CompareAndSet) +DO_VAR_HANDLE_ACCESSOR(Get) +DO_VAR_HANDLE_ACCESSOR(GetAcquire) +DO_VAR_HANDLE_ACCESSOR(GetAndAdd) +DO_VAR_HANDLE_ACCESSOR(GetAndAddAcquire) +DO_VAR_HANDLE_ACCESSOR(GetAndAddRelease) +DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseAnd) +DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseAndAcquire) +DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseAndRelease) +DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseOr) +DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseOrAcquire) +DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseOrRelease) +DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseXor) +DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseXorAcquire) +DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseXorRelease) +DO_VAR_HANDLE_ACCESSOR(GetAndSet) +DO_VAR_HANDLE_ACCESSOR(GetAndSetAcquire) +DO_VAR_HANDLE_ACCESSOR(GetAndSetRelease) +DO_VAR_HANDLE_ACCESSOR(GetOpaque) +DO_VAR_HANDLE_ACCESSOR(GetVolatile) +DO_VAR_HANDLE_ACCESSOR(Set) +DO_VAR_HANDLE_ACCESSOR(SetOpaque) +DO_VAR_HANDLE_ACCESSOR(SetRelease) +DO_VAR_HANDLE_ACCESSOR(SetVolatile) +DO_VAR_HANDLE_ACCESSOR(WeakCompareAndSet) +DO_VAR_HANDLE_ACCESSOR(WeakCompareAndSetAcquire) +DO_VAR_HANDLE_ACCESSOR(WeakCompareAndSetPlain) +DO_VAR_HANDLE_ACCESSOR(WeakCompareAndSetRelease) + +#undef DO_VAR_HANDLE_ACCESSOR template<bool is_range> bool DoInvokePolymorphic(Thread* self, @@ -1049,7 +936,8 @@ static ObjPtr<mirror::CallSite> InvokeBootstrapMethod(Thread* self, // The first parameter is a MethodHandles lookup instance. { - Handle<mirror::Class> lookup_class(hs.NewHandle(bootstrap->GetTargetClass())); + Handle<mirror::Class> lookup_class = + hs.NewHandle(shadow_frame.GetMethod()->GetDeclaringClass()); ObjPtr<mirror::MethodHandlesLookup> lookup = mirror::MethodHandlesLookup::Create(self, lookup_class); if (lookup.IsNull()) { diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 8180222e22..39a1db85d4 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -176,7 +176,8 @@ static inline bool DoInvoke(Thread* self, } const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c(); - ObjPtr<mirror::Object> receiver = (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC); + ObjPtr<mirror::Object> receiver = + (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC); ArtMethod* sf_method = shadow_frame.GetMethod(); ArtMethod* const called_method = FindMethodFromCode<type, do_access_check>( method_idx, &receiver, sf_method, self); @@ -645,7 +646,7 @@ EXPLICIT_DO_FAST_INVOKE_TEMPLATE_DECL(kVirtual); // invoke-virtual // Explicitly instantiate all DoInvokeVirtualQuick functions. #define EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(_is_range) \ - template REQUIRES_SHARED(Locks::mutator_lock_) \ + template REQUIRES_SHARED(Locks::mutator_lock_) \ bool DoInvokeVirtualQuick<_is_range>(Thread* self, ShadowFrame& shadow_frame, \ const Instruction* inst, uint16_t inst_data, \ JValue* result) diff --git a/runtime/interpreter/mterp/arm/entry.S b/runtime/interpreter/mterp/arm/entry.S index df4bcc66f3..7c7c527ef4 100644 --- a/runtime/interpreter/mterp/arm/entry.S +++ b/runtime/interpreter/mterp/arm/entry.S @@ -56,7 +56,7 @@ ENTRY ExecuteMterpImpl VREG_INDEX_TO_ADDR rREFS, r0 @ point to reference array in shadow frame ldr r0, [r2, #SHADOWFRAME_DEX_PC_OFFSET] @ Get starting dex_pc. add rPC, r1, r0, lsl #1 @ Create direct pointer to 1st dex opcode - .cfi_register DPC_PSEUDO_REG, rPC + CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) EXPORT_PC /* Starting ibase */ diff --git a/runtime/interpreter/mterp/arm/header.S b/runtime/interpreter/mterp/arm/header.S index 64ab9efa19..1f15f870ea 100644 --- a/runtime/interpreter/mterp/arm/header.S +++ b/runtime/interpreter/mterp/arm/header.S @@ -93,6 +93,8 @@ unspecified registers or condition codes. /* During bringup, we'll use the shadow frame model instead of rFP */ /* single-purpose registers, given names for clarity */ #define rPC r4 +#define CFI_DEX 4 // DWARF register number of the register holding dex-pc (xPC). +#define CFI_TMP 0 // DWARF register number of the first argument register (r0). #define rFP r5 #define rSELF r6 #define rINST r7 diff --git a/runtime/interpreter/mterp/arm64/entry.S b/runtime/interpreter/mterp/arm64/entry.S index 8d61210be8..cf38a2992d 100644 --- a/runtime/interpreter/mterp/arm64/entry.S +++ b/runtime/interpreter/mterp/arm64/entry.S @@ -46,7 +46,7 @@ ENTRY ExecuteMterpImpl add xREFS, xFP, w0, lsl #2 // point to reference array in shadow frame ldr w0, [x2, #SHADOWFRAME_DEX_PC_OFFSET] // Get starting dex_pc. add xPC, x1, w0, lsl #1 // Create direct pointer to 1st dex opcode - .cfi_register DPC_PSEUDO_REG, xPC + CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) EXPORT_PC /* Starting ibase */ diff --git a/runtime/interpreter/mterp/arm64/header.S b/runtime/interpreter/mterp/arm64/header.S index 9261b770d6..f0bf8ca34e 100644 --- a/runtime/interpreter/mterp/arm64/header.S +++ b/runtime/interpreter/mterp/arm64/header.S @@ -95,6 +95,8 @@ codes. /* During bringup, we'll use the shadow frame model instead of xFP */ /* single-purpose registers, given names for clarity */ #define xPC x20 +#define CFI_DEX 20 // DWARF register number of the register holding dex-pc (xPC). +#define CFI_TMP 0 // DWARF register number of the first argument register (r0). #define xFP x21 #define xSELF x22 #define xINST x23 diff --git a/runtime/interpreter/mterp/cfi_asm_support.h b/runtime/interpreter/mterp/cfi_asm_support.h index a97e153993..0df4eb4f81 100644 --- a/runtime/interpreter/mterp/cfi_asm_support.h +++ b/runtime/interpreter/mterp/cfi_asm_support.h @@ -18,14 +18,30 @@ #define ART_RUNTIME_INTERPRETER_MTERP_CFI_ASM_SUPPORT_H_ /* - * To keep track of the Dalvik PC, give assign it a magic register number that - * won't be confused with a pysical register. Then, standard .cfi directives - * will track the location of it so that it may be extracted during a stack - * unwind. + * Define the DEX PC (memory address of the currently interpreted bytecode) + * within the CFI stream of the current function (stored in .eh_frame). + * This allows libunwind to detect that the frame is in the interpreter, + * and to resolve the memory address into human readable Java method name. + * The CFI instruction is recognised by the magic bytes in the expression + * (we push magic "DEX1" constant on the DWARF stack and drop it again). * - * The Dalvik PC will be in either a physical registor, or the frame. - * Encoded from the ASCII string " DEX" -> 0x20 0x44 0x45 0x58 + * As with any other CFI opcode, the expression needs to be associated with + * a register. Any caller-save register will do as those are unused in CFI. + * Better solution would be to store the expression in Android-specific + * DWARF register (CFI registers don't have to correspond to real hardware + * registers), however, gdb handles any unknown registers very poorly. + * Similarly, we could also use some of the user-defined opcodes defined + * in the DWARF specification, but gdb doesn't support those either. + * + * The DEX PC is generally advanced in the middle of the bytecode handler, + * which will result in the reported DEX PC to be off by an instruction. + * Therefore the macro allows adding/subtracting an offset to compensate. + * TODO: Add the offsets to handlers to get line-accurate DEX PC reporting. */ -#define DPC_PSEUDO_REG 0x20444558 +#define CFI_DEFINE_DEX_PC_WITH_OFFSET(tmpReg, dexReg, dexOffset) .cfi_escape \ + 0x16 /* DW_CFA_val_expression */, tmpReg, 0x09 /* size */, \ + 0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = "DEX1" */ \ + 0x13 /* DW_OP_drop */, \ + 0x92 /* DW_OP_bregx */, dexReg, (dexOffset & 0x7F) /* 1-byte SLEB128 */ #endif // ART_RUNTIME_INTERPRETER_MTERP_CFI_ASM_SUPPORT_H_ diff --git a/runtime/interpreter/mterp/gen_mterp.py b/runtime/interpreter/mterp/gen_mterp.py index 1c9af30d0a..40d99df037 100755 --- a/runtime/interpreter/mterp/gen_mterp.py +++ b/runtime/interpreter/mterp/gen_mterp.py @@ -22,7 +22,7 @@ import sys, string, re, time from string import Template -interp_defs_file = "../../dex_instruction_list.h" # need opcode list +interp_defs_file = "../../dex/dex_instruction_list.h" # need opcode list kNumPackedOpcodes = 256 splitops = False diff --git a/runtime/interpreter/mterp/mips/entry.S b/runtime/interpreter/mterp/mips/entry.S index 41b5d5650d..d342354969 100644 --- a/runtime/interpreter/mterp/mips/entry.S +++ b/runtime/interpreter/mterp/mips/entry.S @@ -54,7 +54,7 @@ ExecuteMterpImpl: EAS2(rREFS, rFP, a0) # point to reference array in shadow frame lw a0, SHADOWFRAME_DEX_PC_OFFSET(a2) # Get starting dex_pc EAS1(rPC, a1, a0) # Create direct pointer to 1st dex opcode - .cfi_register DPC_PSEUDO_REG, rPC + CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) EXPORT_PC() diff --git a/runtime/interpreter/mterp/mips/header.S b/runtime/interpreter/mterp/mips/header.S index 0f7a6f1116..014628f415 100644 --- a/runtime/interpreter/mterp/mips/header.S +++ b/runtime/interpreter/mterp/mips/header.S @@ -61,6 +61,8 @@ /* single-purpose registers, given names for clarity */ #define rPC s0 +#define CFI_DEX 16 // DWARF register number of the register holding dex-pc (s0). +#define CFI_TMP 4 // DWARF register number of the first argument register (a0). #define rFP s1 #define rSELF s2 #define rIBASE s3 diff --git a/runtime/interpreter/mterp/mips64/entry.S b/runtime/interpreter/mterp/mips64/entry.S index 841a817569..ed965aa201 100644 --- a/runtime/interpreter/mterp/mips64/entry.S +++ b/runtime/interpreter/mterp/mips64/entry.S @@ -73,7 +73,7 @@ ExecuteMterpImpl: dlsa rREFS, v0, rFP, 2 lw v0, SHADOWFRAME_DEX_PC_OFFSET(a2) dlsa rPC, v0, a1, 1 - .cfi_register DPC_PSEUDO_REG, rPC + CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) EXPORT_PC /* Starting ibase */ diff --git a/runtime/interpreter/mterp/mips64/header.S b/runtime/interpreter/mterp/mips64/header.S index 2b550cb533..4947aff38e 100644 --- a/runtime/interpreter/mterp/mips64/header.S +++ b/runtime/interpreter/mterp/mips64/header.S @@ -90,6 +90,8 @@ The following registers have fixed assignments: /* During bringup, we'll use the shadow frame model instead of rFP */ /* single-purpose registers, given names for clarity */ #define rPC s0 +#define CFI_DEX 16 // DWARF register number of the register holding dex-pc (s0). +#define CFI_TMP 4 // DWARF register number of the first argument register (a0). #define rFP s1 #define rSELF s2 #define rINST s3 diff --git a/runtime/interpreter/mterp/out/mterp_arm.S b/runtime/interpreter/mterp/out/mterp_arm.S index f3c1124ec4..5c1a13b9d6 100644 --- a/runtime/interpreter/mterp/out/mterp_arm.S +++ b/runtime/interpreter/mterp/out/mterp_arm.S @@ -100,6 +100,8 @@ unspecified registers or condition codes. /* During bringup, we'll use the shadow frame model instead of rFP */ /* single-purpose registers, given names for clarity */ #define rPC r4 +#define CFI_DEX 4 // DWARF register number of the register holding dex-pc (xPC). +#define CFI_TMP 0 // DWARF register number of the first argument register (r0). #define rFP r5 #define rSELF r6 #define rINST r7 @@ -375,7 +377,7 @@ ENTRY ExecuteMterpImpl VREG_INDEX_TO_ADDR rREFS, r0 @ point to reference array in shadow frame ldr r0, [r2, #SHADOWFRAME_DEX_PC_OFFSET] @ Get starting dex_pc. add rPC, r1, r0, lsl #1 @ Create direct pointer to 1st dex opcode - .cfi_register DPC_PSEUDO_REG, rPC + CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) EXPORT_PC /* Starting ibase */ diff --git a/runtime/interpreter/mterp/out/mterp_arm64.S b/runtime/interpreter/mterp/out/mterp_arm64.S index 347d54f705..72446ba082 100644 --- a/runtime/interpreter/mterp/out/mterp_arm64.S +++ b/runtime/interpreter/mterp/out/mterp_arm64.S @@ -102,6 +102,8 @@ codes. /* During bringup, we'll use the shadow frame model instead of xFP */ /* single-purpose registers, given names for clarity */ #define xPC x20 +#define CFI_DEX 20 // DWARF register number of the register holding dex-pc (xPC). +#define CFI_TMP 0 // DWARF register number of the first argument register (r0). #define xFP x21 #define xSELF x22 #define xINST x23 @@ -405,7 +407,7 @@ ENTRY ExecuteMterpImpl add xREFS, xFP, w0, lsl #2 // point to reference array in shadow frame ldr w0, [x2, #SHADOWFRAME_DEX_PC_OFFSET] // Get starting dex_pc. add xPC, x1, w0, lsl #1 // Create direct pointer to 1st dex opcode - .cfi_register DPC_PSEUDO_REG, xPC + CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) EXPORT_PC /* Starting ibase */ diff --git a/runtime/interpreter/mterp/out/mterp_mips.S b/runtime/interpreter/mterp/out/mterp_mips.S index 1687afa58a..d5861b28a7 100644 --- a/runtime/interpreter/mterp/out/mterp_mips.S +++ b/runtime/interpreter/mterp/out/mterp_mips.S @@ -68,6 +68,8 @@ /* single-purpose registers, given names for clarity */ #define rPC s0 +#define CFI_DEX 16 // DWARF register number of the register holding dex-pc (s0). +#define CFI_TMP 4 // DWARF register number of the first argument register (a0). #define rFP s1 #define rSELF s2 #define rIBASE s3 @@ -788,7 +790,7 @@ ExecuteMterpImpl: EAS2(rREFS, rFP, a0) # point to reference array in shadow frame lw a0, SHADOWFRAME_DEX_PC_OFFSET(a2) # Get starting dex_pc EAS1(rPC, a1, a0) # Create direct pointer to 1st dex opcode - .cfi_register DPC_PSEUDO_REG, rPC + CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) EXPORT_PC() diff --git a/runtime/interpreter/mterp/out/mterp_mips64.S b/runtime/interpreter/mterp/out/mterp_mips64.S index 559c72bb0c..5224df92be 100644 --- a/runtime/interpreter/mterp/out/mterp_mips64.S +++ b/runtime/interpreter/mterp/out/mterp_mips64.S @@ -97,6 +97,8 @@ The following registers have fixed assignments: /* During bringup, we'll use the shadow frame model instead of rFP */ /* single-purpose registers, given names for clarity */ #define rPC s0 +#define CFI_DEX 16 // DWARF register number of the register holding dex-pc (s0). +#define CFI_TMP 4 // DWARF register number of the first argument register (a0). #define rFP s1 #define rSELF s2 #define rINST s3 @@ -408,7 +410,7 @@ ExecuteMterpImpl: dlsa rREFS, v0, rFP, 2 lw v0, SHADOWFRAME_DEX_PC_OFFSET(a2) dlsa rPC, v0, a1, 1 - .cfi_register DPC_PSEUDO_REG, rPC + CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) EXPORT_PC /* Starting ibase */ diff --git a/runtime/interpreter/mterp/out/mterp_x86.S b/runtime/interpreter/mterp/out/mterp_x86.S index 0613c9d12e..f98fa5b74f 100644 --- a/runtime/interpreter/mterp/out/mterp_x86.S +++ b/runtime/interpreter/mterp/out/mterp_x86.S @@ -164,6 +164,8 @@ unspecified registers or condition codes. /* single-purpose registers, given names for clarity */ #define rSELF IN_ARG0(%esp) #define rPC %esi +#define CFI_DEX 6 // DWARF register number of the register holding dex-pc (esi). +#define CFI_TMP 0 // DWARF register number of the first argument register (eax). #define rFP %edi #define rINST %ebx #define rINSTw %bx @@ -380,7 +382,7 @@ SYMBOL(ExecuteMterpImpl): leal (rFP, %eax, 4), rREFS movl SHADOWFRAME_DEX_PC_OFFSET(%edx), %eax lea (%ecx, %eax, 2), rPC - .cfi_register DPC_PSEUDO_REG, rPC + CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) EXPORT_PC /* Set up for backwards branches & osr profiling */ diff --git a/runtime/interpreter/mterp/out/mterp_x86_64.S b/runtime/interpreter/mterp/out/mterp_x86_64.S index aa91db3b61..d82a2d2eb0 100644 --- a/runtime/interpreter/mterp/out/mterp_x86_64.S +++ b/runtime/interpreter/mterp/out/mterp_x86_64.S @@ -164,6 +164,8 @@ unspecified registers or condition codes. /* single-purpose registers, given names for clarity */ #define rSELF SELF_SPILL(%rsp) #define rPC %r12 +#define CFI_DEX 12 // DWARF register number of the register holding dex-pc (rPC). +#define CFI_TMP 5 // DWARF register number of the first argument register (rdi). #define rFP %r13 #define rINST %ebx #define rINSTq %rbx @@ -363,7 +365,7 @@ SYMBOL(ExecuteMterpImpl): leaq (rFP, %rax, 4), rREFS movl SHADOWFRAME_DEX_PC_OFFSET(IN_ARG2), %eax leaq (IN_ARG1, %rax, 2), rPC - .cfi_register DPC_PSEUDO_REG, rPC + CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) EXPORT_PC /* Starting ibase */ diff --git a/runtime/interpreter/mterp/x86/entry.S b/runtime/interpreter/mterp/x86/entry.S index 10ca8366de..324637bf9a 100644 --- a/runtime/interpreter/mterp/x86/entry.S +++ b/runtime/interpreter/mterp/x86/entry.S @@ -61,7 +61,7 @@ SYMBOL(ExecuteMterpImpl): leal (rFP, %eax, 4), rREFS movl SHADOWFRAME_DEX_PC_OFFSET(%edx), %eax lea (%ecx, %eax, 2), rPC - .cfi_register DPC_PSEUDO_REG, rPC + CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) EXPORT_PC /* Set up for backwards branches & osr profiling */ diff --git a/runtime/interpreter/mterp/x86/header.S b/runtime/interpreter/mterp/x86/header.S index 0e585e86f0..2e3bbdf6f7 100644 --- a/runtime/interpreter/mterp/x86/header.S +++ b/runtime/interpreter/mterp/x86/header.S @@ -157,6 +157,8 @@ unspecified registers or condition codes. /* single-purpose registers, given names for clarity */ #define rSELF IN_ARG0(%esp) #define rPC %esi +#define CFI_DEX 6 // DWARF register number of the register holding dex-pc (esi). +#define CFI_TMP 0 // DWARF register number of the first argument register (eax). #define rFP %edi #define rINST %ebx #define rINSTw %bx diff --git a/runtime/interpreter/mterp/x86_64/entry.S b/runtime/interpreter/mterp/x86_64/entry.S index d85ef7fe24..2f69226206 100644 --- a/runtime/interpreter/mterp/x86_64/entry.S +++ b/runtime/interpreter/mterp/x86_64/entry.S @@ -58,7 +58,7 @@ SYMBOL(ExecuteMterpImpl): leaq (rFP, %rax, 4), rREFS movl SHADOWFRAME_DEX_PC_OFFSET(IN_ARG2), %eax leaq (IN_ARG1, %rax, 2), rPC - .cfi_register DPC_PSEUDO_REG, rPC + CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) EXPORT_PC /* Starting ibase */ diff --git a/runtime/interpreter/mterp/x86_64/header.S b/runtime/interpreter/mterp/x86_64/header.S index a3ef8953ca..eabaade4e7 100644 --- a/runtime/interpreter/mterp/x86_64/header.S +++ b/runtime/interpreter/mterp/x86_64/header.S @@ -157,6 +157,8 @@ unspecified registers or condition codes. /* single-purpose registers, given names for clarity */ #define rSELF SELF_SPILL(%rsp) #define rPC %r12 +#define CFI_DEX 12 // DWARF register number of the register holding dex-pc (rPC). +#define CFI_TMP 5 // DWARF register number of the first argument register (rdi). #define rFP %r13 #define rINST %ebx #define rINSTq %rbx diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index 85acc71377..f8dd8293ca 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -235,6 +235,20 @@ void UnstartedRuntime::UnstartedClassForNameLong( UnstartedClassForNameCommon(self, shadow_frame, result, arg_offset, true, "Class.forName"); } +void UnstartedRuntime::UnstartedClassGetPrimitiveClass( + Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) { + ObjPtr<mirror::String> class_name = GetClassName(self, shadow_frame, arg_offset); + ObjPtr<mirror::Class> klass = mirror::Class::GetPrimitiveClass(class_name); + if (UNLIKELY(klass == nullptr)) { + DCHECK(self->IsExceptionPending()); + AbortTransactionOrFail(self, + "Class.getPrimitiveClass() failed: %s", + self->GetException()->GetDetailMessage()->ToModifiedUtf8().c_str()); + return; + } + result->SetL(klass); +} + void UnstartedRuntime::UnstartedClassClassForName( Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) { UnstartedClassForNameCommon(self, shadow_frame, result, arg_offset, true, "Class.classForName"); @@ -738,12 +752,6 @@ void UnstartedRuntime::UnstartedVmClassLoaderFindLoadedClass( } } -void UnstartedRuntime::UnstartedVoidLookupType( - Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow_frame ATTRIBUTE_UNUSED, JValue* result, - size_t arg_offset ATTRIBUTE_UNUSED) { - result->SetL(Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V')); -} - // Arraycopy emulation. // Note: we can't use any fast copy functions, as they are not available under transaction. diff --git a/runtime/interpreter/unstarted_runtime_list.h b/runtime/interpreter/unstarted_runtime_list.h index c029e07432..3cc598aed7 100644 --- a/runtime/interpreter/unstarted_runtime_list.h +++ b/runtime/interpreter/unstarted_runtime_list.h @@ -23,6 +23,7 @@ V(CharacterToUpperCase, "int java.lang.Character.toUpperCase(int)") \ V(ClassForName, "java.lang.Class java.lang.Class.forName(java.lang.String)") \ V(ClassForNameLong, "java.lang.Class java.lang.Class.forName(java.lang.String, boolean, java.lang.ClassLoader)") \ + V(ClassGetPrimitiveClass, "java.lang.Class java.lang.Class.getPrimitiveClass(java.lang.String)") \ V(ClassClassForName, "java.lang.Class java.lang.Class.classForName(java.lang.String, boolean, java.lang.ClassLoader)") \ V(ClassNewInstance, "java.lang.Object java.lang.Class.newInstance()") \ V(ClassGetDeclaredField, "java.lang.reflect.Field java.lang.Class.getDeclaredField(java.lang.String)") \ @@ -36,7 +37,6 @@ V(ClassLoaderGetResourceAsStream, "java.io.InputStream java.lang.ClassLoader.getResourceAsStream(java.lang.String)") \ V(ConstructorNewInstance0, "java.lang.Object java.lang.reflect.Constructor.newInstance0(java.lang.Object[])") \ V(VmClassLoaderFindLoadedClass, "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") \ - V(VoidLookupType, "java.lang.Class java.lang.Void.lookupType()") \ V(SystemArraycopy, "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)") \ V(SystemArraycopyByte, "void java.lang.System.arraycopy(byte[], int, byte[], int, int)") \ V(SystemArraycopyChar, "void java.lang.System.arraycopy(char[], int, char[], int, int)") \ diff --git a/runtime/java_vm_ext.h b/runtime/java_vm_ext.h index 8c81c2565d..ac20afecd4 100644 --- a/runtime/java_vm_ext.h +++ b/runtime/java_vm_ext.h @@ -225,7 +225,7 @@ class JavaVMExt : public JavaVM { // Extra checking. bool check_jni_; - bool force_copy_; + const bool force_copy_; const bool tracing_enabled_; // Extra diagnostics. diff --git a/runtime/jdwp/jdwp_adb.cc b/runtime/jdwp/jdwp_adb.cc index d68430f3ac..481aff91f8 100644 --- a/runtime/jdwp/jdwp_adb.cc +++ b/runtime/jdwp/jdwp_adb.cc @@ -38,8 +38,7 @@ * domain stream socket (@jdwp-control) that is opened by the * ADB daemon. * - * 2/ it then sends the current process PID as a string of 4 hexadecimal - * chars (no terminating zero) + * 2/ it then sends the current process PID as an int32_t. * * 3/ then, it uses recvmsg to receive file descriptors from the * daemon. each incoming file descriptor is a pass-through to @@ -225,7 +224,6 @@ bool JdwpAdbState::Accept() { if (ControlSock() == -1) { int sleep_ms = 500; const int sleep_max_ms = 2*1000; - char buff[5]; int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); if (sock < 0) { @@ -247,8 +245,7 @@ bool JdwpAdbState::Accept() { } } - snprintf(buff, sizeof(buff), "%04x", getpid()); - buff[4] = 0; + int32_t pid = getpid(); for (;;) { /* @@ -277,9 +274,9 @@ bool JdwpAdbState::Accept() { #endif /* now try to send our pid to the ADB daemon */ - ret = TEMP_FAILURE_RETRY(send(control_sock, buff, 4, 0)); - if (ret == 4) { - VLOG(jdwp) << StringPrintf("PID sent as '%.*s' to ADB", 4, buff); + ret = TEMP_FAILURE_RETRY(send(control_sock, &pid, sizeof(pid), 0)); + if (ret == sizeof(pid)) { + VLOG(jdwp) << "PID " << pid << " sent to ADB"; break; } diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc index de4d02edaf..dcb4a20b5f 100644 --- a/runtime/jit/profile_compilation_info.cc +++ b/runtime/jit/profile_compilation_info.cc @@ -168,9 +168,10 @@ bool ProfileCompilationInfo::AddMethodIndex(MethodHotness::Flag flags, return data->AddMethod(flags, method_idx); } -bool ProfileCompilationInfo::AddMethods(const std::vector<ProfileMethodInfo>& methods) { +bool ProfileCompilationInfo::AddMethods(const std::vector<ProfileMethodInfo>& methods, + MethodHotness::Flag flags) { for (const ProfileMethodInfo& method : methods) { - if (!AddMethod(method)) { + if (!AddMethod(method, flags)) { return false; } } @@ -644,15 +645,26 @@ bool ProfileCompilationInfo::AddMethod(const std::string& dex_location, uint32_t dex_checksum, uint16_t method_index, uint32_t num_method_ids, - const OfflineProfileMethodInfo& pmi) { + const OfflineProfileMethodInfo& pmi, + MethodHotness::Flag flags) { DexFileData* const data = GetOrAddDexFileData(GetProfileDexFileKey(dex_location), dex_checksum, num_method_ids); - if (data == nullptr) { // checksum mismatch + if (data == nullptr) { + // The data is null if there is a mismatch in the checksum or number of method ids. return false; } + // Add the method. InlineCacheMap* inline_cache = data->FindOrAddMethod(method_index); + if (inline_cache == nullptr) { + // Happens if the method index is outside the range (i.e. is greater then the number + // of methods in the dex file). This should not happen during normal execution, + // But tools (e.g. boot image aggregation tools) and tests stress this behaviour. + return false; + } + + data->SetMethodHotness(method_index, flags); if (pmi.inline_caches == nullptr) { // If we don't have inline caches return success right away. @@ -691,12 +703,16 @@ bool ProfileCompilationInfo::AddMethod(const std::string& dex_location, return true; } -bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi) { +bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi, MethodHotness::Flag flags) { DexFileData* const data = GetOrAddDexFileData(pmi.ref.dex_file); if (data == nullptr) { // checksum mismatch return false; } InlineCacheMap* inline_cache = data->FindOrAddMethod(pmi.ref.index); + if (inline_cache == nullptr) { + return false; + } + data->SetMethodHotness(pmi.ref.index, flags); for (const ProfileMethodInfo::ProfileInlineCache& cache : pmi.inline_caches) { if (cache.is_missing_types) { @@ -811,6 +827,9 @@ bool ProfileCompilationInfo::ReadMethods(SafeBuffer& buffer, uint16_t method_index = last_method_index + diff_with_last_method_index; last_method_index = method_index; InlineCacheMap* inline_cache = data->FindOrAddMethod(method_index); + if (inline_cache == nullptr) { + return false; + } if (!ReadInlineCache(buffer, number_of_dex_files, dex_profile_index_remap, @@ -1521,6 +1540,9 @@ bool ProfileCompilationInfo::MergeWith(const ProfileCompilationInfo& other, for (const auto& other_method_it : other_dex_data->method_map) { uint16_t other_method_index = other_method_it.first; InlineCacheMap* inline_cache = dex_data->FindOrAddMethod(other_method_index); + if (inline_cache == nullptr) { + return false; + } const auto& other_inline_cache = other_method_it.second; for (const auto& other_ic_it : other_inline_cache) { uint16_t other_dex_pc = other_ic_it.first; @@ -1955,6 +1977,10 @@ bool ProfileCompilationInfo::IsEmpty() const { ProfileCompilationInfo::InlineCacheMap* ProfileCompilationInfo::DexFileData::FindOrAddMethod(uint16_t method_index) { + if (method_index >= num_method_ids) { + LOG(ERROR) << "Invalid method index " << method_index << ". num_method_ids=" << num_method_ids; + return nullptr; + } return &(method_map.FindOrAdd( method_index, InlineCacheMap(std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)))->second); @@ -1967,12 +1993,8 @@ bool ProfileCompilationInfo::DexFileData::AddMethod(MethodHotness::Flag flags, s return false; } - if ((flags & MethodHotness::kFlagStartup) != 0) { - method_bitmap.StoreBit(MethodBitIndex(/*startup*/ true, index), /*value*/ true); - } - if ((flags & MethodHotness::kFlagPostStartup) != 0) { - method_bitmap.StoreBit(MethodBitIndex(/*startup*/ false, index), /*value*/ true); - } + SetMethodHotness(index, flags); + if ((flags & MethodHotness::kFlagHot) != 0) { method_map.FindOrAdd( index, @@ -1981,6 +2003,17 @@ bool ProfileCompilationInfo::DexFileData::AddMethod(MethodHotness::Flag flags, s return true; } +void ProfileCompilationInfo::DexFileData::SetMethodHotness(size_t index, + MethodHotness::Flag flags) { + DCHECK_LT(index, num_method_ids); + if ((flags & MethodHotness::kFlagStartup) != 0) { + method_bitmap.StoreBit(MethodBitIndex(/*startup*/ true, index), /*value*/ true); + } + if ((flags & MethodHotness::kFlagPostStartup) != 0) { + method_bitmap.StoreBit(MethodBitIndex(/*startup*/ false, index), /*value*/ true); + } +} + ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::DexFileData::GetHotnessInfo( uint32_t dex_method_index) const { MethodHotness ret; diff --git a/runtime/jit/profile_compilation_info.h b/runtime/jit/profile_compilation_info.h index 1973f3f09e..5488a9e81e 100644 --- a/runtime/jit/profile_compilation_info.h +++ b/runtime/jit/profile_compilation_info.h @@ -241,7 +241,7 @@ class ProfileCompilationInfo { ~ProfileCompilationInfo(); // Add the given methods to the current profile object. - bool AddMethods(const std::vector<ProfileMethodInfo>& methods); + bool AddMethods(const std::vector<ProfileMethodInfo>& methods, MethodHotness::Flag flags); // Add the given classes to the current profile object. bool AddClasses(const std::set<DexCacheResolvedClasses>& resolved_classes); @@ -278,7 +278,7 @@ class ProfileCompilationInfo { bool AddMethodIndex(MethodHotness::Flag flags, const MethodReference& ref); // Add a method to the profile using its online representation (containing runtime structures). - bool AddMethod(const ProfileMethodInfo& pmi); + bool AddMethod(const ProfileMethodInfo& pmi, MethodHotness::Flag flags); // Bulk add sampled methods and/or hot methods for a single dex, fast since it only has one // GetOrAddDexFileData call. @@ -500,6 +500,7 @@ class ProfileCompilationInfo { } } + void SetMethodHotness(size_t index, MethodHotness::Flag flags); MethodHotness GetHotnessInfo(uint32_t dex_method_index) const; // The allocator used to allocate new inline cache maps. @@ -559,7 +560,8 @@ class ProfileCompilationInfo { uint32_t dex_checksum, uint16_t method_index, uint32_t num_method_ids, - const OfflineProfileMethodInfo& pmi); + const OfflineProfileMethodInfo& pmi, + MethodHotness::Flag flags); // Add a class index to the profile. bool AddClassIndex(const std::string& dex_location, diff --git a/runtime/jit/profile_compilation_info_test.cc b/runtime/jit/profile_compilation_info_test.cc index 4ac11ee422..e6917956ae 100644 --- a/runtime/jit/profile_compilation_info_test.cc +++ b/runtime/jit/profile_compilation_info_test.cc @@ -80,7 +80,8 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { uint16_t method_index, const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi, ProfileCompilationInfo* info) { - return info->AddMethod(dex_location, checksum, method_index, kMaxMethodIds, pmi); + return info->AddMethod( + dex_location, checksum, method_index, kMaxMethodIds, pmi, Hotness::kFlagPostStartup); } bool AddClass(const std::string& dex_location, @@ -99,7 +100,8 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { bool SaveProfilingInfo( const std::string& filename, const std::vector<ArtMethod*>& methods, - const std::set<DexCacheResolvedClasses>& resolved_classes) { + const std::set<DexCacheResolvedClasses>& resolved_classes, + Hotness::Flag flags) { ProfileCompilationInfo info; std::vector<ProfileMethodInfo> profile_methods; ScopedObjectAccess soa(Thread::Current()); @@ -107,7 +109,7 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { profile_methods.emplace_back( MethodReference(method->GetDexFile(), method->GetDexMethodIndex())); } - if (!info.AddMethods(profile_methods) || !info.AddClasses(resolved_classes)) { + if (!info.AddMethods(profile_methods, flags) || !info.AddClasses(resolved_classes)) { return false; } if (info.GetNumberOfMethods() != profile_methods.size()) { @@ -130,6 +132,7 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { bool SaveProfilingInfoWithFakeInlineCaches( const std::string& filename, const std::vector<ArtMethod*>& methods, + Hotness::Flag flags, /*out*/ SafeMap<ArtMethod*, ProfileMethodInfo>* profile_methods_map) { ProfileCompilationInfo info; std::vector<ProfileMethodInfo> profile_methods; @@ -170,7 +173,8 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { profile_methods_map->Put(method, pmi); } - if (!info.AddMethods(profile_methods) || info.GetNumberOfMethods() != profile_methods.size()) { + if (!info.AddMethods(profile_methods, flags) + || info.GetNumberOfMethods() != profile_methods.size()) { return false; } return info.Save(filename, nullptr); @@ -345,7 +349,8 @@ TEST_F(ProfileCompilationInfoTest, SaveArtMethods) { // Save virtual methods from Main. std::set<DexCacheResolvedClasses> resolved_classes; std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;"); - ASSERT_TRUE(SaveProfilingInfo(profile.GetFilename(), main_methods, resolved_classes)); + ASSERT_TRUE(SaveProfilingInfo( + profile.GetFilename(), main_methods, resolved_classes, Hotness::kFlagPostStartup)); // Check that what we saved is in the profile. ProfileCompilationInfo info1; @@ -354,14 +359,16 @@ TEST_F(ProfileCompilationInfoTest, SaveArtMethods) { { ScopedObjectAccess soa(self); for (ArtMethod* m : main_methods) { - ASSERT_TRUE(info1.GetMethodHotness( - MethodReference(m->GetDexFile(), m->GetDexMethodIndex())).IsHot()); + Hotness h = info1.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); + ASSERT_TRUE(h.IsHot()); + ASSERT_TRUE(h.IsPostStartup()); } } // Save virtual methods from Second. std::vector<ArtMethod*> second_methods = GetVirtualMethods(class_loader, "LSecond;"); - ASSERT_TRUE(SaveProfilingInfo(profile.GetFilename(), second_methods, resolved_classes)); + ASSERT_TRUE(SaveProfilingInfo( + profile.GetFilename(), second_methods, resolved_classes, Hotness::kFlagStartup)); // Check that what we saved is in the profile (methods form Main and Second). ProfileCompilationInfo info2; @@ -371,12 +378,14 @@ TEST_F(ProfileCompilationInfoTest, SaveArtMethods) { { ScopedObjectAccess soa(self); for (ArtMethod* m : main_methods) { - ASSERT_TRUE( - info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())).IsHot()); + Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); + ASSERT_TRUE(h.IsHot()); + ASSERT_TRUE(h.IsPostStartup()); } for (ArtMethod* m : second_methods) { - ASSERT_TRUE( - info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())).IsHot()); + Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); + ASSERT_TRUE(h.IsHot()); + ASSERT_TRUE(h.IsStartup()); } } } @@ -730,7 +739,7 @@ TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) { SafeMap<ArtMethod*, ProfileMethodInfo> profile_methods_map; ASSERT_TRUE(SaveProfilingInfoWithFakeInlineCaches( - profile.GetFilename(), main_methods, &profile_methods_map)); + profile.GetFilename(), main_methods, Hotness::kFlagStartup, &profile_methods_map)); // Check that what we saved is in the profile. ProfileCompilationInfo info; @@ -739,8 +748,9 @@ TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) { { ScopedObjectAccess soa(self); for (ArtMethod* m : main_methods) { - ASSERT_TRUE( - info.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())).IsHot()); + Hotness h = info.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); + ASSERT_TRUE(h.IsHot()); + ASSERT_TRUE(h.IsStartup()); const ProfileMethodInfo& pmi = profile_methods_map.find(m)->second; std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> offline_pmi = info.GetMethod(m->GetDexFile()->GetLocation(), diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc index 8f0ac33594..53f48644f2 100644 --- a/runtime/jit/profile_saver.cc +++ b/runtime/jit/profile_saver.cc @@ -511,7 +511,7 @@ bool ProfileSaver::ProcessProfilingInfo(bool force_save, /*out*/uint16_t* number uint64_t last_save_number_of_methods = info.GetNumberOfMethods(); uint64_t last_save_number_of_classes = info.GetNumberOfResolvedClasses(); - info.AddMethods(profile_methods); + info.AddMethods(profile_methods, ProfileCompilationInfo::MethodHotness::kFlagPostStartup); auto profile_cache_it = profile_cache_.find(filename); if (profile_cache_it != profile_cache_.end()) { info.MergeWith(*(profile_cache_it->second)); diff --git a/runtime/jni_env_ext.h b/runtime/jni_env_ext.h index 0e8fd03057..291ac48e86 100644 --- a/runtime/jni_env_ext.h +++ b/runtime/jni_env_ext.h @@ -96,6 +96,15 @@ class JNIEnvExt : public JNIEnv { } Thread* GetSelf() const { return self_; } + uint32_t GetCritical() const { return critical_; } + void SetCritical(uint32_t new_critical) { critical_ = new_critical; } + uint64_t GetCriticalStartUs() const { return critical_start_us_; } + void SetCriticalStartUs(uint64_t new_critical_start_us) { + critical_start_us_ = new_critical_start_us; + } + const JNINativeInterface* GetUncheckedFunctions() const { + return unchecked_functions_; + } JavaVMExt* GetVm() const { return vm_; } bool IsRuntimeDeleted() const { return runtime_deleted_; } @@ -190,9 +199,7 @@ class JNIEnvExt : public JNIEnv { // If we are a JNI env for a daemon thread with a deleted runtime. bool runtime_deleted_; - friend class CheckJNI; friend class JNI; - friend class ScopedCheck; friend class ScopedJniEnvLocalRefState; friend class Thread; ART_FRIEND_TEST(JniInternalTest, JNIEnvExtOffsets); diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index 666fb98354..cd4d9543be 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -90,7 +90,8 @@ static bool IsCallerInBootClassPath(Thread* self) REQUIRES_SHARED(Locks::mutator template<typename T> ALWAYS_INLINE static bool ShouldBlockAccessToMember(T* member, Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) { - return hiddenapi::ShouldBlockAccessToMember(member, self, IsCallerInBootClassPath); + return hiddenapi::ShouldBlockAccessToMember( + member, self, IsCallerInBootClassPath, hiddenapi::kJNI); } // Helpers to call instrumentation functions for fields. These take jobjects so we don't need to set diff --git a/runtime/lock_word.h b/runtime/lock_word.h index fac1a7597d..e89beb6d41 100644 --- a/runtime/lock_word.h +++ b/runtime/lock_word.h @@ -34,7 +34,9 @@ class Monitor; /* The lock value itself as stored in mirror::Object::monitor_. The two most significant bits of * the state. The four possible states are fat locked, thin/unlocked, hash code, and forwarding - * address. When the lock word is in the "thin" state and its bits are formatted as follows: + * address. + * + * When the lock word is in the "thin" state and its bits are formatted as follows: * * |33|2|2|222222221111|1111110000000000| * |10|9|8|765432109876|5432109876543210| @@ -59,7 +61,7 @@ class Monitor; * |11|0| ForwardingAddress | * * The `r` bit stores the read barrier state. - * The `m` bit stores the mark state. + * The `m` bit stores the mark bit state. */ class LockWord { public: diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc index 2701ec66a4..9b21e1d9bf 100644 --- a/runtime/method_handles.cc +++ b/runtime/method_handles.cc @@ -346,7 +346,7 @@ inline bool ConvertAndCopyArgumentsFromCallerFrame( return false; } - ShadowFrameGetter getter(operands, caller_frame); + ShadowFrameGetter getter(caller_frame, operands); ShadowFrameSetter setter(callee_frame, first_dest_reg); return PerformConversions<ShadowFrameGetter, ShadowFrameSetter>(self, callsite_type, diff --git a/runtime/method_handles.h b/runtime/method_handles.h index 6ffd1a81fc..3b1bf2ee66 100644 --- a/runtime/method_handles.h +++ b/runtime/method_handles.h @@ -130,8 +130,10 @@ bool PerformConversions(Thread* self, // arguments while performing standard argument conversions. class ShadowFrameGetter { public: - ShadowFrameGetter(const InstructionOperands* const operands, const ShadowFrame& shadow_frame) - : operands_(operands), operand_index_(0), shadow_frame_(shadow_frame) {} + ShadowFrameGetter(const ShadowFrame& shadow_frame, + const InstructionOperands* const operands, + size_t operand_index = 0u) + : shadow_frame_(shadow_frame), operands_(operands), operand_index_(operand_index) {} ALWAYS_INLINE uint32_t Get() REQUIRES_SHARED(Locks::mutator_lock_) { return shadow_frame_.GetVReg(Next()); @@ -151,26 +153,24 @@ class ShadowFrameGetter { operand_index_ += 1; return next; } + uint32_t NextLong() { const uint32_t next = operands_->GetOperand(operand_index_); operand_index_ += 2; return next; } - const InstructionOperands* const operands_; - size_t operand_index_; // the next register operand to read from frame const ShadowFrame& shadow_frame_; + const InstructionOperands* const operands_; // the set of register operands to read + size_t operand_index_; // the next register operand to read from frame }; // A convenience class that allows values to be written to a given shadow frame, // starting at location |first_dst_reg|. class ShadowFrameSetter { public: - ShadowFrameSetter(ShadowFrame* shadow_frame, - size_t first_dst_reg) : - shadow_frame_(shadow_frame), - arg_index_(first_dst_reg) { - } + ShadowFrameSetter(ShadowFrame* shadow_frame, size_t first_dst_reg) + : shadow_frame_(shadow_frame), arg_index_(first_dst_reg) {} ALWAYS_INLINE void Set(uint32_t value) REQUIRES_SHARED(Locks::mutator_lock_) { shadow_frame_->SetVReg(arg_index_++, value); diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 36388eb3aa..86d538ec80 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -550,7 +550,7 @@ inline bool Class::IsSubClass(ObjPtr<Class> klass) { current = current->GetSuperClass(); } while (current != nullptr); - if (kIsDebugBuild) { + if (kIsDebugBuild && kBitstringSubtypeCheckEnabled) { ObjPtr<mirror::Class> dis(this); SubtypeCheckInfo::Result sc_result = SubtypeCheck<ObjPtr<Class>>::IsSubtypeOf(dis, klass); diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 8a7defd362..5d730ce0b0 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -72,6 +72,42 @@ void Class::VisitRoots(RootVisitor* visitor) { java_lang_Class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); } +ObjPtr<mirror::Class> Class::GetPrimitiveClass(ObjPtr<mirror::String> name) { + const char* expected_name = nullptr; + ClassLinker::ClassRoot class_root = ClassLinker::kJavaLangObject; // Invalid. + if (name != nullptr && name->GetLength() >= 2) { + // Perfect hash for the expected values: from the second letters of the primitive types, + // only 'y' has the bit 0x10 set, so use it to change 'b' to 'B'. + char hash = name->CharAt(0) ^ ((name->CharAt(1) & 0x10) << 1); + switch (hash) { + case 'b': expected_name = "boolean"; class_root = ClassLinker::kPrimitiveBoolean; break; + case 'B': expected_name = "byte"; class_root = ClassLinker::kPrimitiveByte; break; + case 'c': expected_name = "char"; class_root = ClassLinker::kPrimitiveChar; break; + case 'd': expected_name = "double"; class_root = ClassLinker::kPrimitiveDouble; break; + case 'f': expected_name = "float"; class_root = ClassLinker::kPrimitiveFloat; break; + case 'i': expected_name = "int"; class_root = ClassLinker::kPrimitiveInt; break; + case 'l': expected_name = "long"; class_root = ClassLinker::kPrimitiveLong; break; + case 's': expected_name = "short"; class_root = ClassLinker::kPrimitiveShort; break; + case 'v': expected_name = "void"; class_root = ClassLinker::kPrimitiveVoid; break; + default: break; + } + } + if (expected_name != nullptr && name->Equals(expected_name)) { + ObjPtr<mirror::Class> klass = Runtime::Current()->GetClassLinker()->GetClassRoot(class_root); + DCHECK(klass != nullptr); + return klass; + } else { + Thread* self = Thread::Current(); + if (name == nullptr) { + // Note: ThrowNullPointerException() requires a message which we deliberately want to omit. + self->ThrowNewException("Ljava/lang/NullPointerException;", /* msg */ nullptr); + } else { + self->ThrowNewException("Ljava/lang/ClassNotFoundException;", name->ToModifiedUtf8().c_str()); + } + return nullptr; + } +} + ClassExt* Class::EnsureExtDataPresent(Thread* self) { ObjPtr<ClassExt> existing(GetExtData()); if (!existing.IsNull()) { @@ -156,9 +192,19 @@ void Class::SetStatus(Handle<Class> h_this, ClassStatus new_status, Thread* self self->AssertPendingException(); } - { + if (kBitstringSubtypeCheckEnabled) { + // FIXME: This looks broken with respect to aborted transactions. ObjPtr<mirror::Class> h_this_ptr = h_this.Get(); SubtypeCheck<ObjPtr<mirror::Class>>::WriteStatus(h_this_ptr, new_status); + } else { + // The ClassStatus is always in the 4 most-significant bits of status_. + static_assert(sizeof(status_) == sizeof(uint32_t), "Size of status_ not equal to uint32"); + uint32_t new_status_value = static_cast<uint32_t>(new_status) << (32 - kClassStatusBitSize); + if (Runtime::Current()->IsActiveTransaction()) { + h_this->SetField32Volatile<true>(StatusOffset(), new_status_value); + } else { + h_this->SetField32Volatile<false>(StatusOffset(), new_status_value); + } } // Setting the object size alloc fast path needs to be after the status write so that if the diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index ced7c7c908..b9a31e54b7 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -81,7 +81,7 @@ class MANAGED Class FINAL : public Object { template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> ClassStatus GetStatus() REQUIRES_SHARED(Locks::mutator_lock_) { // Avoid including "subtype_check_bits_and_status.h" to get the field. - // The ClassStatus is always in the 4 most-significant of status_. + // The ClassStatus is always in the 4 most-significant bits of status_. return enum_cast<ClassStatus>( static_cast<uint32_t>(GetField32Volatile<kVerifyFlags>(StatusOffset())) >> (32 - 4)); } @@ -1134,6 +1134,10 @@ class MANAGED Class FINAL : public Object { void VisitNativeRoots(Visitor& visitor, PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_); + // Get one of the primitive classes. + static ObjPtr<mirror::Class> GetPrimitiveClass(ObjPtr<mirror::String> name) + REQUIRES_SHARED(Locks::mutator_lock_); + // When class is verified, set the kAccSkipAccessChecks flag on each method. void SetSkipAccessChecksFlagOnAllMethods(PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/mirror/emulated_stack_frame.cc b/runtime/mirror/emulated_stack_frame.cc index 5757992167..5f00c6e9c7 100644 --- a/runtime/mirror/emulated_stack_frame.cc +++ b/runtime/mirror/emulated_stack_frame.cc @@ -183,7 +183,7 @@ mirror::EmulatedStackFrame* EmulatedStackFrame::CreateFromShadowFrameAndArgs( } // Step 4 : Perform argument conversions (if required). - ShadowFrameGetter getter(operands, caller_frame); + ShadowFrameGetter getter(caller_frame, operands); EmulatedStackFrameAccessor setter(references, stack_frame, stack_frame->GetLength()); if (!PerformConversions<ShadowFrameGetter, EmulatedStackFrameAccessor>( self, caller_type, callee_type, &getter, &setter, num_method_params)) { diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h index 6e2a07c9e0..7fdaa32751 100644 --- a/runtime/mirror/object-inl.h +++ b/runtime/mirror/object-inl.h @@ -160,7 +160,8 @@ inline bool Object::VerifierInstanceOf(ObjPtr<Class> klass) { template<VerifyObjectFlags kVerifyFlags> inline bool Object::InstanceOf(ObjPtr<Class> klass) { DCHECK(klass != nullptr); - DCHECK(GetClass<kVerifyNone>() != nullptr); + DCHECK(GetClass<kVerifyNone>() != nullptr) + << "this=" << std::hex << reinterpret_cast<uintptr_t>(this) << std::dec; return klass->IsAssignableFrom(GetClass<kVerifyFlags>()); } @@ -935,6 +936,195 @@ inline bool Object::CasFieldWeakReleaseObjectWithoutWriteBarrier( return success; } +template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> +inline ObjPtr<Object> Object::CompareAndExchangeFieldObject(MemberOffset field_offset, + ObjPtr<Object> old_value, + ObjPtr<Object> new_value) { + if (kCheckTransaction) { + DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); + } + if (kVerifyFlags & kVerifyThis) { + VerifyObject(this); + } + if (kVerifyFlags & kVerifyWrites) { + VerifyObject(new_value); + } + if (kVerifyFlags & kVerifyReads) { + VerifyObject(old_value); + } + uint32_t old_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(old_value)); + uint32_t new_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(new_value)); + uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); + Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr); + bool success = atomic_addr->CompareAndExchangeStrongSequentiallyConsistent(&old_ref, new_ref); + ObjPtr<Object> witness_value(PtrCompression<kPoisonHeapReferences, Object>::Decompress(old_ref)); + if (kIsDebugBuild) { + // Ensure caller has done read barrier on the reference field so it's in the to-space. + ReadBarrier::AssertToSpaceInvariant(witness_value.Ptr()); + } + if (kTransactionActive && success) { + Runtime::Current()->RecordWriteFieldReference(this, field_offset, witness_value, true); + } + if (kVerifyFlags & kVerifyReads) { + VerifyObject(witness_value); + } + return witness_value; +} + +template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> +inline ObjPtr<Object> Object::ExchangeFieldObject(MemberOffset field_offset, + ObjPtr<Object> new_value) { + if (kCheckTransaction) { + DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); + } + if (kVerifyFlags & kVerifyThis) { + VerifyObject(this); + } + if (kVerifyFlags & kVerifyWrites) { + VerifyObject(new_value); + } + uint32_t new_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(new_value)); + uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); + Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr); + uint32_t old_ref = atomic_addr->ExchangeSequentiallyConsistent(new_ref); + ObjPtr<Object> old_value(PtrCompression<kPoisonHeapReferences, Object>::Decompress(old_ref)); + if (kIsDebugBuild) { + // Ensure caller has done read barrier on the reference field so it's in the to-space. + ReadBarrier::AssertToSpaceInvariant(old_value.Ptr()); + } + if (kTransactionActive) { + Runtime::Current()->RecordWriteFieldReference(this, field_offset, old_value, true); + } + if (kVerifyFlags & kVerifyReads) { + VerifyObject(old_value); + } + return old_value; +} + +template<typename T, VerifyObjectFlags kVerifyFlags> +inline void Object::GetPrimitiveFieldViaAccessor(MemberOffset field_offset, Accessor<T>* accessor) { + if (kVerifyFlags & kVerifyThis) { + VerifyObject(this); + } + uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); + T* addr = reinterpret_cast<T*>(raw_addr); + accessor->Access(addr); +} + +template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> +inline void Object::UpdateFieldBooleanViaAccessor(MemberOffset field_offset, + Accessor<uint8_t>* accessor) { + if (kCheckTransaction) { + DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); + } + if (kTransactionActive) { + static const bool kIsVolatile = true; + uint8_t old_value = GetFieldBoolean<kVerifyFlags, kIsVolatile>(field_offset); + Runtime::Current()->RecordWriteFieldBoolean(this, field_offset, old_value, kIsVolatile); + } + if (kVerifyFlags & kVerifyThis) { + VerifyObject(this); + } + uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); + uint8_t* addr = raw_addr; + accessor->Access(addr); +} + +template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> +inline void Object::UpdateFieldByteViaAccessor(MemberOffset field_offset, + Accessor<int8_t>* accessor) { + if (kCheckTransaction) { + DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); + } + if (kTransactionActive) { + static const bool kIsVolatile = true; + int8_t old_value = GetFieldByte<kVerifyFlags, kIsVolatile>(field_offset); + Runtime::Current()->RecordWriteFieldByte(this, field_offset, old_value, kIsVolatile); + } + if (kVerifyFlags & kVerifyThis) { + VerifyObject(this); + } + uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); + int8_t* addr = reinterpret_cast<int8_t*>(raw_addr); + accessor->Access(addr); +} + +template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> +inline void Object::UpdateFieldCharViaAccessor(MemberOffset field_offset, + Accessor<uint16_t>* accessor) { + if (kCheckTransaction) { + DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); + } + if (kTransactionActive) { + static const bool kIsVolatile = true; + uint16_t old_value = GetFieldChar<kVerifyFlags, kIsVolatile>(field_offset); + Runtime::Current()->RecordWriteFieldChar(this, field_offset, old_value, kIsVolatile); + } + if (kVerifyFlags & kVerifyThis) { + VerifyObject(this); + } + uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); + uint16_t* addr = reinterpret_cast<uint16_t*>(raw_addr); + accessor->Access(addr); +} + +template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> +inline void Object::UpdateFieldShortViaAccessor(MemberOffset field_offset, + Accessor<int16_t>* accessor) { + if (kCheckTransaction) { + DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); + } + if (kTransactionActive) { + static const bool kIsVolatile = true; + int16_t old_value = GetFieldShort<kVerifyFlags, kIsVolatile>(field_offset); + Runtime::Current()->RecordWriteFieldShort(this, field_offset, old_value, kIsVolatile); + } + if (kVerifyFlags & kVerifyThis) { + VerifyObject(this); + } + uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); + int16_t* addr = reinterpret_cast<int16_t*>(raw_addr); + accessor->Access(addr); +} + +template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> +inline void Object::UpdateField32ViaAccessor(MemberOffset field_offset, + Accessor<int32_t>* accessor) { + if (kCheckTransaction) { + DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); + } + if (kTransactionActive) { + static const bool kIsVolatile = true; + int32_t old_value = GetField32<kVerifyFlags, kIsVolatile>(field_offset); + Runtime::Current()->RecordWriteField32(this, field_offset, old_value, kIsVolatile); + } + if (kVerifyFlags & kVerifyThis) { + VerifyObject(this); + } + uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); + int32_t* addr = reinterpret_cast<int32_t*>(raw_addr); + accessor->Access(addr); +} + +template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> +inline void Object::UpdateField64ViaAccessor(MemberOffset field_offset, + Accessor<int64_t>* accessor) { + if (kCheckTransaction) { + DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); + } + if (kTransactionActive) { + static const bool kIsVolatile = true; + int64_t old_value = GetField64<kVerifyFlags, kIsVolatile>(field_offset); + Runtime::Current()->RecordWriteField64(this, field_offset, old_value, kIsVolatile); + } + if (kVerifyFlags & kVerifyThis) { + VerifyObject(this); + } + uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); + int64_t* addr = reinterpret_cast<int64_t*>(raw_addr); + accessor->Access(addr); +} + template<bool kIsStatic, VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption, diff --git a/runtime/mirror/object-readbarrier-inl.h b/runtime/mirror/object-readbarrier-inl.h index d81fff0a22..126cb04cf1 100644 --- a/runtime/mirror/object-readbarrier-inl.h +++ b/runtime/mirror/object-readbarrier-inl.h @@ -187,7 +187,7 @@ inline bool Object::AtomicSetMarkBit(uint32_t expected_mark_bit, uint32_t mark_b expected_lw = lw; new_lw = lw; new_lw.SetMarkBitState(mark_bit); - // Since this is only set from the mutator, we can use the non release Cas. + // Since this is only set from the mutator, we can use the non-release CAS. } while (!CasLockWordWeakRelaxed(expected_lw, new_lw)); return true; } diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h index 25b86a527d..816ac69b29 100644 --- a/runtime/mirror/object.h +++ b/runtime/mirror/object.h @@ -347,6 +347,21 @@ class MANAGED LOCKABLE Object { ObjPtr<Object> old_value, ObjPtr<Object> new_value) REQUIRES_SHARED(Locks::mutator_lock_); + + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + ObjPtr<Object> CompareAndExchangeFieldObject(MemberOffset field_offset, + ObjPtr<Object> old_value, + ObjPtr<Object> new_value) + REQUIRES_SHARED(Locks::mutator_lock_); + + template<bool kTransactionActive, + bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + ObjPtr<Object> ExchangeFieldObject(MemberOffset field_offset, ObjPtr<Object> new_value) + REQUIRES_SHARED(Locks::mutator_lock_); + template<bool kTransactionActive, bool kCheckTransaction = true, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> @@ -592,6 +607,52 @@ class MANAGED LOCKABLE Object { field_offset, reinterpret_cast64<int64_t>(new_value)); } } + + // Base class for accessors used to describe accesses performed by VarHandle methods. + template <typename T> + class Accessor { + public: + virtual ~Accessor() { + static_assert(std::is_arithmetic<T>::value, "unsupported type"); + } + virtual void Access(T* field_address) = 0; + }; + + // Getter method that exposes the raw address of a primitive value-type field to an Accessor + // instance. This are used by VarHandle accessor methods to read fields with a wider range of + // memory orderings than usually required. + template<typename T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + void GetPrimitiveFieldViaAccessor(MemberOffset field_offset, Accessor<T>* accessor) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Update methods that expose the raw address of a primitive value-type to an Accessor instance + // that will attempt to update the field. These are used by VarHandle accessor methods to + // atomically update fields with a wider range of memory orderings than usually required. + template<bool kTransactionActive, bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + void UpdateFieldBooleanViaAccessor(MemberOffset field_offset, Accessor<uint8_t>* accessor) + REQUIRES_SHARED(Locks::mutator_lock_); + template<bool kTransactionActive, bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + void UpdateFieldByteViaAccessor(MemberOffset field_offset, Accessor<int8_t>* accessor) + REQUIRES_SHARED(Locks::mutator_lock_); + template<bool kTransactionActive, bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + void UpdateFieldCharViaAccessor(MemberOffset field_offset, Accessor<uint16_t>* accessor) + REQUIRES_SHARED(Locks::mutator_lock_); + template<bool kTransactionActive, bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + void UpdateFieldShortViaAccessor(MemberOffset field_offset, Accessor<int16_t>* accessor) + REQUIRES_SHARED(Locks::mutator_lock_); + template<bool kTransactionActive, bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + void UpdateField32ViaAccessor(MemberOffset field_offset, Accessor<int32_t>* accessor) + REQUIRES_SHARED(Locks::mutator_lock_); + template<bool kTransactionActive, bool kCheckTransaction = true, + VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + void UpdateField64ViaAccessor(MemberOffset field_offset, Accessor<int64_t>* accessor) + REQUIRES_SHARED(Locks::mutator_lock_); + // TODO fix thread safety analysis broken by the use of template. This should be // REQUIRES_SHARED(Locks::mutator_lock_). template <bool kVisitNativeRoots = true, diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc index 3f4a28ce9d..85d06f03fe 100644 --- a/runtime/mirror/var_handle.cc +++ b/runtime/mirror/var_handle.cc @@ -16,14 +16,23 @@ #include "var_handle.h" +#include "array-inl.h" +#include "art_field-inl.h" #include "class-inl.h" #include "class_linker.h" #include "gc_root-inl.h" +#include "jni_internal.h" +#include "jvalue-inl.h" +#include "method_handles.h" #include "method_type.h" +#include "well_known_classes.h" namespace art { namespace mirror { +static constexpr bool kTransactionActive = true; +static constexpr bool kTransactionInactive = !kTransactionActive; + namespace { struct VarHandleAccessorToAccessModeEntry { @@ -158,32 +167,64 @@ AccessModeTemplate GetAccessModeTemplate(VarHandle::AccessMode access_mode) { } } -// Returns the number of parameters associated with an -// AccessModeTemplate and the supplied coordinate types. -int32_t GetParameterCount(AccessModeTemplate access_mode_template, - ObjPtr<Class> coordinateType0, - ObjPtr<Class> coordinateType1) { - int32_t index = 0; - if (!coordinateType0.IsNull()) { - index++; - if (!coordinateType1.IsNull()) { - index++; - } - } - +int32_t GetNumberOfVarTypeParameters(AccessModeTemplate access_mode_template) { switch (access_mode_template) { case AccessModeTemplate::kGet: - return index; + return 0; case AccessModeTemplate::kSet: case AccessModeTemplate::kGetAndUpdate: - return index + 1; + return 1; case AccessModeTemplate::kCompareAndSet: case AccessModeTemplate::kCompareAndExchange: - return index + 2; + return 2; } UNREACHABLE(); } +// Returns the number of parameters associated with an +// AccessModeTemplate and the supplied coordinate types. +int32_t GetNumberOfParameters(AccessModeTemplate access_mode_template, + ObjPtr<Class> coordinateType0, + ObjPtr<Class> coordinateType1) { + int32_t count = 0; + if (!coordinateType0.IsNull()) { + count++; + if (!coordinateType1.IsNull()) { + count++; + } + } + return count + GetNumberOfVarTypeParameters(access_mode_template); +} + +void ThrowNullPointerExceptionForCoordinate() REQUIRES_SHARED(Locks::mutator_lock_) { + ThrowNullPointerException("Attempt to access memory on a null object"); +} + +bool CheckElementIndex(Primitive::Type type, + int32_t relative_index, + int32_t start, + int32_t limit) REQUIRES_SHARED(Locks::mutator_lock_) { + int64_t index = start + relative_index; + int64_t max_index = limit - Primitive::ComponentSize(type); + if (index < start || index > max_index) { + ThrowIndexOutOfBoundsException(index, limit - start); + return false; + } + return true; +} + +bool CheckElementIndex(Primitive::Type type, int32_t index, int32_t range_limit) + REQUIRES_SHARED(Locks::mutator_lock_) { + return CheckElementIndex(type, index, 0, range_limit); +} + +// Returns true if access_mode only entails a memory read. False if +// access_mode may write to memory. +bool IsReadOnlyAccessMode(VarHandle::AccessMode access_mode) { + AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode); + return access_mode_template == AccessModeTemplate::kGet; +} + // Writes the parameter types associated with the AccessModeTemplate // into an array. The parameter types are derived from the specified // variable type and coordinate types. Returns the number of @@ -248,6 +289,1123 @@ ObjectArray<Class>* NewArrayOfClasses(Thread* self, int count) return ObjectArray<Class>::Alloc(Thread::Current(), array_of_class, count); } +// Method to insert a read barrier for accessors to reference fields. +inline void ReadBarrierForVarHandleAccess(ObjPtr<Object> obj, MemberOffset field_offset) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (kUseReadBarrier) { + // We need to ensure that the reference stored in the field is a to-space one before attempting + // the CompareAndSet/CompareAndExchange/Exchange operation otherwise it will fail incorrectly + // if obj is in the process of being moved. + uint8_t* raw_field_addr = reinterpret_cast<uint8_t*>(obj.Ptr()) + field_offset.SizeValue(); + auto field_addr = reinterpret_cast<mirror::HeapReference<mirror::Object>*>(raw_field_addr); + // Note that the read barrier load does NOT need to be volatile. + static constexpr bool kIsVolatile = false; + static constexpr bool kAlwaysUpdateField = true; + ReadBarrier::Barrier<mirror::Object, kIsVolatile, kWithReadBarrier, kAlwaysUpdateField>( + obj.Ptr(), + MemberOffset(field_offset), + field_addr); + } +} + +inline MemberOffset GetMemberOffset(jfieldID field_id) REQUIRES_SHARED(Locks::mutator_lock_) { + ArtField* const field = jni::DecodeArtField(field_id); + return field->GetOffset(); +} + +// +// Helper methods for storing results from atomic operations into +// JValue instances. +// + +inline void StoreResult(uint8_t value, JValue* result) { + result->SetZ(value); +} + +inline void StoreResult(int8_t value, JValue* result) { + result->SetB(value); +} + +inline void StoreResult(uint16_t value, JValue* result) { + result->SetC(value); +} + +inline void StoreResult(int16_t value, JValue* result) { + result->SetS(value); +} + +inline void StoreResult(int32_t value, JValue* result) { + result->SetI(value); +} + +inline void StoreResult(int64_t value, JValue* result) { + result->SetJ(value); +} + +inline void StoreResult(float value, JValue* result) { + result->SetF(value); +} + +inline void StoreResult(double value, JValue* result) { + result->SetD(value); +} + +inline void StoreResult(ObjPtr<Object> value, JValue* result) + REQUIRES_SHARED(Locks::mutator_lock_) { + result->SetL(value); +} + +// +// Helper class for byte-swapping value that has been stored in a JValue. +// + +template <typename T> +class JValueByteSwapper FINAL { + public: + static void ByteSwap(JValue* value); + static void MaybeByteSwap(bool byte_swap, JValue* value) { + if (byte_swap) { + ByteSwap(value); + } + } +}; + +template <> +void JValueByteSwapper<uint16_t>::ByteSwap(JValue* value) { + value->SetC(BSWAP(value->GetC())); +} + +template <> +void JValueByteSwapper<int16_t>::ByteSwap(JValue* value) { + value->SetS(BSWAP(value->GetS())); +} + +template <> +void JValueByteSwapper<int32_t>::ByteSwap(JValue* value) { + value->SetI(BSWAP(value->GetI())); +} + +template <> +void JValueByteSwapper<int64_t>::ByteSwap(JValue* value) { + value->SetJ(BSWAP(value->GetJ())); +} + +// +// Accessor implementations, shared across all VarHandle types. +// + +template <typename T, std::memory_order MO> +class AtomicGetAccessor : public Object::Accessor<T> { + public: + explicit AtomicGetAccessor(JValue* result) : result_(result) {} + + void Access(T* addr) OVERRIDE { + std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr); + StoreResult(atom->load(MO), result_); + } + + private: + JValue* result_; +}; + +template <typename T, std::memory_order MO> +class AtomicSetAccessor : public Object::Accessor<T> { + public: + explicit AtomicSetAccessor(T new_value) : new_value_(new_value) {} + + void Access(T* addr) OVERRIDE { + std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr); + atom->store(new_value_, MO); + } + + private: + T new_value_; +}; + +template <typename T> using GetAccessor = AtomicGetAccessor<T, std::memory_order_relaxed>; + +template <typename T> using SetAccessor = AtomicSetAccessor<T, std::memory_order_relaxed>; + +template <typename T> +using GetVolatileAccessor = AtomicGetAccessor<T, std::memory_order_seq_cst>; + +template <typename T> +using SetVolatileAccessor = AtomicSetAccessor<T, std::memory_order_seq_cst>; + +template <typename T, std::memory_order MOS, std::memory_order MOF> +class AtomicStrongCompareAndSetAccessor : public Object::Accessor<T> { + public: + AtomicStrongCompareAndSetAccessor(T expected_value, T desired_value, JValue* result) + : expected_value_(expected_value), desired_value_(desired_value), result_(result) {} + + void Access(T* addr) OVERRIDE { + std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr); + bool success = atom->compare_exchange_strong(expected_value_, desired_value_, MOS, MOF); + StoreResult(success ? JNI_TRUE : JNI_FALSE, result_); + } + + private: + T expected_value_; + T desired_value_; + JValue* result_; +}; + +template<typename T> +using CompareAndSetAccessor = + AtomicStrongCompareAndSetAccessor<T, std::memory_order_seq_cst, std::memory_order_seq_cst>; + +template <typename T, std::memory_order MOS, std::memory_order MOF> +class AtomicStrongCompareAndExchangeAccessor : public Object::Accessor<T> { + public: + AtomicStrongCompareAndExchangeAccessor(T expected_value, T desired_value, JValue* result) + : expected_value_(expected_value), desired_value_(desired_value), result_(result) {} + + void Access(T* addr) OVERRIDE { + std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr); + atom->compare_exchange_strong(expected_value_, desired_value_, MOS, MOF); + StoreResult(expected_value_, result_); + } + + private: + T expected_value_; + T desired_value_; + JValue* result_; +}; + +template <typename T> +using CompareAndExchangeAccessor = + AtomicStrongCompareAndExchangeAccessor<T, std::memory_order_seq_cst, std::memory_order_seq_cst>; + +template <typename T, std::memory_order MOS, std::memory_order MOF> +class AtomicWeakCompareAndSetAccessor : public Object::Accessor<T> { + public: + AtomicWeakCompareAndSetAccessor(T expected_value, T desired_value, JValue* result) + : expected_value_(expected_value), desired_value_(desired_value), result_(result) {} + + void Access(T* addr) OVERRIDE { + std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr); + bool success = atom->compare_exchange_weak(expected_value_, desired_value_, MOS, MOF); + StoreResult(success ? JNI_TRUE : JNI_FALSE, result_); + } + + private: + T expected_value_; + T desired_value_; + JValue* result_; +}; + +template <typename T> +using WeakCompareAndSetAccessor = + AtomicWeakCompareAndSetAccessor<T, std::memory_order_seq_cst, std::memory_order_seq_cst>; + +template <typename T, std::memory_order MO> +class AtomicGetAndSetAccessor : public Object::Accessor<T> { + public: + AtomicGetAndSetAccessor(T new_value, JValue* result) : new_value_(new_value), result_(result) {} + + void Access(T* addr) OVERRIDE { + std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr); + T old_value = atom->exchange(new_value_, MO); + StoreResult(old_value, result_); + } + + private: + T new_value_; + JValue* result_; +}; + +template <typename T> +using GetAndSetAccessor = AtomicGetAndSetAccessor<T, std::memory_order_seq_cst>; + +template <typename T, bool kIsFloat, std::memory_order MO> +class AtomicGetAndAddOperator { + public: + static T Apply(T* addr, T addend) { + std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr); + return atom->fetch_add(addend, MO); + } +}; + +template <typename T, std::memory_order MO> +class AtomicGetAndAddOperator<T, /* kIsFloat */ true, MO> { + public: + static T Apply(T* addr, T addend) { + // c++11 does not have std::atomic<T>::fetch_and_add for floating + // point types, so we effect one with a compare and swap. + std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr); + T old_value = atom->load(std::memory_order_relaxed); + T new_value; + do { + new_value = old_value + addend; + } while (!atom->compare_exchange_weak(old_value, new_value, MO, std::memory_order_relaxed)); + return old_value; + } +}; + +template <typename T, std::memory_order MO> +class AtomicGetAndAddAccessor : public Object::Accessor<T> { + public: + AtomicGetAndAddAccessor(T addend, JValue* result) : addend_(addend), result_(result) {} + + void Access(T* addr) OVERRIDE { + constexpr bool kIsFloatingPoint = std::is_floating_point<T>::value; + T old_value = AtomicGetAndAddOperator<T, kIsFloatingPoint, MO>::Apply(addr, addend_); + StoreResult(old_value, result_); + } + + private: + T addend_; + JValue* result_; +}; + +template <typename T> +using GetAndAddAccessor = AtomicGetAndAddAccessor<T, std::memory_order_seq_cst>; + +// Accessor specifically for memory views where the caller can specify +// the byte-ordering. Addition only works outside of the byte-swapped +// memory view because of the direction of carries. +template <typename T, std::memory_order MO> +class AtomicGetAndAddWithByteSwapAccessor : public Object::Accessor<T> { + public: + AtomicGetAndAddWithByteSwapAccessor(T value, JValue* result) : value_(value), result_(result) {} + + void Access(T* addr) OVERRIDE { + std::atomic<T>* const atom = reinterpret_cast<std::atomic<T>*>(addr); + T current_value = atom->load(std::memory_order_relaxed); + T sum; + do { + sum = BSWAP(current_value) + value_; + // NB current_value is a pass-by-reference argument in the call to + // atomic<T>::compare_exchange_weak(). + } while (!atom->compare_exchange_weak(current_value, + BSWAP(sum), + MO, + std::memory_order_relaxed)); + StoreResult(BSWAP(current_value), result_); + } + + private: + T value_; + JValue* result_; +}; + +template <typename T> +using GetAndAddWithByteSwapAccessor = + AtomicGetAndAddWithByteSwapAccessor<T, std::memory_order_seq_cst>; + +template <typename T, std::memory_order MO> +class AtomicGetAndBitwiseOrAccessor : public Object::Accessor<T> { + public: + AtomicGetAndBitwiseOrAccessor(T value, JValue* result) : value_(value), result_(result) {} + + void Access(T* addr) OVERRIDE { + std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr); + T old_value = atom->fetch_or(value_, MO); + StoreResult(old_value, result_); + } + + private: + T value_; + JValue* result_; +}; + +template <typename T> +using GetAndBitwiseOrAccessor = AtomicGetAndBitwiseOrAccessor<T, std::memory_order_seq_cst>; + +template <typename T, std::memory_order MO> +class AtomicGetAndBitwiseAndAccessor : public Object::Accessor<T> { + public: + AtomicGetAndBitwiseAndAccessor(T value, JValue* result) : value_(value), result_(result) {} + + void Access(T* addr) OVERRIDE { + std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr); + T old_value = atom->fetch_and(value_, MO); + StoreResult(old_value, result_); + } + + private: + T value_; + JValue* result_; +}; + +template <typename T> +using GetAndBitwiseAndAccessor = + AtomicGetAndBitwiseAndAccessor<T, std::memory_order_seq_cst>; + +template <typename T, std::memory_order MO> +class AtomicGetAndBitwiseXorAccessor : public Object::Accessor<T> { + public: + AtomicGetAndBitwiseXorAccessor(T value, JValue* result) : value_(value), result_(result) {} + + void Access(T* addr) OVERRIDE { + std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr); + T old_value = atom->fetch_xor(value_, MO); + StoreResult(old_value, result_); + } + + private: + T value_; + JValue* result_; +}; + +template <typename T> +using GetAndBitwiseXorAccessor = AtomicGetAndBitwiseXorAccessor<T, std::memory_order_seq_cst>; + +// +// Unreachable access modes. +// + +NO_RETURN void UnreachableAccessMode(const char* access_mode, const char* type_name) { + LOG(FATAL) << "Unreachable access mode :" << access_mode << " for type " << type_name; + UNREACHABLE(); +} + +#define UNREACHABLE_ACCESS_MODE(ACCESS_MODE, TYPE) \ +template<> void ACCESS_MODE ## Accessor<TYPE>::Access(TYPE*) { \ + UnreachableAccessMode(#ACCESS_MODE, #TYPE); \ +} + +// The boolean primitive type is not numeric (boolean == std::uint8_t). +UNREACHABLE_ACCESS_MODE(GetAndAdd, uint8_t) + +// The floating point types do not support bitwise operations. +UNREACHABLE_ACCESS_MODE(GetAndBitwiseOr, float) +UNREACHABLE_ACCESS_MODE(GetAndBitwiseAnd, float) +UNREACHABLE_ACCESS_MODE(GetAndBitwiseXor, float) +UNREACHABLE_ACCESS_MODE(GetAndBitwiseOr, double) +UNREACHABLE_ACCESS_MODE(GetAndBitwiseAnd, double) +UNREACHABLE_ACCESS_MODE(GetAndBitwiseXor, double) + +// A helper class for object field accesses for floats and +// doubles. The object interface deals with Field32 and Field64. The +// former is used for both integers and floats, the latter for longs +// and doubles. This class provides the necessary coercion. +template <typename T, typename U> +class TypeAdaptorAccessor : public Object::Accessor<T> { + public: + explicit TypeAdaptorAccessor(Object::Accessor<U>* inner_accessor) + : inner_accessor_(inner_accessor) {} + + void Access(T* addr) OVERRIDE { + static_assert(sizeof(T) == sizeof(U), "bad conversion"); + inner_accessor_->Access(reinterpret_cast<U*>(addr)); + } + + private: + Object::Accessor<U>* inner_accessor_; +}; + +template <typename T> +class FieldAccessViaAccessor { + public: + typedef Object::Accessor<T> Accessor; + + // Apply an Accessor to get a field in an object. + static void Get(ObjPtr<Object> obj, + MemberOffset field_offset, + Accessor* accessor) + REQUIRES_SHARED(Locks::mutator_lock_) { + obj->GetPrimitiveFieldViaAccessor(field_offset, accessor); + } + + // Apply an Accessor to update a field in an object. + static void Update(ObjPtr<Object> obj, + MemberOffset field_offset, + Accessor* accessor) + REQUIRES_SHARED(Locks::mutator_lock_); +}; + +template <> +inline void FieldAccessViaAccessor<float>::Get(ObjPtr<Object> obj, + MemberOffset field_offset, + Accessor* accessor) + REQUIRES_SHARED(Locks::mutator_lock_) { + TypeAdaptorAccessor<int32_t, float> float_to_int_accessor(accessor); + obj->GetPrimitiveFieldViaAccessor(field_offset, &float_to_int_accessor); +} + +template <> +inline void FieldAccessViaAccessor<double>::Get(ObjPtr<Object> obj, + MemberOffset field_offset, + Accessor* accessor) + REQUIRES_SHARED(Locks::mutator_lock_) { + TypeAdaptorAccessor<int64_t, double> double_to_int_accessor(accessor); + obj->GetPrimitiveFieldViaAccessor(field_offset, &double_to_int_accessor); +} + +template <> +void FieldAccessViaAccessor<uint8_t>::Update(ObjPtr<Object> obj, + MemberOffset field_offset, + Accessor* accessor) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (Runtime::Current()->IsActiveTransaction()) { + obj->UpdateFieldBooleanViaAccessor<kTransactionActive>(field_offset, accessor); + } else { + obj->UpdateFieldBooleanViaAccessor<kTransactionInactive>(field_offset, accessor); + } +} + +template <> +void FieldAccessViaAccessor<int8_t>::Update(ObjPtr<Object> obj, + MemberOffset field_offset, + Accessor* accessor) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (Runtime::Current()->IsActiveTransaction()) { + obj->UpdateFieldByteViaAccessor<kTransactionActive>(field_offset, accessor); + } else { + obj->UpdateFieldByteViaAccessor<kTransactionInactive>(field_offset, accessor); + } +} + +template <> +void FieldAccessViaAccessor<uint16_t>::Update(ObjPtr<Object> obj, + MemberOffset field_offset, + Accessor* accessor) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (Runtime::Current()->IsActiveTransaction()) { + obj->UpdateFieldCharViaAccessor<kTransactionActive>(field_offset, accessor); + } else { + obj->UpdateFieldCharViaAccessor<kTransactionInactive>(field_offset, accessor); + } +} + +template <> +void FieldAccessViaAccessor<int16_t>::Update(ObjPtr<Object> obj, + MemberOffset field_offset, + Accessor* accessor) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (Runtime::Current()->IsActiveTransaction()) { + obj->UpdateFieldShortViaAccessor<kTransactionActive>(field_offset, accessor); + } else { + obj->UpdateFieldShortViaAccessor<kTransactionInactive>(field_offset, accessor); + } +} + +template <> +void FieldAccessViaAccessor<int32_t>::Update(ObjPtr<Object> obj, + MemberOffset field_offset, + Accessor* accessor) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (Runtime::Current()->IsActiveTransaction()) { + obj->UpdateField32ViaAccessor<kTransactionActive>(field_offset, accessor); + } else { + obj->UpdateField32ViaAccessor<kTransactionInactive>(field_offset, accessor); + } +} + +template <> +void FieldAccessViaAccessor<int64_t>::Update(ObjPtr<Object> obj, + MemberOffset field_offset, + Accessor* accessor) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (Runtime::Current()->IsActiveTransaction()) { + obj->UpdateField64ViaAccessor<kTransactionActive>(field_offset, accessor); + } else { + obj->UpdateField64ViaAccessor<kTransactionInactive>(field_offset, accessor); + } +} + +template <> +void FieldAccessViaAccessor<float>::Update(ObjPtr<Object> obj, + MemberOffset field_offset, + Accessor* accessor) + REQUIRES_SHARED(Locks::mutator_lock_) { + TypeAdaptorAccessor<int32_t, float> float_to_int_accessor(accessor); + if (Runtime::Current()->IsActiveTransaction()) { + obj->UpdateField32ViaAccessor<kTransactionActive>(field_offset, &float_to_int_accessor); + } else { + obj->UpdateField32ViaAccessor<kTransactionInactive>(field_offset, &float_to_int_accessor); + } +} + +template <> +void FieldAccessViaAccessor<double>::Update(ObjPtr<Object> obj, + MemberOffset field_offset, + Accessor* accessor) + REQUIRES_SHARED(Locks::mutator_lock_) { + TypeAdaptorAccessor<int64_t, double> double_to_int_accessor(accessor); + if (Runtime::Current()->IsActiveTransaction()) { + obj->UpdateField64ViaAccessor<kTransactionActive>(field_offset, &double_to_int_accessor); + } else { + obj->UpdateField64ViaAccessor<kTransactionInactive>(field_offset, &double_to_int_accessor); + } +} + +// Helper class that gets values from a shadow frame with appropriate type coercion. +template <typename T> +class ValueGetter { + public: + static T Get(ShadowFrameGetter* getter) REQUIRES_SHARED(Locks::mutator_lock_) { + static_assert(sizeof(T) <= sizeof(uint32_t), "Bad size"); + uint32_t raw_value = getter->Get(); + return static_cast<T>(raw_value); + } +}; + +template <> +int64_t ValueGetter<int64_t>::Get(ShadowFrameGetter* getter) { + return getter->GetLong(); +} + +template <> +float ValueGetter<float>::Get(ShadowFrameGetter* getter) { + uint32_t raw_value = getter->Get(); + return *reinterpret_cast<float*>(&raw_value); +} + +template <> +double ValueGetter<double>::Get(ShadowFrameGetter* getter) { + int64_t raw_value = getter->GetLong(); + return *reinterpret_cast<double*>(&raw_value); +} + +template <> +ObjPtr<Object> ValueGetter<ObjPtr<Object>>::Get(ShadowFrameGetter* getter) { + return getter->GetReference(); +} + +// Class for accessing fields of Object instances +template <typename T> +class FieldAccessor { + public: + static bool Dispatch(VarHandle::AccessMode access_mode, + ObjPtr<Object> obj, + MemberOffset field_offset, + ShadowFrameGetter* getter, + JValue* result) + REQUIRES_SHARED(Locks::mutator_lock_); +}; + +// Dispatch implementation for primitive fields. +template <typename T> +bool FieldAccessor<T>::Dispatch(VarHandle::AccessMode access_mode, + ObjPtr<Object> obj, + MemberOffset field_offset, + ShadowFrameGetter* getter, + JValue* result) { + switch (access_mode) { + case VarHandle::AccessMode::kGet: { + GetAccessor<T> accessor(result); + FieldAccessViaAccessor<T>::Get(obj, field_offset, &accessor); + break; + } + case VarHandle::AccessMode::kSet: { + T new_value = ValueGetter<T>::Get(getter); + SetAccessor<T> accessor(new_value); + FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); + break; + } + case VarHandle::AccessMode::kGetAcquire: + case VarHandle::AccessMode::kGetOpaque: + case VarHandle::AccessMode::kGetVolatile: { + GetVolatileAccessor<T> accessor(result); + FieldAccessViaAccessor<T>::Get(obj, field_offset, &accessor); + break; + } + case VarHandle::AccessMode::kSetOpaque: + case VarHandle::AccessMode::kSetRelease: + case VarHandle::AccessMode::kSetVolatile: { + T new_value = ValueGetter<T>::Get(getter); + SetVolatileAccessor<T> accessor(new_value); + FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); + break; + } + case VarHandle::AccessMode::kCompareAndSet: { + T expected_value = ValueGetter<T>::Get(getter); + T desired_value = ValueGetter<T>::Get(getter); + CompareAndSetAccessor<T> accessor(expected_value, desired_value, result); + FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); + break; + } + case VarHandle::AccessMode::kCompareAndExchange: + case VarHandle::AccessMode::kCompareAndExchangeAcquire: + case VarHandle::AccessMode::kCompareAndExchangeRelease: { + T expected_value = ValueGetter<T>::Get(getter); + T desired_value = ValueGetter<T>::Get(getter); + CompareAndExchangeAccessor<T> accessor(expected_value, desired_value, result); + FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); + break; + } + case VarHandle::AccessMode::kWeakCompareAndSet: + case VarHandle::AccessMode::kWeakCompareAndSetAcquire: + case VarHandle::AccessMode::kWeakCompareAndSetPlain: + case VarHandle::AccessMode::kWeakCompareAndSetRelease: { + T expected_value = ValueGetter<T>::Get(getter); + T desired_value = ValueGetter<T>::Get(getter); + WeakCompareAndSetAccessor<T> accessor(expected_value, desired_value, result); + FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); + break; + } + case VarHandle::AccessMode::kGetAndSet: + case VarHandle::AccessMode::kGetAndSetAcquire: + case VarHandle::AccessMode::kGetAndSetRelease: { + T new_value = ValueGetter<T>::Get(getter); + GetAndSetAccessor<T> accessor(new_value, result); + FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); + break; + } + case VarHandle::AccessMode::kGetAndAdd: + case VarHandle::AccessMode::kGetAndAddAcquire: + case VarHandle::AccessMode::kGetAndAddRelease: { + T value = ValueGetter<T>::Get(getter); + GetAndAddAccessor<T> accessor(value, result); + FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); + break; + } + case VarHandle::AccessMode::kGetAndBitwiseOr: + case VarHandle::AccessMode::kGetAndBitwiseOrAcquire: + case VarHandle::AccessMode::kGetAndBitwiseOrRelease: { + T value = ValueGetter<T>::Get(getter); + GetAndBitwiseOrAccessor<T> accessor(value, result); + FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); + break; + } + case VarHandle::AccessMode::kGetAndBitwiseAnd: + case VarHandle::AccessMode::kGetAndBitwiseAndAcquire: + case VarHandle::AccessMode::kGetAndBitwiseAndRelease: { + T value = ValueGetter<T>::Get(getter); + GetAndBitwiseAndAccessor<T> accessor(value, result); + FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); + break; + } + case VarHandle::AccessMode::kGetAndBitwiseXor: + case VarHandle::AccessMode::kGetAndBitwiseXorAcquire: + case VarHandle::AccessMode::kGetAndBitwiseXorRelease: { + T value = ValueGetter<T>::Get(getter); + GetAndBitwiseXorAccessor<T> accessor(value, result); + FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor); + break; + } + } + return true; +} + +// Dispatch implementation for reference fields. +template <> +bool FieldAccessor<ObjPtr<Object>>::Dispatch(VarHandle::AccessMode access_mode, + ObjPtr<Object> obj, + MemberOffset field_offset, + ShadowFrameGetter* getter, + JValue* result) + REQUIRES_SHARED(Locks::mutator_lock_) { + // To keep things simple, use the minimum strongest existing + // field accessor for Object fields. This may be the most + // straightforward strategy in general for the interpreter. + switch (access_mode) { + case VarHandle::AccessMode::kGet: { + StoreResult(obj->GetFieldObject<Object>(field_offset), result); + break; + } + case VarHandle::AccessMode::kSet: { + ObjPtr<Object> new_value = ValueGetter<ObjPtr<Object>>::Get(getter); + if (Runtime::Current()->IsActiveTransaction()) { + obj->SetFieldObject<kTransactionActive>(field_offset, new_value); + } else { + obj->SetFieldObject<kTransactionInactive>(field_offset, new_value); + } + break; + } + case VarHandle::AccessMode::kGetAcquire: + case VarHandle::AccessMode::kGetOpaque: + case VarHandle::AccessMode::kGetVolatile: { + StoreResult(obj->GetFieldObjectVolatile<Object>(field_offset), result); + break; + } + case VarHandle::AccessMode::kSetOpaque: + case VarHandle::AccessMode::kSetRelease: + case VarHandle::AccessMode::kSetVolatile: { + ObjPtr<Object> new_value = ValueGetter<ObjPtr<Object>>::Get(getter); + if (Runtime::Current()->IsActiveTransaction()) { + obj->SetFieldObjectVolatile<kTransactionActive>(field_offset, new_value); + } else { + obj->SetFieldObjectVolatile<kTransactionInactive>(field_offset, new_value); + } + break; + } + case VarHandle::AccessMode::kCompareAndSet: { + ReadBarrierForVarHandleAccess(obj, field_offset); + ObjPtr<Object> expected_value = ValueGetter<ObjPtr<Object>>::Get(getter); + ObjPtr<Object> desired_value = ValueGetter<ObjPtr<Object>>::Get(getter); + bool cas_result; + if (Runtime::Current()->IsActiveTransaction()) { + cas_result = obj->CasFieldStrongSequentiallyConsistentObject<kTransactionActive>( + field_offset, + expected_value, + desired_value); + } else { + cas_result = obj->CasFieldStrongSequentiallyConsistentObject<kTransactionInactive>( + field_offset, + expected_value, + desired_value); + } + StoreResult(cas_result, result); + break; + } + case VarHandle::AccessMode::kWeakCompareAndSet: + case VarHandle::AccessMode::kWeakCompareAndSetAcquire: + case VarHandle::AccessMode::kWeakCompareAndSetPlain: + case VarHandle::AccessMode::kWeakCompareAndSetRelease: { + ReadBarrierForVarHandleAccess(obj, field_offset); + ObjPtr<Object> expected_value = ValueGetter<ObjPtr<Object>>::Get(getter); + ObjPtr<Object> desired_value = ValueGetter<ObjPtr<Object>>::Get(getter); + bool cas_result; + if (Runtime::Current()->IsActiveTransaction()) { + cas_result = obj->CasFieldWeakSequentiallyConsistentObject<kTransactionActive>( + field_offset, + expected_value, + desired_value); + } else { + cas_result = obj->CasFieldWeakSequentiallyConsistentObject<kTransactionInactive>( + field_offset, + expected_value, + desired_value); + } + StoreResult(cas_result, result); + break; + } + case VarHandle::AccessMode::kCompareAndExchange: + case VarHandle::AccessMode::kCompareAndExchangeAcquire: + case VarHandle::AccessMode::kCompareAndExchangeRelease: { + ReadBarrierForVarHandleAccess(obj, field_offset); + ObjPtr<Object> expected_value = ValueGetter<ObjPtr<Object>>::Get(getter); + ObjPtr<Object> desired_value = ValueGetter<ObjPtr<Object>>::Get(getter); + ObjPtr<Object> witness_value; + if (Runtime::Current()->IsActiveTransaction()) { + witness_value = obj->CompareAndExchangeFieldObject<kTransactionActive>( + field_offset, + expected_value, + desired_value); + } else { + witness_value = obj->CompareAndExchangeFieldObject<kTransactionInactive>( + field_offset, + expected_value, + desired_value); + } + StoreResult(witness_value, result); + break; + } + case VarHandle::AccessMode::kGetAndSet: + case VarHandle::AccessMode::kGetAndSetAcquire: + case VarHandle::AccessMode::kGetAndSetRelease: { + ReadBarrierForVarHandleAccess(obj, field_offset); + ObjPtr<Object> new_value = ValueGetter<ObjPtr<Object>>::Get(getter); + ObjPtr<Object> old_value; + if (Runtime::Current()->IsActiveTransaction()) { + old_value = obj->ExchangeFieldObject<kTransactionActive>(field_offset, new_value); + } else { + old_value = obj->ExchangeFieldObject<kTransactionInactive>(field_offset, new_value); + } + StoreResult(old_value, result); + break; + } + case VarHandle::AccessMode::kGetAndAdd: + case VarHandle::AccessMode::kGetAndAddAcquire: + case VarHandle::AccessMode::kGetAndAddRelease: + case VarHandle::AccessMode::kGetAndBitwiseOr: + case VarHandle::AccessMode::kGetAndBitwiseOrAcquire: + case VarHandle::AccessMode::kGetAndBitwiseOrRelease: + case VarHandle::AccessMode::kGetAndBitwiseAnd: + case VarHandle::AccessMode::kGetAndBitwiseAndAcquire: + case VarHandle::AccessMode::kGetAndBitwiseAndRelease: + case VarHandle::AccessMode::kGetAndBitwiseXor: + case VarHandle::AccessMode::kGetAndBitwiseXorAcquire: + case VarHandle::AccessMode::kGetAndBitwiseXorRelease: { + size_t index = static_cast<size_t>(access_mode); + const char* access_mode_name = kAccessorToAccessMode[index].method_name; + UnreachableAccessMode(access_mode_name, "Object"); + } + } + return true; +} + +// Class for accessing primitive array elements. +template <typename T> +class PrimitiveArrayElementAccessor { + public: + static T* GetElementAddress(ObjPtr<Array> target_array, int target_element) + REQUIRES_SHARED(Locks::mutator_lock_) { + auto primitive_array = ObjPtr<PrimitiveArray<T>>::DownCast(target_array); + DCHECK(primitive_array->CheckIsValidIndex(target_element)); + return &primitive_array->GetData()[target_element]; + } + + static bool Dispatch(VarHandle::AccessMode access_mode, + ObjPtr<Array> target_array, + int target_element, + ShadowFrameGetter* getter, + JValue* result) + REQUIRES_SHARED(Locks::mutator_lock_) { + T* element_address = GetElementAddress(target_array, target_element); + switch (access_mode) { + case VarHandle::AccessMode::kGet: { + GetAccessor<T> accessor(result); + accessor.Access(element_address); + break; + } + case VarHandle::AccessMode::kSet: { + T new_value = ValueGetter<T>::Get(getter); + SetAccessor<T> accessor(new_value); + accessor.Access(element_address); + break; + } + case VarHandle::AccessMode::kGetAcquire: + case VarHandle::AccessMode::kGetOpaque: + case VarHandle::AccessMode::kGetVolatile: { + GetVolatileAccessor<T> accessor(result); + accessor.Access(element_address); + break; + } + case VarHandle::AccessMode::kSetOpaque: + case VarHandle::AccessMode::kSetRelease: + case VarHandle::AccessMode::kSetVolatile: { + T new_value = ValueGetter<T>::Get(getter); + SetVolatileAccessor<T> accessor(new_value); + accessor.Access(element_address); + break; + } + case VarHandle::AccessMode::kCompareAndSet: { + T expected_value = ValueGetter<T>::Get(getter); + T desired_value = ValueGetter<T>::Get(getter); + CompareAndSetAccessor<T> accessor(expected_value, desired_value, result); + accessor.Access(element_address); + break; + } + case VarHandle::AccessMode::kCompareAndExchange: + case VarHandle::AccessMode::kCompareAndExchangeAcquire: + case VarHandle::AccessMode::kCompareAndExchangeRelease: { + T expected_value = ValueGetter<T>::Get(getter); + T desired_value = ValueGetter<T>::Get(getter); + CompareAndExchangeAccessor<T> accessor(expected_value, desired_value, result); + accessor.Access(element_address); + break; + } + case VarHandle::AccessMode::kWeakCompareAndSet: + case VarHandle::AccessMode::kWeakCompareAndSetAcquire: + case VarHandle::AccessMode::kWeakCompareAndSetPlain: + case VarHandle::AccessMode::kWeakCompareAndSetRelease: { + T expected_value = ValueGetter<T>::Get(getter); + T desired_value = ValueGetter<T>::Get(getter); + WeakCompareAndSetAccessor<T> accessor(expected_value, desired_value, result); + accessor.Access(element_address); + break; + } + case VarHandle::AccessMode::kGetAndSet: + case VarHandle::AccessMode::kGetAndSetAcquire: + case VarHandle::AccessMode::kGetAndSetRelease: { + T new_value = ValueGetter<T>::Get(getter); + GetAndSetAccessor<T> accessor(new_value, result); + accessor.Access(element_address); + break; + } + case VarHandle::AccessMode::kGetAndAdd: + case VarHandle::AccessMode::kGetAndAddAcquire: + case VarHandle::AccessMode::kGetAndAddRelease: { + T value = ValueGetter<T>::Get(getter); + GetAndAddAccessor<T> accessor(value, result); + accessor.Access(element_address); + break; + } + case VarHandle::AccessMode::kGetAndBitwiseOr: + case VarHandle::AccessMode::kGetAndBitwiseOrAcquire: + case VarHandle::AccessMode::kGetAndBitwiseOrRelease: { + T value = ValueGetter<T>::Get(getter); + GetAndBitwiseOrAccessor<T> accessor(value, result); + accessor.Access(element_address); + break; + } + case VarHandle::AccessMode::kGetAndBitwiseAnd: + case VarHandle::AccessMode::kGetAndBitwiseAndAcquire: + case VarHandle::AccessMode::kGetAndBitwiseAndRelease: { + T value = ValueGetter<T>::Get(getter); + GetAndBitwiseAndAccessor<T> accessor(value, result); + accessor.Access(element_address); + break; + } + case VarHandle::AccessMode::kGetAndBitwiseXor: + case VarHandle::AccessMode::kGetAndBitwiseXorAcquire: + case VarHandle::AccessMode::kGetAndBitwiseXorRelease: { + T value = ValueGetter<T>::Get(getter); + GetAndBitwiseXorAccessor<T> accessor(value, result); + accessor.Access(element_address); + break; + } + } + return true; + } +}; + +// Class for accessing primitive array elements. +template <typename T> +class ByteArrayViewAccessor { + public: + static inline bool IsAccessAligned(int8_t* data, int data_index) { + static_assert(IsPowerOfTwo(sizeof(T)), "unexpected size"); + static_assert(std::is_arithmetic<T>::value, "unexpected type"); + uintptr_t alignment_mask = sizeof(T) - 1; + uintptr_t address = reinterpret_cast<uintptr_t>(data + data_index); + return (address & alignment_mask) == 0; + } + + static inline void MaybeByteSwap(bool byte_swap, T* const value) { + if (byte_swap) { + *value = BSWAP(*value); + } + } + + static bool Dispatch(const VarHandle::AccessMode access_mode, + int8_t* const data, + const int data_index, + const bool byte_swap, + ShadowFrameGetter* const getter, + JValue* const result) + REQUIRES_SHARED(Locks::mutator_lock_) { + const bool is_aligned = IsAccessAligned(data, data_index); + if (!is_aligned) { + switch (access_mode) { + case VarHandle::AccessMode::kGet: { + T value; + memcpy(&value, data + data_index, sizeof(T)); + MaybeByteSwap(byte_swap, &value); + StoreResult(value, result); + return true; + } + case VarHandle::AccessMode::kSet: { + T new_value = ValueGetter<T>::Get(getter); + MaybeByteSwap(byte_swap, &new_value); + memcpy(data + data_index, &new_value, sizeof(T)); + return true; + } + default: + // No other access modes support unaligned access. + ThrowIllegalStateException("Unaligned access not supported"); + return false; + } + } + + T* const element_address = reinterpret_cast<T*>(data + data_index); + CHECK(IsAccessAligned(reinterpret_cast<int8_t*>(element_address), 0)); + switch (access_mode) { + case VarHandle::AccessMode::kGet: { + GetAccessor<T> accessor(result); + accessor.Access(element_address); + JValueByteSwapper<T>::MaybeByteSwap(byte_swap, result); + break; + } + case VarHandle::AccessMode::kSet: { + T new_value = ValueGetter<T>::Get(getter); + MaybeByteSwap(byte_swap, &new_value); + SetAccessor<T> accessor(new_value); + accessor.Access(element_address); + break; + } + case VarHandle::AccessMode::kGetAcquire: + case VarHandle::AccessMode::kGetOpaque: + case VarHandle::AccessMode::kGetVolatile: { + GetVolatileAccessor<T> accessor(result); + accessor.Access(element_address); + JValueByteSwapper<T>::MaybeByteSwap(byte_swap, result); + break; + } + case VarHandle::AccessMode::kSetOpaque: + case VarHandle::AccessMode::kSetRelease: + case VarHandle::AccessMode::kSetVolatile: { + T new_value = ValueGetter<T>::Get(getter); + MaybeByteSwap(byte_swap, &new_value); + SetVolatileAccessor<T> accessor(new_value); + accessor.Access(element_address); + break; + } + case VarHandle::AccessMode::kCompareAndSet: { + T expected_value = ValueGetter<T>::Get(getter); + T desired_value = ValueGetter<T>::Get(getter); + MaybeByteSwap(byte_swap, &expected_value); + MaybeByteSwap(byte_swap, &desired_value); + CompareAndSetAccessor<T> accessor(expected_value, desired_value, result); + accessor.Access(element_address); + break; + } + case VarHandle::AccessMode::kCompareAndExchange: + case VarHandle::AccessMode::kCompareAndExchangeAcquire: + case VarHandle::AccessMode::kCompareAndExchangeRelease: { + T expected_value = ValueGetter<T>::Get(getter); + T desired_value = ValueGetter<T>::Get(getter); + MaybeByteSwap(byte_swap, &expected_value); + MaybeByteSwap(byte_swap, &desired_value); + CompareAndExchangeAccessor<T> accessor(expected_value, desired_value, result); + accessor.Access(element_address); + JValueByteSwapper<T>::MaybeByteSwap(byte_swap, result); + break; + } + case VarHandle::AccessMode::kWeakCompareAndSet: + case VarHandle::AccessMode::kWeakCompareAndSetAcquire: + case VarHandle::AccessMode::kWeakCompareAndSetPlain: + case VarHandle::AccessMode::kWeakCompareAndSetRelease: { + T expected_value = ValueGetter<T>::Get(getter); + T desired_value = ValueGetter<T>::Get(getter); + MaybeByteSwap(byte_swap, &expected_value); + MaybeByteSwap(byte_swap, &desired_value); + WeakCompareAndSetAccessor<T> accessor(expected_value, desired_value, result); + accessor.Access(element_address); + break; + } + case VarHandle::AccessMode::kGetAndSet: + case VarHandle::AccessMode::kGetAndSetAcquire: + case VarHandle::AccessMode::kGetAndSetRelease: { + T new_value = ValueGetter<T>::Get(getter); + MaybeByteSwap(byte_swap, &new_value); + GetAndSetAccessor<T> accessor(new_value, result); + accessor.Access(element_address); + JValueByteSwapper<T>::MaybeByteSwap(byte_swap, result); + break; + } + case VarHandle::AccessMode::kGetAndAdd: + case VarHandle::AccessMode::kGetAndAddAcquire: + case VarHandle::AccessMode::kGetAndAddRelease: { + T value = ValueGetter<T>::Get(getter); + if (byte_swap) { + GetAndAddWithByteSwapAccessor<T> accessor(value, result); + accessor.Access(element_address); + } else { + GetAndAddAccessor<T> accessor(value, result); + accessor.Access(element_address); + } + break; + } + case VarHandle::AccessMode::kGetAndBitwiseOr: + case VarHandle::AccessMode::kGetAndBitwiseOrAcquire: + case VarHandle::AccessMode::kGetAndBitwiseOrRelease: { + T value = ValueGetter<T>::Get(getter); + MaybeByteSwap(byte_swap, &value); + GetAndBitwiseOrAccessor<T> accessor(value, result); + accessor.Access(element_address); + JValueByteSwapper<T>::MaybeByteSwap(byte_swap, result); + break; + } + case VarHandle::AccessMode::kGetAndBitwiseAnd: + case VarHandle::AccessMode::kGetAndBitwiseAndAcquire: + case VarHandle::AccessMode::kGetAndBitwiseAndRelease: { + T value = ValueGetter<T>::Get(getter); + MaybeByteSwap(byte_swap, &value); + GetAndBitwiseAndAccessor<T> accessor(value, result); + accessor.Access(element_address); + JValueByteSwapper<T>::MaybeByteSwap(byte_swap, result); + break; + } + case VarHandle::AccessMode::kGetAndBitwiseXor: + case VarHandle::AccessMode::kGetAndBitwiseXorAcquire: + case VarHandle::AccessMode::kGetAndBitwiseXorRelease: { + T value = ValueGetter<T>::Get(getter); + MaybeByteSwap(byte_swap, &value); + GetAndBitwiseXorAccessor<T> accessor(value, result); + accessor.Access(element_address); + JValueByteSwapper<T>::MaybeByteSwap(byte_swap, result); + break; + } + } + return true; + } +}; + } // namespace Class* VarHandle::GetVarType() { @@ -267,35 +1425,38 @@ int32_t VarHandle::GetAccessModesBitMask() { } bool VarHandle::IsMethodTypeCompatible(AccessMode access_mode, MethodType* method_type) { - ScopedAssertNoThreadSuspension ants(__FUNCTION__); - + StackHandleScope<3> hs(Thread::Current()); + Handle<Class> mt_rtype(hs.NewHandle(method_type->GetRType())); + Handle<VarHandle> vh(hs.NewHandle(this)); + Handle<Class> var_type(hs.NewHandle(vh->GetVarType())); AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode); - // Check return types first. - ObjPtr<Class> var_type = GetVarType(); - ObjPtr<Class> vh_rtype = GetReturnType(access_mode_template, var_type); - ObjPtr<Class> void_type = Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V'); - ObjPtr<Class> mt_rtype = method_type->GetRType(); - - // If the mt_rtype is void, the result of the operation will be discarded (okay). - if (mt_rtype != void_type && mt_rtype != vh_rtype) { - return false; + + // Check return type first. + if (mt_rtype->GetPrimitiveType() == Primitive::Type::kPrimVoid) { + // The result of the operation will be discarded. The return type + // of the VarHandle is immaterial. + } else { + ObjPtr<Class> vh_rtype(GetReturnType(access_mode_template, var_type.Get())); + if (!IsReturnTypeConvertible(vh_rtype, mt_rtype.Get())) { + return false; + } } // Check the number of parameters matches. ObjPtr<Class> vh_ptypes[VarHandle::kMaxAccessorParameters]; const int32_t vh_ptypes_count = BuildParameterArray(vh_ptypes, access_mode_template, - var_type, + var_type.Get(), GetCoordinateType0(), GetCoordinateType1()); if (vh_ptypes_count != method_type->GetPTypes()->GetLength()) { return false; } - // Check the parameter types match. + // Check the parameter types are compatible. ObjPtr<ObjectArray<Class>> mt_ptypes = method_type->GetPTypes(); for (int32_t i = 0; i < vh_ptypes_count; ++i) { - if (mt_ptypes->Get(i) != vh_ptypes[i].Ptr()) { + if (!IsParameterTypeConvertible(mt_ptypes->Get(i), vh_ptypes[i])) { return false; } } @@ -311,8 +1472,9 @@ MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self, StackHandleScope<3> hs(self); Handle<VarHandle> vh = hs.NewHandle(var_handle); Handle<Class> rtype = hs.NewHandle(GetReturnType(access_mode_template, vh->GetVarType())); - const int32_t ptypes_count = - GetParameterCount(access_mode_template, vh->GetCoordinateType0(), vh->GetCoordinateType1()); + const int32_t ptypes_count = GetNumberOfParameters(access_mode_template, + vh->GetCoordinateType0(), + vh->GetCoordinateType1()); Handle<ObjectArray<Class>> ptypes = hs.NewHandle(NewArrayOfClasses(self, ptypes_count)); if (ptypes == nullptr) { return nullptr; @@ -334,6 +1496,29 @@ MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self, AccessMode acces return GetMethodTypeForAccessMode(self, this, access_mode); } +bool VarHandle::Access(AccessMode access_mode, + ShadowFrame* shadow_frame, + InstructionOperands* operands, + JValue* result) { + Class* klass = GetClass(); + if (klass == FieldVarHandle::StaticClass()) { + auto vh = reinterpret_cast<FieldVarHandle*>(this); + return vh->Access(access_mode, shadow_frame, operands, result); + } else if (klass == ArrayElementVarHandle::StaticClass()) { + auto vh = reinterpret_cast<ArrayElementVarHandle*>(this); + return vh->Access(access_mode, shadow_frame, operands, result); + } else if (klass == ByteArrayViewVarHandle::StaticClass()) { + auto vh = reinterpret_cast<ByteArrayViewVarHandle*>(this); + return vh->Access(access_mode, shadow_frame, operands, result); + } else if (klass == ByteBufferViewVarHandle::StaticClass()) { + auto vh = reinterpret_cast<ByteBufferViewVarHandle*>(this); + return vh->Access(access_mode, shadow_frame, operands, result); + } else { + LOG(FATAL) << "Unknown varhandle kind"; + UNREACHABLE(); + } +} + const char* VarHandle::GetReturnTypeDescriptor(const char* accessor_name) { AccessMode access_mode; if (!GetAccessModeByMethodName(accessor_name, &access_mode)) { @@ -369,6 +1554,10 @@ bool VarHandle::GetAccessModeByMethodName(const char* method_name, AccessMode* a return true; } +Class* VarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { + return static_class_.Read(); +} + void VarHandle::SetClass(Class* klass) { CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; CHECK(klass != nullptr); @@ -391,6 +1580,57 @@ ArtField* FieldVarHandle::GetField() { return reinterpret_cast<ArtField*>(opaque_field); } +bool FieldVarHandle::Access(AccessMode access_mode, + ShadowFrame* shadow_frame, + InstructionOperands* operands, + JValue* result) { + ShadowFrameGetter getter(*shadow_frame, operands); + ArtField* field = GetField(); + ObjPtr<Object> obj; + if (field->IsStatic()) { + DCHECK_LE(operands->GetNumberOfOperands(), + 2u * (Primitive::Is64BitType(GetVarType()->GetPrimitiveType()) ? 2u : 1u)); + obj = field->GetDeclaringClass(); + } else { + DCHECK_GE(operands->GetNumberOfOperands(), 1u); + DCHECK_LE(operands->GetNumberOfOperands(), + 1u + 2u * (Primitive::Is64BitType(GetVarType()->GetPrimitiveType()) ? 2u : 1u)); + obj = getter.GetReference(); + if (obj.IsNull()) { + ThrowNullPointerExceptionForCoordinate(); + return false; + } + } + DCHECK(!obj.IsNull()); + + const MemberOffset offset = field->GetOffset(); + const Primitive::Type primitive_type = GetVarType()->GetPrimitiveType(); + switch (primitive_type) { + case Primitive::Type::kPrimNot: + return FieldAccessor<ObjPtr<Object>>::Dispatch(access_mode, obj, offset, &getter, result); + case Primitive::kPrimBoolean: + return FieldAccessor<uint8_t>::Dispatch(access_mode, obj, offset, &getter, result); + case Primitive::kPrimByte: + return FieldAccessor<int8_t>::Dispatch(access_mode, obj, offset, &getter, result); + case Primitive::kPrimChar: + return FieldAccessor<uint16_t>::Dispatch(access_mode, obj, offset, &getter, result); + case Primitive::kPrimShort: + return FieldAccessor<int16_t>::Dispatch(access_mode, obj, offset, &getter, result); + case Primitive::kPrimInt: + return FieldAccessor<int32_t>::Dispatch(access_mode, obj, offset, &getter, result); + case Primitive::kPrimFloat: + return FieldAccessor<float>::Dispatch(access_mode, obj, offset, &getter, result); + case Primitive::kPrimLong: + return FieldAccessor<int64_t>::Dispatch(access_mode, obj, offset, &getter, result); + case Primitive::kPrimDouble: + return FieldAccessor<double>::Dispatch(access_mode, obj, offset, &getter, result); + case Primitive::kPrimVoid: + break; + } + LOG(FATAL) << "Unreachable: Unexpected primitive " << primitive_type; + UNREACHABLE(); +} + Class* FieldVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { return static_class_.Read(); } @@ -412,6 +1652,94 @@ void FieldVarHandle::VisitRoots(RootVisitor* visitor) { GcRoot<Class> FieldVarHandle::static_class_; +bool ArrayElementVarHandle::Access(AccessMode access_mode, + ShadowFrame* shadow_frame, + InstructionOperands* operands, + JValue* result) { + ShadowFrameGetter getter(*shadow_frame, operands); + + // The target array is the first co-ordinate type preceeding var type arguments. + ObjPtr<Object> raw_array(getter.GetReference()); + if (raw_array == nullptr) { + ThrowNullPointerExceptionForCoordinate(); + return false; + } + + ObjPtr<Array> target_array(raw_array->AsArray()); + + // The target array element is the second co-ordinate type preceeding var type arguments. + const int target_element = getter.Get(); + if (!target_array->CheckIsValidIndex(target_element)) { + DCHECK(Thread::Current()->IsExceptionPending()); + return false; + } + + const Primitive::Type primitive_type = GetVarType()->GetPrimitiveType(); + switch (primitive_type) { + case Primitive::Type::kPrimNot: { + MemberOffset target_element_offset = + target_array->AsObjectArray<Object>()->OffsetOfElement(target_element); + return FieldAccessor<ObjPtr<Object>>::Dispatch(access_mode, + target_array, + target_element_offset, + &getter, + result); + } + case Primitive::Type::kPrimBoolean: + return PrimitiveArrayElementAccessor<uint8_t>::Dispatch(access_mode, + target_array, + target_element, + &getter, + result); + case Primitive::Type::kPrimByte: + return PrimitiveArrayElementAccessor<int8_t>::Dispatch(access_mode, + target_array, + target_element, + &getter, + result); + case Primitive::Type::kPrimChar: + return PrimitiveArrayElementAccessor<uint16_t>::Dispatch(access_mode, + target_array, + target_element, + &getter, + result); + case Primitive::Type::kPrimShort: + return PrimitiveArrayElementAccessor<int16_t>::Dispatch(access_mode, + target_array, + target_element, + &getter, + result); + case Primitive::Type::kPrimInt: + return PrimitiveArrayElementAccessor<int32_t>::Dispatch(access_mode, + target_array, + target_element, + &getter, + result); + case Primitive::Type::kPrimLong: + return PrimitiveArrayElementAccessor<int64_t>::Dispatch(access_mode, + target_array, + target_element, + &getter, + result); + case Primitive::Type::kPrimFloat: + return PrimitiveArrayElementAccessor<float>::Dispatch(access_mode, + target_array, + target_element, + &getter, + result); + case Primitive::Type::kPrimDouble: + return PrimitiveArrayElementAccessor<double>::Dispatch(access_mode, + target_array, + target_element, + &getter, + result); + case Primitive::Type::kPrimVoid: + break; + } + LOG(FATAL) << "Unreachable: Unexpected primitive " << primitive_type; + UNREACHABLE(); +} + Class* ArrayElementVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { return static_class_.Read(); } @@ -437,6 +1765,90 @@ bool ByteArrayViewVarHandle::GetNativeByteOrder() { return GetFieldBoolean(NativeByteOrderOffset()); } +bool ByteArrayViewVarHandle::Access(AccessMode access_mode, + ShadowFrame* shadow_frame, + InstructionOperands* operands, + JValue* result) { + ShadowFrameGetter getter(*shadow_frame, operands); + + // The byte array is the first co-ordinate type preceeding var type arguments. + ObjPtr<Object> raw_byte_array(getter.GetReference()); + if (raw_byte_array == nullptr) { + ThrowNullPointerExceptionForCoordinate(); + return false; + } + + ObjPtr<ByteArray> byte_array(raw_byte_array->AsByteArray()); + + // The offset in the byte array element is the second co-ordinate type. + const int32_t data_offset = getter.Get(); + + // Bounds check requested access. + const Primitive::Type primitive_type = GetVarType()->GetPrimitiveType(); + if (!CheckElementIndex(primitive_type, data_offset, byte_array->GetLength())) { + return false; + } + + int8_t* const data = byte_array->GetData(); + bool byte_swap = !GetNativeByteOrder(); + switch (primitive_type) { + case Primitive::Type::kPrimNot: + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimVoid: + // These are not supported for byte array views and not instantiable. + break; + case Primitive::kPrimChar: + return ByteArrayViewAccessor<uint16_t>::Dispatch(access_mode, + data, + data_offset, + byte_swap, + &getter, + result); + case Primitive::kPrimShort: + return ByteArrayViewAccessor<int16_t>::Dispatch(access_mode, + data, + data_offset, + byte_swap, + &getter, + result); + case Primitive::kPrimInt: + return ByteArrayViewAccessor<int32_t>::Dispatch(access_mode, + data, + data_offset, + byte_swap, + &getter, + result); + case Primitive::kPrimFloat: + // Treated as a bitwise representation. See javadoc comments for + // java.lang.invoke.MethodHandles.byteArrayViewVarHandle(). + return ByteArrayViewAccessor<int32_t>::Dispatch(access_mode, + data, + data_offset, + byte_swap, + &getter, + result); + case Primitive::kPrimLong: + return ByteArrayViewAccessor<int64_t>::Dispatch(access_mode, + data, + data_offset, + byte_swap, + &getter, + result); + case Primitive::kPrimDouble: + // Treated as a bitwise representation. See javadoc comments for + // java.lang.invoke.MethodHandles.byteArrayViewVarHandle(). + return ByteArrayViewAccessor<int64_t>::Dispatch(access_mode, + data, + data_offset, + byte_swap, + &getter, + result); + } + LOG(FATAL) << "Unreachable: Unexpected primitive " << primitive_type; + UNREACHABLE(); +} + Class* ByteArrayViewVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { return static_class_.Read(); } @@ -462,6 +1874,122 @@ bool ByteBufferViewVarHandle::GetNativeByteOrder() { return GetFieldBoolean(NativeByteOrderOffset()); } +bool ByteBufferViewVarHandle::Access(AccessMode access_mode, + ShadowFrame* shadow_frame, + InstructionOperands* operands, + JValue* result) { + ShadowFrameGetter getter(*shadow_frame, operands); + + // The byte buffer is the first co-ordinate argument preceeding var type arguments. + ObjPtr<Object> byte_buffer(getter.GetReference()); + if (byte_buffer == nullptr) { + ThrowNullPointerExceptionForCoordinate(); + return false; + } + + // The byte index for access is the second co-ordinate + // argument. This is relative to the offset field of the ByteBuffer. + const int32_t byte_index = getter.Get(); + + // Check access_mode is compatible with ByteBuffer's read-only property. + bool is_read_only = byte_buffer->GetFieldBoolean( + GetMemberOffset(WellKnownClasses::java_nio_ByteBuffer_isReadOnly)); + if (is_read_only && !IsReadOnlyAccessMode(access_mode)) { + ThrowReadOnlyBufferException(); + return false; + } + + // The native_address is only set for ByteBuffer instances backed by native memory. + const int64_t native_address = + byte_buffer->GetField64(GetMemberOffset(WellKnownClasses::java_nio_ByteBuffer_address)); + + // Determine offset and limit for accesses. + int32_t byte_buffer_offset; + if (native_address == 0l) { + // Accessing a heap allocated byte buffer. + byte_buffer_offset = byte_buffer->GetField32( + GetMemberOffset(WellKnownClasses::java_nio_ByteBuffer_offset)); + } else { + // Accessing direct memory. + byte_buffer_offset = 0; + } + const int32_t byte_buffer_limit = byte_buffer->GetField32( + GetMemberOffset(WellKnownClasses::java_nio_ByteBuffer_limit)); + + const Primitive::Type primitive_type = GetVarType()->GetPrimitiveType(); + if (!CheckElementIndex(primitive_type, byte_index, byte_buffer_offset, byte_buffer_limit)) { + return false; + } + const int32_t checked_offset32 = byte_buffer_offset + byte_index; + + int8_t* data; + if (native_address == 0) { + ObjPtr<ByteArray> heap_byte_array = byte_buffer->GetFieldObject<ByteArray>( + GetMemberOffset(WellKnownClasses::java_nio_ByteBuffer_hb)); + data = heap_byte_array->GetData(); + } else { + data = reinterpret_cast<int8_t*>(static_cast<uint32_t>(native_address)); + } + + bool byte_swap = !GetNativeByteOrder(); + switch (primitive_type) { + case Primitive::kPrimChar: + return ByteArrayViewAccessor<uint16_t>::Dispatch(access_mode, + data, + checked_offset32, + byte_swap, + &getter, + result); + case Primitive::kPrimShort: + return ByteArrayViewAccessor<int16_t>::Dispatch(access_mode, + data, + checked_offset32, + byte_swap, + &getter, + result); + case Primitive::kPrimInt: + return ByteArrayViewAccessor<int32_t>::Dispatch(access_mode, + data, + checked_offset32, + byte_swap, + &getter, + result); + case Primitive::kPrimFloat: + // Treated as a bitwise representation. See javadoc comments for + // java.lang.invoke.MethodHandles.byteArrayViewVarHandle(). + return ByteArrayViewAccessor<int32_t>::Dispatch(access_mode, + data, + checked_offset32, + byte_swap, + &getter, + result); + case Primitive::kPrimLong: + return ByteArrayViewAccessor<int64_t>::Dispatch(access_mode, + data, + checked_offset32, + byte_swap, + &getter, + result); + case Primitive::kPrimDouble: + // Treated as a bitwise representation. See javadoc comments for + // java.lang.invoke.MethodHandles.byteArrayViewVarHandle(). + return ByteArrayViewAccessor<int64_t>::Dispatch(access_mode, + data, + checked_offset32, + byte_swap, + &getter, + result); + case Primitive::Type::kPrimNot: + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimVoid: + // These are not supported for byte array views and not instantiable. + break; + } + LOG(FATAL) << "Unreachable: Unexpected primitive " << primitive_type; + UNREACHABLE(); +} + Class* ByteBufferViewVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { return static_class_.Read(); } diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h index 7b48669bba..6565af7f06 100644 --- a/runtime/mirror/var_handle.h +++ b/runtime/mirror/var_handle.h @@ -18,18 +18,24 @@ #define ART_RUNTIME_MIRROR_VAR_HANDLE_H_ #include "handle.h" +#include "interpreter/shadow_frame.h" #include "gc_root.h" +#include "jvalue.h" #include "object.h" namespace art { template<class T> class Handle; +class InstructionOperands; + struct VarHandleOffsets; struct FieldVarHandleOffsets; struct ArrayElementVarHandleOffsets; struct ByteArrayViewVarHandleOffsets; struct ByteBufferViewVarHandleOffsets; +class ShadowFrameGetter; + namespace mirror { class MethodType; @@ -44,6 +50,10 @@ class MANAGED VarHandle : public Object { // (array, index, old, new). static constexpr int kMaxAccessorParameters = 4; + // The maximum number of VarType parameters a VarHandle accessor + // method can take. + static constexpr size_t kMaxVarTypeParameters = 2; + // Enumeration of the possible access modes. This mirrors the enum // in java.lang.invoke.VarHandle. enum class AccessMode : uint32_t { @@ -101,11 +111,16 @@ class MANAGED VarHandle : public Object { // supported operation so the MethodType can be used when raising a // WrongMethodTypeException exception. MethodType* GetMethodTypeForAccessMode(Thread* self, AccessMode accessMode) - REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); + REQUIRES_SHARED(Locks::mutator_lock_); - static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return static_class_.Read(); - } + bool Access(AccessMode access_mode, + ShadowFrame* shadow_frame, + InstructionOperands* operands, + JValue* result) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Gets the variable type that is operated on by this VarHandle instance. + Class* GetVarType() REQUIRES_SHARED(Locks::mutator_lock_); // Gets the return type descriptor for a named accessor method, // nullptr if accessor_method is not supported. @@ -115,12 +130,13 @@ class MANAGED VarHandle : public Object { // VarHandle access method, such as "setOpaque". Returns false otherwise. static bool GetAccessModeByMethodName(const char* method_name, AccessMode* access_mode); + + static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); private: - Class* GetVarType() REQUIRES_SHARED(Locks::mutator_lock_); Class* GetCoordinateType0() REQUIRES_SHARED(Locks::mutator_lock_); Class* GetCoordinateType1() REQUIRES_SHARED(Locks::mutator_lock_); int32_t GetAccessModesBitMask() REQUIRES_SHARED(Locks::mutator_lock_); @@ -163,6 +179,12 @@ class MANAGED VarHandle : public Object { // The corresponding managed class in libart java.lang.invoke.FieldVarHandle. class MANAGED FieldVarHandle : public VarHandle { public: + bool Access(AccessMode access_mode, + ShadowFrame* shadow_frame, + InstructionOperands* operands, + JValue* result) + REQUIRES_SHARED(Locks::mutator_lock_); + ArtField* GetField() REQUIRES_SHARED(Locks::mutator_lock_); static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); @@ -190,6 +212,12 @@ class MANAGED FieldVarHandle : public VarHandle { // The corresponding managed class in libart java.lang.invoke.ArrayElementVarHandle. class MANAGED ArrayElementVarHandle : public VarHandle { public: + bool Access(AccessMode access_mode, + ShadowFrame* shadow_frame, + InstructionOperands* operands, + JValue* result) + REQUIRES_SHARED(Locks::mutator_lock_); + static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); @@ -207,6 +235,12 @@ class MANAGED ArrayElementVarHandle : public VarHandle { // The corresponding managed class in libart java.lang.invoke.ByteArrayViewVarHandle. class MANAGED ByteArrayViewVarHandle : public VarHandle { public: + bool Access(AccessMode access_mode, + ShadowFrame* shadow_frame, + InstructionOperands* operands, + JValue* result) + REQUIRES_SHARED(Locks::mutator_lock_); + bool GetNativeByteOrder() REQUIRES_SHARED(Locks::mutator_lock_); static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); @@ -234,10 +268,13 @@ class MANAGED ByteArrayViewVarHandle : public VarHandle { // The corresponding managed class in libart java.lang.invoke.ByteBufferViewVarHandle. class MANAGED ByteBufferViewVarHandle : public VarHandle { public: - bool GetNativeByteOrder() REQUIRES_SHARED(Locks::mutator_lock_); + bool Access(AccessMode access_mode, + ShadowFrame* shadow_frame, + InstructionOperands* operands, + JValue* result) + REQUIRES_SHARED(Locks::mutator_lock_); - static ByteBufferViewVarHandle* Create(Thread* const self, bool native_byte_order) - REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); + bool GetNativeByteOrder() REQUIRES_SHARED(Locks::mutator_lock_); static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); @@ -245,6 +282,21 @@ class MANAGED ByteBufferViewVarHandle : public VarHandle { static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); private: + bool AccessHeapBuffer(AccessMode access_mode, + ObjPtr<Object> byte_buffer, + int buffer_offset, + ObjPtr<ByteArray> heap_byte_array, + ShadowFrameGetter* getter, + JValue* result) + REQUIRES_SHARED(Locks::mutator_lock_); + + bool AccessFixedMemory(AccessMode access_mode, + ObjPtr<Object> byte_buffer, + int buffer_offset, + ShadowFrameGetter* getter, + JValue* result) + REQUIRES_SHARED(Locks::mutator_lock_); + static MemberOffset NativeByteOrderOffset() { return MemberOffset(OFFSETOF_MEMBER(ByteBufferViewVarHandle, native_byte_order_)); } diff --git a/runtime/mirror/var_handle_test.cc b/runtime/mirror/var_handle_test.cc index e844fd4436..d9fa07f207 100644 --- a/runtime/mirror/var_handle_test.cc +++ b/runtime/mirror/var_handle_test.cc @@ -327,7 +327,7 @@ TEST_F(VarHandleTest, InstanceFieldVarHandle) { EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;II)I"))); EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;II)V"))); EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)Z"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(III)V"))); + EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(IIII)V"))); } // Check compatibility - "GetAndUpdate" pattern @@ -336,7 +336,7 @@ TEST_F(VarHandleTest, InstanceFieldVarHandle) { EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)I"))); EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)V"))); EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)Z"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V"))); + EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)S"))); } // Check synthesized method types match expected forms. @@ -461,8 +461,8 @@ TEST_F(VarHandleTest, StaticFieldVarHandle) { EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)I"))); EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V"))); EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(ID)I"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)D"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(III)V"))); + EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)S"))); + EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(IIJ)V"))); } // Check compatibility - "GetAndUpdate" pattern diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 6ea9a7ad62..b49209c4cf 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -549,6 +549,55 @@ static jstring DexFile_getDexFileStatus(JNIEnv* env, return env->NewStringUTF(oat_file_assistant.GetStatusDump().c_str()); } +// Return an array specifying the optimization status of the given file. +// The array specification is [compiler_filter, compiler_reason]. +static jobjectArray DexFile_getDexFileOptimizationStatus(JNIEnv* env, + jclass, + jstring javaFilename, + jstring javaInstructionSet) { + ScopedUtfChars filename(env, javaFilename); + if (env->ExceptionCheck()) { + return nullptr; + } + + ScopedUtfChars instruction_set(env, javaInstructionSet); + if (env->ExceptionCheck()) { + return nullptr; + } + + const InstructionSet target_instruction_set = GetInstructionSetFromString( + instruction_set.c_str()); + if (target_instruction_set == InstructionSet::kNone) { + ScopedLocalRef<jclass> iae(env, env->FindClass("java/lang/IllegalArgumentException")); + std::string message(StringPrintf("Instruction set %s is invalid.", instruction_set.c_str())); + env->ThrowNew(iae.get(), message.c_str()); + return nullptr; + } + + std::string compilation_filter; + std::string compilation_reason; + OatFileAssistant::GetOptimizationStatus( + filename.c_str(), target_instruction_set, &compilation_filter, &compilation_reason); + + ScopedLocalRef<jstring> j_compilation_filter(env, env->NewStringUTF(compilation_filter.c_str())); + if (j_compilation_filter.get() == nullptr) { + return nullptr; + } + ScopedLocalRef<jstring> j_compilation_reason(env, env->NewStringUTF(compilation_reason.c_str())); + if (j_compilation_reason.get() == nullptr) { + return nullptr; + } + + // Now create output array and copy the set into it. + jobjectArray result = env->NewObjectArray(2, + WellKnownClasses::java_lang_String, + nullptr); + env->SetObjectArrayElement(result, 0, j_compilation_filter.get()); + env->SetObjectArrayElement(result, 1, j_compilation_reason.get()); + + return result; +} + static jint DexFile_getDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename, @@ -801,7 +850,9 @@ static JNINativeMethod gMethods[] = { "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"), NATIVE_METHOD(DexFile, getDexFileOutputPaths, "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"), - NATIVE_METHOD(DexFile, getStaticSizeOfDexFile, "(Ljava/lang/Object;)J") + NATIVE_METHOD(DexFile, getStaticSizeOfDexFile, "(Ljava/lang/Object;)J"), + NATIVE_METHOD(DexFile, getDexFileOptimizationStatus, + "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;") }; void register_dalvik_system_DexFile(JNIEnv* env) { diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc index 57a429cf1e..505b745200 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -405,18 +405,15 @@ static void PreloadDexCachesResolveMethod(ObjPtr<mirror::DexCache> dex_cache, ui } const DexFile* dex_file = dex_cache->GetDexFile(); const DexFile::MethodId& method_id = dex_file->GetMethodId(method_idx); - ObjPtr<mirror::Class> klass = Runtime::Current()->GetClassLinker()->LookupResolvedType( + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + + ObjPtr<mirror::Class> klass = class_linker->LookupResolvedType( method_id.class_idx_, dex_cache, /* class_loader */ nullptr); if (klass == nullptr) { return; } - ArtMethod* method = klass->IsInterface() - ? klass->FindInterfaceMethod(dex_cache, method_idx, kRuntimePointerSize) - : klass->FindClassMethod(dex_cache, method_idx, kRuntimePointerSize); - if (method == nullptr) { - return; - } - dex_cache->SetResolvedMethod(method_idx, method, kRuntimePointerSize); + // Call FindResolvedMethod to populate the dex cache. + class_linker->FindResolvedMethod(klass, dex_cache, /* class_loader */ nullptr, method_idx); } struct DexCacheStats { diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc index 648a464b6e..12400e26ea 100644 --- a/runtime/native/dalvik_system_ZygoteHooks.cc +++ b/runtime/native/dalvik_system_ZygoteHooks.cc @@ -173,7 +173,7 @@ enum { DEBUG_JAVA_DEBUGGABLE = 1 << 8, DISABLE_VERIFIER = 1 << 9, ONLY_USE_SYSTEM_OAT_FILES = 1 << 10, - DISABLE_HIDDEN_API_CHECKS = 1 << 11, + ENABLE_HIDDEN_API_CHECKS = 1 << 11, DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 12, }; @@ -282,7 +282,7 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env, // Our system thread ID, etc, has changed so reset Thread state. thread->InitAfterFork(); runtime_flags = EnableDebugFeatures(runtime_flags); - bool do_hidden_api_checks = true; + bool do_hidden_api_checks = false; if ((runtime_flags & DISABLE_VERIFIER) != 0) { Runtime::Current()->DisableVerifier(); @@ -294,9 +294,9 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env, runtime_flags &= ~ONLY_USE_SYSTEM_OAT_FILES; } - if ((runtime_flags & DISABLE_HIDDEN_API_CHECKS) != 0) { - do_hidden_api_checks = false; - runtime_flags &= ~DISABLE_HIDDEN_API_CHECKS; + if ((runtime_flags & ENABLE_HIDDEN_API_CHECKS) != 0) { + do_hidden_api_checks = true; + runtime_flags &= ~ENABLE_HIDDEN_API_CHECKS; } if (runtime_flags != 0) { diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index 2091a27ffd..e518553292 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -97,7 +97,8 @@ ALWAYS_INLINE static bool ShouldEnforceHiddenApi(Thread* self) template<typename T> ALWAYS_INLINE static bool ShouldBlockAccessToMember(T* member, Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) { - return hiddenapi::ShouldBlockAccessToMember(member, self, IsCallerInBootClassPath); + return hiddenapi::ShouldBlockAccessToMember( + member, self, IsCallerInBootClassPath, hiddenapi::kReflection); } // Returns true if a class member should be discoverable with reflection given @@ -175,6 +176,12 @@ static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean return soa.AddLocalReference<jclass>(c.Get()); } +static jclass Class_getPrimitiveClass(JNIEnv* env, jclass, jstring name) { + ScopedFastNativeObjectAccess soa(env); + ObjPtr<mirror::Class> klass = mirror::Class::GetPrimitiveClass(soa.Decode<mirror::String>(name)); + return soa.AddLocalReference<jclass>(klass); +} + static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) { ScopedFastNativeObjectAccess soa(env); StackHandleScope<1> hs(soa.Self()); @@ -868,6 +875,7 @@ static JNINativeMethod gMethods[] = { FAST_NATIVE_METHOD(Class, getInnerClassFlags, "(I)I"), FAST_NATIVE_METHOD(Class, getInnerClassName, "()Ljava/lang/String;"), FAST_NATIVE_METHOD(Class, getInterfacesInternal, "()[Ljava/lang/Class;"), + FAST_NATIVE_METHOD(Class, getPrimitiveClass, "(Ljava/lang/String;)Ljava/lang/Class;"), FAST_NATIVE_METHOD(Class, getNameNative, "()Ljava/lang/String;"), FAST_NATIVE_METHOD(Class, getPublicDeclaredFields, "()[Ljava/lang/reflect/Field;"), FAST_NATIVE_METHOD(Class, getSignatureAnnotation, "()[Ljava/lang/String;"), diff --git a/runtime/native/java_lang_Void.cc b/runtime/native/java_lang_Void.cc deleted file mode 100644 index af83dd1a79..0000000000 --- a/runtime/native/java_lang_Void.cc +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2017 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 "java_lang_Void.h" - -#include "nativehelper/jni_macros.h" - -#include "class_linker-inl.h" -#include "jni_internal.h" -#include "native_util.h" -#include "runtime.h" -#include "scoped_fast_native_object_access-inl.h" - -namespace art { - -static jclass Void_lookupType(JNIEnv* env, jclass) { - ScopedFastNativeObjectAccess soa(env); - return soa.AddLocalReference<jclass>( - Runtime::Current()->GetClassLinker()->GetClassRoot(ClassLinker::kPrimitiveVoid)); -} - -static JNINativeMethod gMethods[] = { - FAST_NATIVE_METHOD(Void, lookupType, "()Ljava/lang/Class;"), -}; - -void register_java_lang_Void(JNIEnv* env) { - REGISTER_NATIVE_METHODS("java/lang/Void"); -} - -} // namespace art diff --git a/runtime/native_stack_dump.cc b/runtime/native_stack_dump.cc index 099d77edaa..4d4bab764c 100644 --- a/runtime/native_stack_dump.cc +++ b/runtime/native_stack_dump.cc @@ -345,6 +345,9 @@ void DumpNativeStack(std::ostream& os, } else { os << it->map.name; } + if (it->map.offset != 0) { + os << StringPrintf(" (offset %" PRIx64 ")", it->map.offset); + } os << " ("; if (!it->func_name.empty()) { os << it->func_name; diff --git a/runtime/oat.h b/runtime/oat.h index 8f81010a06..af14b3e601 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -45,6 +45,7 @@ class PACKED(4) OatHeader { static constexpr const char* kClassPathKey = "classpath"; static constexpr const char* kBootClassPathKey = "bootclasspath"; static constexpr const char* kConcurrentCopying = "concurrent-copying"; + static constexpr const char* kCompilationReasonKey = "compilation-reason"; static constexpr const char kTrueValue[] = "true"; static constexpr const char kFalseValue[] = "false"; diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index dc4bae3415..0852da5644 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -633,6 +633,15 @@ bool OatFileBase::Setup(const char* abs_dex_location, std::string* error_msg) { const uint8_t* dex_file_pointer = nullptr; if (UNLIKELY(dex_file_offset == 0U)) { if (uncompressed_dex_files_ == nullptr) { + // Do not support mixed-mode oat files. + if (i > 0) { + *error_msg = StringPrintf("In oat file '%s', unsupported uncompressed-dex-file for dex " + "file %zu (%s)", + GetLocation().c_str(), + i, + dex_file_location.c_str()); + return false; + } uncompressed_dex_files_.reset(new std::vector<std::unique_ptr<const DexFile>>()); // No dex files, load it from location. const ArtDexFileLoader dex_file_loader; @@ -652,9 +661,31 @@ bool OatFileBase::Setup(const char* abs_dex_location, std::string* error_msg) { return false; } } + // The oat file may be out of date wrt/ the dex-file location. We need to be defensive + // here and ensure that at least the number of dex files still matches. + // Note: actual checksum comparisons are the duty of the OatFileAssistant and will be + // done after loading the OatFile. + if (uncompressed_dex_files_->size() != dex_file_count) { + *error_msg = StringPrintf("In oat file '%s', expected %u uncompressed dex files, but " + "found %zu in '%s'", + GetLocation().c_str(), + dex_file_count, + uncompressed_dex_files_->size(), + dex_file_location.c_str()); + return false; + } } dex_file_pointer = uncompressed_dex_files_.get()->at(i)->Begin(); } else { + // Do not support mixed-mode oat files. + if (uncompressed_dex_files_ != nullptr) { + *error_msg = StringPrintf("In oat file '%s', unsupported embedded dex-file for dex file " + "%zu (%s)", + GetLocation().c_str(), + i, + dex_file_location.c_str()); + return false; + } if (UNLIKELY(DexSize() - dex_file_offset < sizeof(DexFile::Header))) { *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with dex file " "offset %u of %zu but the size of dex file header is %zu", @@ -1893,6 +1924,10 @@ std::string OatFile::GetClassLoaderContext() const { return GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey); } +const char* OatFile::GetCompilationReason() const { + return GetOatHeader().GetStoreValueByKey(OatHeader::kCompilationReasonKey); +} + OatFile::OatClass OatFile::FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, bool* found) { diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 46c692e568..802adc3a36 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -130,6 +130,8 @@ class OatFile { std::string GetClassLoaderContext() const; + const char* GetCompilationReason() const; + const std::string& GetLocation() const { return location_; } diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index 15a5954396..0170073e29 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -1262,4 +1262,27 @@ std::unique_ptr<OatFile> OatFileAssistant::OatFileInfo::ReleaseFileForUse() { } return std::unique_ptr<OatFile>(); } + +// TODO(calin): we could provide a more refined status here +// (e.g. run from uncompressed apk, run with vdex but not oat etc). It will allow us to +// track more experiments but adds extra complexity. +void OatFileAssistant::GetOptimizationStatus( + const std::string& filename, + InstructionSet isa, + std::string* out_compilation_filter, + std::string* out_compilation_reason) { + // Try to load the oat file as we would do at runtime. + OatFileAssistant oat_file_assistant(filename.c_str(), isa, true /* load_executable */); + std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); + + if (oat_file == nullptr) { + *out_compilation_filter = "run-from-apk"; + *out_compilation_reason = "unknown"; + } else { + *out_compilation_filter = CompilerFilter::NameOfFilter(oat_file->GetCompilerFilter()); + const char* reason = oat_file->GetCompilationReason(); + *out_compilation_reason = reason == nullptr ? "unknown" : reason; + } +} + } // namespace art diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h index a6140304c2..a184807b73 100644 --- a/runtime/oat_file_assistant.h +++ b/runtime/oat_file_assistant.h @@ -226,6 +226,20 @@ class OatFileAssistant { // dex file. The returned description is for debugging purposes only. std::string GetStatusDump(); + // Computes the optimization status of the given dex file. The result is + // returned via the two output parameters. + // - out_compilation_filter: the level of optimizations (compiler filter) + // - out_compilation_reason: the optimization reason. The reason might + // be "unknown" if the compiler artifacts were not annotated during optimizations. + // + // This method will try to mimic the runtime effect of loading the dex file. + // For example, if there is no usable oat file, the compiler filter will be set + // to "run-from-apk". + static void GetOptimizationStatus(const std::string& filename, + InstructionSet isa, + std::string* out_compilation_filter, + std::string* out_compilation_reason); + // Open and returns an image space associated with the oat file. static std::unique_ptr<gc::space::ImageSpace> OpenImageSpace(const OatFile* oat_file); diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index 50f5e7a0d5..72f7d02892 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -43,7 +43,27 @@ namespace art { static const std::string kSpecialSharedLibrary = "&"; // NOLINT [runtime/string] [4] static ClassLoaderContext* kSpecialSharedLibraryContext = nullptr; -class OatFileAssistantTest : public DexoptTest {}; +class OatFileAssistantTest : public DexoptTest { + public: + void VerifyOptimizationStatus(const std::string& file, + const std::string& expected_filter, + const std::string& expected_reason) { + std::string compilation_filter; + std::string compilation_reason; + OatFileAssistant::GetOptimizationStatus( + file, kRuntimeISA, &compilation_filter, &compilation_reason); + + ASSERT_EQ(expected_filter, compilation_filter); + ASSERT_EQ(expected_reason, compilation_reason); + } + + void VerifyOptimizationStatus(const std::string& file, + CompilerFilter::Filter expected_filter, + const std::string& expected_reason) { + VerifyOptimizationStatus( + file, CompilerFilter::NameOfFilter(expected_filter), expected_reason); + } +}; class OatFileAssistantNoDex2OatTest : public DexoptTest { public: @@ -107,6 +127,8 @@ TEST_F(OatFileAssistantTest, DexNoOat) { EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus()); EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); + + VerifyOptimizationStatus(dex_location, "run-from-apk", "unknown"); } // Case: We have no DEX file and no OAT file. @@ -136,7 +158,7 @@ TEST_F(OatFileAssistantTest, OdexUpToDate) { std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar"; std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex"; Copy(GetDexSrc1(), dex_location); - GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); + GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, "install"); // For the use of oat location by making the dex parent not writable. OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); @@ -154,6 +176,8 @@ TEST_F(OatFileAssistantTest, OdexUpToDate) { EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus()); EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus()); EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); + + VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "install"); } // Case: We have a DEX file and a PIC ODEX file, but no OAT file. We load the dex @@ -221,6 +245,8 @@ TEST_F(OatFileAssistantTest, OatUpToDate) { EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus()); EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); + + VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "unknown"); } // Case: Passing valid file descriptors of updated odex/vdex filesalong with @@ -381,6 +407,8 @@ TEST_F(OatFileAssistantTest, VdexUpToDateNoOdex) { // Make sure we don't crash in this case when we dump the status. We don't // care what the actual dumped value is. oat_file_assistant.GetStatusDump(); + + VerifyOptimizationStatus(dex_location, "run-from-apk", "unknown"); } // Case: We have a DEX file and empty VDEX and ODEX files. diff --git a/runtime/oat_file_test.cc b/runtime/oat_file_test.cc index 8d864018ab..89812f370f 100644 --- a/runtime/oat_file_test.cc +++ b/runtime/oat_file_test.cc @@ -88,4 +88,46 @@ TEST_F(OatFileTest, LoadOat) { EXPECT_EQ(odex_file->GetVdexFile()->Begin(), odex_file->VdexBegin()); } +TEST_F(OatFileTest, ChangingMultiDexUncompressed) { + std::string dex_location = GetScratchDir() + "/MultiDexUncompressed.jar"; + + Copy(GetTestDexFileName("MultiDexUncompressed"), dex_location); + GenerateOatForTest(dex_location.c_str(), CompilerFilter::kQuicken); + + std::string oat_location; + std::string error_msg; + ASSERT_TRUE(OatFileAssistant::DexLocationToOatFilename( + dex_location, kRuntimeISA, &oat_location, &error_msg)) << error_msg; + + // Ensure we can load that file. Just a precondition. + { + std::unique_ptr<OatFile> odex_file(OatFile::Open(oat_location.c_str(), + oat_location.c_str(), + nullptr, + nullptr, + false, + /*low_4gb*/false, + dex_location.c_str(), + &error_msg)); + ASSERT_TRUE(odex_file != nullptr); + ASSERT_EQ(2u, odex_file->GetOatDexFiles().size()); + } + + // Now replace the source. + Copy(GetTestDexFileName("MainUncompressed"), dex_location); + + // And try to load again. + std::unique_ptr<OatFile> odex_file(OatFile::Open(oat_location.c_str(), + oat_location.c_str(), + nullptr, + nullptr, + false, + /*low_4gb*/false, + dex_location.c_str(), + &error_msg)); + EXPECT_TRUE(odex_file == nullptr); + EXPECT_NE(std::string::npos, error_msg.find("expected 2 uncompressed dex files, but found 1")) + << error_msg; +} + } // namespace art diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc index 92eb703338..c7f73d14db 100644 --- a/runtime/parsed_options.cc +++ b/runtime/parsed_options.cc @@ -330,8 +330,10 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize .Define("-Xtarget-sdk-version:_") .WithType<int>() .IntoKey(M::TargetSdkVersion) - .Define("-Xno-hidden-api-checks") - .IntoKey(M::NoHiddenApiChecks) + .Define("-Xhidden-api-checks") + .IntoKey(M::HiddenApiChecks) + .Define("-Xuse-stderr-logger") + .IntoKey(M::UseStderrLogger) .Ignore({ "-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa", "-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:_", diff --git a/runtime/runtime.cc b/runtime/runtime.cc index b26b09c156..d0aec116a4 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -105,6 +105,7 @@ #include "mirror/method_type.h" #include "mirror/stack_trace_element.h" #include "mirror/throwable.h" +#include "mirror/var_handle.h" #include "monitor.h" #include "native/dalvik_system_DexFile.h" #include "native/dalvik_system_VMDebug.h" @@ -119,7 +120,6 @@ #include "native/java_lang_Thread.h" #include "native/java_lang_Throwable.h" #include "native/java_lang_VMClassLoader.h" -#include "native/java_lang_Void.h" #include "native/java_lang_invoke_MethodHandleImpl.h" #include "native/java_lang_ref_FinalizerReference.h" #include "native/java_lang_ref_Reference.h" @@ -265,7 +265,7 @@ Runtime::Runtime() oat_file_manager_(nullptr), is_low_memory_mode_(false), safe_mode_(false), - do_hidden_api_checks_(true), + do_hidden_api_checks_(false), pending_hidden_api_warning_(false), dedupe_hidden_api_warnings_(true), always_set_hidden_api_warning_flag_(false), @@ -1082,10 +1082,16 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { // Take a snapshot of the environment at the time the runtime was created, for use by Exec, etc. env_snapshot_.TakeSnapshot(); - RuntimeArgumentMap runtime_options(std::move(runtime_options_in)); + using Opt = RuntimeArgumentMap; + Opt runtime_options(std::move(runtime_options_in)); ScopedTrace trace(__FUNCTION__); CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize); + // Early override for logging output. + if (runtime_options.Exists(Opt::UseStderrLogger)) { + android::base::SetLogger(android::base::StderrLogger); + } + MemMap::Init(); // Try to reserve a dedicated fault page. This is allocated for clobbered registers and sentinels. @@ -1112,7 +1118,6 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { } } - using Opt = RuntimeArgumentMap; VLOG(startup) << "Runtime::Init -verbose:startup enabled"; QuasiAtomic::Startup(); @@ -1176,14 +1181,7 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { // by default and we only enable them if: // (a) runtime was started with a flag that enables the checks, or // (b) Zygote forked a new process that is not exempt (see ZygoteHooks). - // TODO(dbrazdil): Turn the NoHiddenApiChecks negative flag into a positive one - // to clean up this logic. - if (kIsTargetBuild && IsAotCompiler() && !runtime_options.Exists(Opt::NoHiddenApiChecks)) { - // dex2oat on target without -Xno-hidden-api-checks. - do_hidden_api_checks_ = !IsCompilingBootImage(); - } else { - do_hidden_api_checks_ = false; - } + do_hidden_api_checks_ = runtime_options.Exists(Opt::HiddenApiChecks); DCHECK(!is_zygote_ || !do_hidden_api_checks_) << "Zygote should not be started with hidden API checks"; @@ -1747,7 +1745,6 @@ void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) { register_java_lang_Thread(env); register_java_lang_Throwable(env); register_java_lang_VMClassLoader(env); - register_java_lang_Void(env); register_java_util_concurrent_atomic_AtomicLong(env); register_libcore_util_CharsetUtils(env); register_org_apache_harmony_dalvik_ddmc_DdmServer(env); @@ -1934,6 +1931,11 @@ void Runtime::VisitConstantRoots(RootVisitor* visitor) { mirror::EmulatedStackFrame::VisitRoots(visitor); mirror::ClassExt::VisitRoots(visitor); mirror::CallSite::VisitRoots(visitor); + mirror::VarHandle::VisitRoots(visitor); + mirror::FieldVarHandle::VisitRoots(visitor); + mirror::ArrayElementVarHandle::VisitRoots(visitor); + mirror::ByteArrayViewVarHandle::VisitRoots(visitor); + mirror::ByteBufferViewVarHandle::VisitRoots(visitor); // Visit all the primitive array types classes. mirror::PrimitiveArray<uint8_t>::VisitRoots(visitor); // BooleanArray mirror::PrimitiveArray<int8_t>::VisitRoots(visitor); // ByteArray diff --git a/runtime/runtime.h b/runtime/runtime.h index 7ab9be5c5b..c7f650ea3f 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -325,7 +325,7 @@ class Runtime { // instead. void VisitImageRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - // Visit all of the roots we can do safely do concurrently. + // Visit all of the roots we can safely visit concurrently. void VisitConcurrentRoots(RootVisitor* visitor, VisitRootFlags flags = kVisitRootFlagAllRoots) REQUIRES(!Locks::classlinker_classes_lock_, !Locks::trace_lock_) diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def index e78d952c1c..dba648e785 100644 --- a/runtime/runtime_options.def +++ b/runtime/runtime_options.def @@ -119,7 +119,7 @@ RUNTIME_OPTIONS_KEY (std::vector<std::string>, \ RUNTIME_OPTIONS_KEY (verifier::VerifyMode, \ Verify, verifier::VerifyMode::kEnable) RUNTIME_OPTIONS_KEY (int, TargetSdkVersion, Runtime::kUnsetSdkVersion) -RUNTIME_OPTIONS_KEY (Unit, NoHiddenApiChecks) +RUNTIME_OPTIONS_KEY (Unit, HiddenApiChecks) RUNTIME_OPTIONS_KEY (std::string, NativeBridge) RUNTIME_OPTIONS_KEY (unsigned int, ZygoteMaxFailedBoots, 10) RUNTIME_OPTIONS_KEY (Unit, NoDexFileFallback) @@ -150,5 +150,6 @@ RUNTIME_OPTIONS_KEY (void (*)(), HookAbort, nullpt RUNTIME_OPTIONS_KEY (bool, SlowDebug, false) RUNTIME_OPTIONS_KEY (unsigned int, GlobalRefAllocStackTraceLimit, 0) // 0 = off +RUNTIME_OPTIONS_KEY (Unit, UseStderrLogger) #undef RUNTIME_OPTIONS_KEY diff --git a/runtime/subtype_check.h b/runtime/subtype_check.h index 54d2f00106..3b1d5f8c4a 100644 --- a/runtime/subtype_check.h +++ b/runtime/subtype_check.h @@ -24,6 +24,9 @@ #include "mirror/class.h" #include "runtime.h" +// Build flag for the bitstring subtype check runtime hooks. +constexpr bool kBitstringSubtypeCheckEnabled = false; + /** * Any node in a tree can have its path (from the root to the node) represented as a string by * concatenating the path of the parent to that of the current node. diff --git a/runtime/thread.cc b/runtime/thread.cc index 9dc92f3788..2ee7f9deda 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -663,8 +663,8 @@ void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_siz child_thread->tlsPtr_.jpeer = env->NewGlobalRef(java_peer); stack_size = FixStackSize(stack_size); - // Thread.start is synchronized, so we know that nativePeer is 0, and know that we're not racing to - // assign it. + // Thread.start is synchronized, so we know that nativePeer is 0, and know that we're not racing + // to assign it. env->SetLongField(java_peer, WellKnownClasses::java_lang_Thread_nativePeer, reinterpret_cast<jlong>(child_thread)); @@ -839,7 +839,8 @@ Thread* Thread::Attach(const char* thread_name, if (create_peer) { self->CreatePeer(thread_name, as_daemon, thread_group); if (self->IsExceptionPending()) { - // We cannot keep the exception around, as we're deleting self. Try to be helpful and log it. + // We cannot keep the exception around, as we're deleting self. Try to be helpful and log + // it. { ScopedObjectAccess soa(self); LOG(ERROR) << "Exception creating thread peer:"; @@ -3435,6 +3436,9 @@ bool Thread::HoldsLock(ObjPtr<mirror::Object> object) const { return object != nullptr && object->GetLockOwnerThreadId() == GetThreadId(); } +extern "C" StackReference<mirror::Object>* artQuickGetProxyThisObjectReference(ArtMethod** sp) + REQUIRES_SHARED(Locks::mutator_lock_); + // RootVisitor parameters are: (const Object* obj, size_t vreg, const StackVisitor* visitor). template <typename RootVisitor, bool kPrecise = false> class ReferenceMapVisitor : public StackVisitor { @@ -3535,7 +3539,7 @@ class ReferenceMapVisitor : public StackVisitor { if (!m->IsNative() && !m->IsRuntimeMethod() && (!m->IsProxyMethod() || m->IsConstructor())) { const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); DCHECK(method_header->IsOptimized()); - auto* vreg_base = reinterpret_cast<StackReference<mirror::Object>*>( + StackReference<mirror::Object>* vreg_base = reinterpret_cast<StackReference<mirror::Object>*>( reinterpret_cast<uintptr_t>(cur_quick_frame)); uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc()); CodeInfo code_info = method_header->GetOptimizedCodeInfo(); @@ -3550,7 +3554,7 @@ class ReferenceMapVisitor : public StackVisitor { BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, map); for (size_t i = 0; i < number_of_bits; ++i) { if (stack_mask.LoadBit(i)) { - auto* ref_addr = vreg_base + i; + StackReference<mirror::Object>* ref_addr = vreg_base + i; mirror::Object* ref = ref_addr->AsMirrorPtr(); if (ref != nullptr) { mirror::Object* new_ref = ref; @@ -3579,6 +3583,19 @@ class ReferenceMapVisitor : public StackVisitor { } } } + } else if (!m->IsStatic() && !m->IsRuntimeMethod() && m->IsProxyMethod()) { + // If this is a non-static proxy method, visit its target (`this` object). + DCHECK(!m->IsNative()); + StackReference<mirror::Object>* ref_addr = + artQuickGetProxyThisObjectReference(cur_quick_frame); + mirror::Object* ref = ref_addr->AsMirrorPtr(); + if (ref != nullptr) { + mirror::Object* new_ref = ref; + visitor_(&new_ref, -1, this); + if (ref != new_ref) { + ref_addr->Assign(new_ref); + } + } } } @@ -3773,9 +3790,9 @@ void Thread::VisitRoots(RootVisitor* visitor) { void Thread::VisitRoots(RootVisitor* visitor, VisitRootFlags flags) { if ((flags & VisitRootFlags::kVisitRootFlagPrecise) != 0) { - VisitRoots<true>(visitor); + VisitRoots</* kPrecise */ true>(visitor); } else { - VisitRoots<false>(visitor); + VisitRoots</* kPrecise */ false>(visitor); } } diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index afb3224944..66e578f312 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -3899,21 +3899,13 @@ ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess( } ObjPtr<mirror::Class> klass = klass_type.GetClass(); const RegType& referrer = GetDeclaringClass(); - auto* cl = Runtime::Current()->GetClassLinker(); - auto pointer_size = cl->GetImagePointerSize(); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + PointerSize pointer_size = class_linker->GetImagePointerSize(); ArtMethod* res_method = dex_cache_->GetResolvedMethod(dex_method_idx, pointer_size); if (res_method == nullptr) { - // Try to find the method with the appropriate lookup for the klass type (interface or not). - // If this lookup does not match `method_type`, errors shall be reported below. - if (klass->IsInterface()) { - res_method = klass->FindInterfaceMethod(dex_cache_.Get(), dex_method_idx, pointer_size); - } else { - res_method = klass->FindClassMethod(dex_cache_.Get(), dex_method_idx, pointer_size); - } - if (res_method != nullptr) { - dex_cache_->SetResolvedMethod(dex_method_idx, res_method, pointer_size); - } + res_method = class_linker->FindResolvedMethod( + klass, dex_cache_.Get(), class_loader_.Get(), dex_method_idx); } // Record result of method resolution attempt. The klass resolution has recorded whether @@ -4432,6 +4424,8 @@ bool MethodVerifier::CheckSignaturePolymorphicMethod(ArtMethod* method) { expected_return_descriptor = mirror::MethodHandle::GetReturnTypeDescriptor(method_name); } else if (klass == mirror::VarHandle::StaticClass()) { expected_return_descriptor = mirror::VarHandle::GetReturnTypeDescriptor(method_name); + // TODO: add compiler support for VarHandle accessor methods (b/71781600) + Fail(VERIFY_ERROR_FORCE_INTERPRETER); } else { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Signature polymorphic method in unsuppported class: " << klass->PrettyDescriptor(); diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc index 5564684c4f..30aefede20 100644 --- a/runtime/verifier/reg_type_cache.cc +++ b/runtime/verifier/reg_type_cache.cc @@ -278,7 +278,7 @@ RegTypeCache::RegTypeCache(bool can_load_classes, ScopedArenaAllocator& allocato klass_entries_(allocator.Adapter(kArenaAllocVerifier)), can_load_classes_(can_load_classes), allocator_(allocator) { - DCHECK(can_suspend || !can_load_classes) << "Cannot load classes is suspension is disabled!"; + DCHECK(can_suspend || !can_load_classes) << "Cannot load classes if suspension is disabled!"; if (kIsDebugBuild && can_suspend) { Thread::Current()->AssertThreadSuspensionIsAllowable(gAborting == 0); } diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index 5fe10f5c12..67ea64be74 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -72,6 +72,7 @@ jclass WellKnownClasses::java_lang_System; jclass WellKnownClasses::java_lang_Thread; jclass WellKnownClasses::java_lang_ThreadGroup; jclass WellKnownClasses::java_lang_Throwable; +jclass WellKnownClasses::java_nio_ByteBuffer; jclass WellKnownClasses::java_nio_DirectByteBuffer; jclass WellKnownClasses::java_util_ArrayList; jclass WellKnownClasses::java_util_Collections; @@ -142,6 +143,11 @@ jfieldID WellKnownClasses::java_lang_Throwable_stackState; jfieldID WellKnownClasses::java_lang_Throwable_suppressedExceptions; jfieldID WellKnownClasses::java_lang_reflect_Executable_artMethod; jfieldID WellKnownClasses::java_lang_reflect_Proxy_h; +jfieldID WellKnownClasses::java_nio_ByteBuffer_address; +jfieldID WellKnownClasses::java_nio_ByteBuffer_hb; +jfieldID WellKnownClasses::java_nio_ByteBuffer_isReadOnly; +jfieldID WellKnownClasses::java_nio_ByteBuffer_limit; +jfieldID WellKnownClasses::java_nio_ByteBuffer_offset; jfieldID WellKnownClasses::java_nio_DirectByteBuffer_capacity; jfieldID WellKnownClasses::java_nio_DirectByteBuffer_effectiveDirectAddress; jfieldID WellKnownClasses::java_util_ArrayList_array; @@ -277,7 +283,27 @@ uint32_t WellKnownClasses::StringInitToEntryPoint(ArtMethod* string_init) { } #undef STRING_INIT_LIST +class ScopedHiddenApiExemption { + public: + explicit ScopedHiddenApiExemption(Runtime* runtime) + : runtime_(runtime), + initially_enabled_(runtime_->AreHiddenApiChecksEnabled()) { + runtime_->SetHiddenApiChecksEnabled(false); + } + + ~ScopedHiddenApiExemption() { + runtime_->SetHiddenApiChecksEnabled(initially_enabled_); + } + + private: + Runtime* runtime_; + const bool initially_enabled_; + DISALLOW_COPY_AND_ASSIGN(ScopedHiddenApiExemption); +}; + void WellKnownClasses::Init(JNIEnv* env) { + ScopedHiddenApiExemption hiddenapi_exemption(Runtime::Current()); + dalvik_annotation_optimization_CriticalNative = CacheClass(env, "dalvik/annotation/optimization/CriticalNative"); dalvik_annotation_optimization_FastNative = CacheClass(env, "dalvik/annotation/optimization/FastNative"); @@ -318,6 +344,7 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_Thread = CacheClass(env, "java/lang/Thread"); java_lang_ThreadGroup = CacheClass(env, "java/lang/ThreadGroup"); java_lang_Throwable = CacheClass(env, "java/lang/Throwable"); + java_nio_ByteBuffer = CacheClass(env, "java/nio/ByteBuffer"); java_nio_DirectByteBuffer = CacheClass(env, "java/nio/DirectByteBuffer"); java_util_ArrayList = CacheClass(env, "java/util/ArrayList"); java_util_Collections = CacheClass(env, "java/util/Collections"); @@ -379,6 +406,11 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_Throwable_stackState = CacheField(env, java_lang_Throwable, false, "backtrace", "Ljava/lang/Object;"); java_lang_Throwable_suppressedExceptions = CacheField(env, java_lang_Throwable, false, "suppressedExceptions", "Ljava/util/List;"); java_lang_reflect_Executable_artMethod = CacheField(env, java_lang_reflect_Executable, false, "artMethod", "J"); + java_nio_ByteBuffer_address = CacheField(env, java_nio_ByteBuffer, false, "address", "J"); + java_nio_ByteBuffer_hb = CacheField(env, java_nio_ByteBuffer, false, "hb", "[B"); + java_nio_ByteBuffer_isReadOnly = CacheField(env, java_nio_ByteBuffer, false, "isReadOnly", "Z"); + java_nio_ByteBuffer_limit = CacheField(env, java_nio_ByteBuffer, false, "limit", "I"); + java_nio_ByteBuffer_offset = CacheField(env, java_nio_ByteBuffer, false, "offset", "I"); java_nio_DirectByteBuffer_capacity = CacheField(env, java_nio_DirectByteBuffer, false, "capacity", "I"); java_nio_DirectByteBuffer_effectiveDirectAddress = CacheField(env, java_nio_DirectByteBuffer, false, "address", "J"); java_util_ArrayList_array = CacheField(env, java_util_ArrayList, false, "elementData", "[Ljava/lang/Object;"); @@ -462,6 +494,7 @@ void WellKnownClasses::Clear() { java_lang_Throwable = nullptr; java_util_ArrayList = nullptr; java_util_Collections = nullptr; + java_nio_ByteBuffer = nullptr; java_nio_DirectByteBuffer = nullptr; libcore_reflect_AnnotationFactory = nullptr; libcore_reflect_AnnotationMember = nullptr; @@ -530,6 +563,11 @@ void WellKnownClasses::Clear() { java_lang_Throwable_stackTrace = nullptr; java_lang_Throwable_stackState = nullptr; java_lang_Throwable_suppressedExceptions = nullptr; + java_nio_ByteBuffer_address = nullptr; + java_nio_ByteBuffer_hb = nullptr; + java_nio_ByteBuffer_isReadOnly = nullptr; + java_nio_ByteBuffer_limit = nullptr; + java_nio_ByteBuffer_offset = nullptr; java_nio_DirectByteBuffer_capacity = nullptr; java_nio_DirectByteBuffer_effectiveDirectAddress = nullptr; java_util_ArrayList_array = nullptr; diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h index 9e0b079b7b..d5d7033132 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -85,6 +85,7 @@ struct WellKnownClasses { static jclass java_lang_Throwable; static jclass java_util_ArrayList; static jclass java_util_Collections; + static jclass java_nio_ByteBuffer; static jclass java_nio_DirectByteBuffer; static jclass libcore_reflect_AnnotationFactory; static jclass libcore_reflect_AnnotationMember; @@ -153,8 +154,14 @@ struct WellKnownClasses { static jfieldID java_lang_Throwable_stackTrace; static jfieldID java_lang_Throwable_stackState; static jfieldID java_lang_Throwable_suppressedExceptions; + static jfieldID java_nio_ByteBuffer_address; + static jfieldID java_nio_ByteBuffer_hb; + static jfieldID java_nio_ByteBuffer_isReadOnly; + static jfieldID java_nio_ByteBuffer_limit; + static jfieldID java_nio_ByteBuffer_offset; static jfieldID java_nio_DirectByteBuffer_capacity; static jfieldID java_nio_DirectByteBuffer_effectiveDirectAddress; + static jfieldID java_util_ArrayList_array; static jfieldID java_util_ArrayList_size; static jfieldID java_util_Collections_EMPTY_LIST; diff --git a/test/030-bad-finalizer/expected.txt b/test/030-bad-finalizer/expected.txt index 74e208c3f9..0aca6f2e93 100644 --- a/test/030-bad-finalizer/expected.txt +++ b/test/030-bad-finalizer/expected.txt @@ -2,3 +2,4 @@ About to null reference. Finalizer started and spinning... Finalizer done spinning. Finalizer sleeping forever now. +exit status: 2 diff --git a/test/911-get-stack-trace/build b/test/030-bad-finalizer/run index 10ffcc537d..7a0d0d05ab 100644..100755 --- a/test/911-get-stack-trace/build +++ b/test/030-bad-finalizer/run @@ -14,7 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# See b/65168732 -export USE_D8=false - -./default-build "$@" +# Squash the exit status and put it in expected +./default-run "$@" +echo "exit status:" $? diff --git a/test/034-call-null/expected.txt b/test/034-call-null/expected.txt index 4e0281e556..11aefde417 100644 --- a/test/034-call-null/expected.txt +++ b/test/034-call-null/expected.txt @@ -1,2 +1,3 @@ Exception in thread "main" java.lang.NullPointerException: Attempt to invoke direct method 'void Main.doStuff(int, int[][], java.lang.String, java.lang.String[][])' on a null object reference at Main.main(Main.java:26) +exit status: 1 diff --git a/test/1937-transform-soft-fail/check b/test/034-call-null/run index 7cee530291..7a0d0d05ab 100755 --- a/test/1937-transform-soft-fail/check +++ b/test/034-call-null/run @@ -1,12 +1,12 @@ #!/bin/bash # -# Copyright (C) 2017 The Android Open Source Project +# Copyright 2017 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 +# 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, @@ -14,6 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -sed -e 's/:.*$//' "$2" > "$2.tmp" - -./default-check "$1" "$2.tmp" +# Squash the exit status and put it in expected +./default-run "$@" +echo "exit status:" $? diff --git a/test/038-inner-null/expected.txt b/test/038-inner-null/expected.txt index 2e925644e3..d148eff407 100644 --- a/test/038-inner-null/expected.txt +++ b/test/038-inner-null/expected.txt @@ -2,3 +2,4 @@ new Special() Exception in thread "main" java.lang.NullPointerException: Attempt to invoke virtual method 'void Main$Blort.repaint()' on a null object reference at Main$Special.callInner(Main.java:31) at Main.main(Main.java:20) +exit status: 1 diff --git a/test/038-inner-null/run b/test/038-inner-null/run new file mode 100755 index 0000000000..7a0d0d05ab --- /dev/null +++ b/test/038-inner-null/run @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Copyright 2017 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. + +# Squash the exit status and put it in expected +./default-run "$@" +echo "exit status:" $? diff --git a/test/046-reflect/src/Main.java b/test/046-reflect/src/Main.java index b8a48ea247..6d6cc132d1 100644 --- a/test/046-reflect/src/Main.java +++ b/test/046-reflect/src/Main.java @@ -232,10 +232,10 @@ public class Main { field.set(instance, null); /* - * Try getDeclaredField on a non-existant field. + * Try getDeclaredField on a non-existent field. */ try { - field = target.getDeclaredField("nonExistant"); + field = target.getDeclaredField("nonExistent"); System.out.println("ERROR: Expected NoSuchFieldException"); } catch (NoSuchFieldException nsfe) { String msg = nsfe.getMessage(); diff --git a/test/054-uncaught/expected.txt b/test/054-uncaught/expected.txt index 7d7f03c3a7..878260a07d 100644 --- a/test/054-uncaught/expected.txt +++ b/test/054-uncaught/expected.txt @@ -18,3 +18,4 @@ Uncaught exception DEFAULT! java.lang.NullPointerException: Hi diddly-ho, neighborino. at Main.catchTheUncaught(Main.java:63) at Main.main(Main.java:26) +exit status: 1 diff --git a/test/054-uncaught/run b/test/054-uncaught/run new file mode 100755 index 0000000000..7a0d0d05ab --- /dev/null +++ b/test/054-uncaught/run @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Copyright 2017 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. + +# Squash the exit status and put it in expected +./default-run "$@" +echo "exit status:" $? diff --git a/test/075-verification-error/src/Main.java b/test/075-verification-error/src/Main.java index 13aeaee7e4..2519de5132 100644 --- a/test/075-verification-error/src/Main.java +++ b/test/075-verification-error/src/Main.java @@ -31,7 +31,7 @@ public class Main { testBadInterfaceMethod(); } /** - * Try to create and invoke a non-existant interface method. + * Try to create and invoke a non-existent interface method. */ static void testBadInterfaceMethod() { BadInterface badiface = new BadIfaceImpl(); diff --git a/test/134-nodex2oat-nofallback/run b/test/134-nodex2oat-nofallback/run index 38b4adb183..33265ac471 100755 --- a/test/134-nodex2oat-nofallback/run +++ b/test/134-nodex2oat-nofallback/run @@ -18,3 +18,5 @@ flags="${@}" # Make sure we cannot run without an oat file without fallback. ${RUN} ${flags} --runtime-option -Xnodex2oat --runtime-option -Xno-dex-file-fallback +# Suppress the exit value. This isn't expected to be successful. +echo "Exit status:" $? diff --git a/test/1917-get-stack-frame/expected.txt b/test/1917-get-stack-frame/expected.txt index 4c9efcf157..06f5873d76 100644 --- a/test/1917-get-stack-frame/expected.txt +++ b/test/1917-get-stack-frame/expected.txt @@ -1,6 +1,6 @@ Recurring 5 times 'private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread)' line: -1 -'public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread)' line: 60 +'public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread)' line: 61 'public void art.Test1917$StackTraceGenerator.run()' line: 82 'public void art.Test1917$RecurCount.doRecur(int)' line: 104 'public void art.Test1917$RecurCount.doRecur(int)' line: 102 @@ -12,7 +12,7 @@ Recurring 5 times 'public static void art.Test1917.run() throws java.lang.Exception' line: 133 Recurring 5 times on another thread 'private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread)' line: -1 -'public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread)' line: 60 +'public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread)' line: 61 'public void art.Test1917$StackTraceGenerator.run()' line: 82 'public void art.Test1917$RecurCount.doRecur(int)' line: 104 'public void art.Test1917$RecurCount.doRecur(int)' line: 102 diff --git a/test/1917-get-stack-frame/src/art/StackTrace.java b/test/1917-get-stack-frame/src/art/StackTrace.java index b12c3df66b..2ea2f201e8 100644 --- a/test/1917-get-stack-frame/src/art/StackTrace.java +++ b/test/1917-get-stack-frame/src/art/StackTrace.java @@ -53,7 +53,8 @@ public class StackTrace { // consistent we will suspend for the RI. boolean suspend_thread = !System.getProperty("java.vm.name").equals("Dalvik") && - !thr.equals(Thread.currentThread()); + !thr.equals(Thread.currentThread()) && + !Suspension.isSuspended(thr); if (suspend_thread) { Suspension.suspend(thr); } diff --git a/test/1927-exception-event/expected.txt b/test/1927-exception-event/expected.txt index be8f39c29a..fcdd814977 100644 --- a/test/1927-exception-event/expected.txt +++ b/test/1927-exception-event/expected.txt @@ -3,7 +3,7 @@ Running test_J main: public static void art.Test1927.test_J() @ line = 110 throws class art.Test1927$TestException: from java Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static void art.Test1927.test_J() @ line = 110 @@ -12,7 +12,7 @@ main: public static void art.Test1927.test_J() @ line = 110 throws class art.Tes main: public static void art.Test1927.test_J() @ line = 111 caught class art.Test1927$TestException: from java Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 43 public static void art.Test1927.test_J() @ line = 111 @@ -24,7 +24,7 @@ Running test_J_J() main: public static void art.Test1927.terminal_J() @ line = 103 throws class art.Test1927$TestException: from java Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static void art.Test1927.terminal_J() @ line = 103 @@ -34,7 +34,7 @@ main: public static void art.Test1927.terminal_J() @ line = 103 throws class art main: public static void art.Test1927.test_J_J() @ line = 122 caught class art.Test1927$TestException: from java Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 43 public static void art.Test1927.test_J_J() @ line = 122 @@ -44,7 +44,7 @@ Running test_J_N() main: public static native void art.Test1927.terminal_N() @ line = -1 throws class art.Test1927$TestException: from native Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static native void art.Test1927.terminal_N() @ line = -1 @@ -54,7 +54,7 @@ main: public static native void art.Test1927.terminal_N() @ line = -1 throws cla main: public static void art.Test1927.test_J_N() @ line = 130 caught class art.Test1927$TestException: from native Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 43 public static void art.Test1927.test_J_N() @ line = 130 @@ -64,7 +64,7 @@ Running test_N_J() main: public static void art.Test1927.terminal_J() @ line = 103 throws class art.Test1927$TestException: from java Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static void art.Test1927.terminal_J() @ line = 103 @@ -76,7 +76,7 @@ Running test_N_N() main: public static native void art.Test1927.terminal_N() @ line = -1 throws class art.Test1927$TestException: from native Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static native void art.Test1927.terminal_N() @ line = -1 @@ -88,7 +88,7 @@ Running test_J_J_J() main: public static void art.Test1927.terminal_J() @ line = 103 throws class art.Test1927$TestException: from java Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static void art.Test1927.terminal_J() @ line = 103 @@ -99,7 +99,7 @@ main: public static void art.Test1927.terminal_J() @ line = 103 throws class art main: public static void art.Test1927.test_J_J_J() @ line = 146 caught class art.Test1927$TestException: from java Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 43 public static void art.Test1927.test_J_J_J() @ line = 146 @@ -109,7 +109,7 @@ Running test_J_J_N() main: public static native void art.Test1927.terminal_N() @ line = -1 throws class art.Test1927$TestException: from native Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static native void art.Test1927.terminal_N() @ line = -1 @@ -120,7 +120,7 @@ main: public static native void art.Test1927.terminal_N() @ line = -1 throws cla main: public static void art.Test1927.test_J_J_N() @ line = 154 caught class art.Test1927$TestException: from native Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 43 public static void art.Test1927.test_J_J_N() @ line = 154 @@ -130,7 +130,7 @@ Running test_J_N_J() main: public static void art.Test1927.terminal_J() @ line = 103 throws class art.Test1927$TestException: from java Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static void art.Test1927.terminal_J() @ line = 103 @@ -141,7 +141,7 @@ main: public static void art.Test1927.terminal_J() @ line = 103 throws class art main: public static void art.Test1927.test_J_N_J() @ line = 162 caught class art.Test1927$TestException: from java Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 43 public static void art.Test1927.test_J_N_J() @ line = 162 @@ -151,7 +151,7 @@ Running test_J_N_N() main: public static native void art.Test1927.terminal_N() @ line = -1 throws class art.Test1927$TestException: from native Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static native void art.Test1927.terminal_N() @ line = -1 @@ -162,7 +162,7 @@ main: public static native void art.Test1927.terminal_N() @ line = -1 throws cla main: public static void art.Test1927.test_J_N_N() @ line = 170 caught class art.Test1927$TestException: from native Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 43 public static void art.Test1927.test_J_N_N() @ line = 170 @@ -172,7 +172,7 @@ Running test_N_J_J() main: public static void art.Test1927.terminal_J() @ line = 103 throws class art.Test1927$TestException: from java Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static void art.Test1927.terminal_J() @ line = 103 @@ -185,7 +185,7 @@ Running test_N_J_N() main: public static native void art.Test1927.terminal_N() @ line = -1 throws class art.Test1927$TestException: from native Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static native void art.Test1927.terminal_N() @ line = -1 @@ -198,7 +198,7 @@ Running test_N_N_J() main: public static void art.Test1927.terminal_J() @ line = 103 throws class art.Test1927$TestException: from java Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static void art.Test1927.terminal_J() @ line = 103 @@ -211,7 +211,7 @@ Running test_N_N_N() main: public static native void art.Test1927.terminal_N() @ line = -1 throws class art.Test1927$TestException: from native Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static native void art.Test1927.terminal_N() @ line = -1 @@ -224,7 +224,7 @@ Running test_extra_N_J_J() main: public static void art.Test1927.terminal_J() @ line = 103 throws class art.Test1927$TestException: from java Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static void art.Test1927.terminal_J() @ line = 103 @@ -238,7 +238,7 @@ Running test_extra_N_J_N() main: public static native void art.Test1927.terminal_N() @ line = -1 throws class art.Test1927$TestException: from native Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static native void art.Test1927.terminal_N() @ line = -1 @@ -252,7 +252,7 @@ Running test_extra_N_N_J() main: public static void art.Test1927.terminal_J() @ line = 103 throws class art.Test1927$TestException: from java Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static void art.Test1927.terminal_J() @ line = 103 @@ -266,7 +266,7 @@ Running test_extra_N_N_N() main: public static native void art.Test1927.terminal_N() @ line = -1 throws class art.Test1927$TestException: from native Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1927.PrintStack() @ line = 28 public static void art.Test1927.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 66 public static native void art.Test1927.terminal_N() @ line = -1 diff --git a/test/1927-exception-event/src/art/StackTrace.java b/test/1927-exception-event/src/art/StackTrace.java index b12c3df66b..2ea2f201e8 100644 --- a/test/1927-exception-event/src/art/StackTrace.java +++ b/test/1927-exception-event/src/art/StackTrace.java @@ -53,7 +53,8 @@ public class StackTrace { // consistent we will suspend for the RI. boolean suspend_thread = !System.getProperty("java.vm.name").equals("Dalvik") && - !thr.equals(Thread.currentThread()); + !thr.equals(Thread.currentThread()) && + !Suspension.isSuspended(thr); if (suspend_thread) { Suspension.suspend(thr); } diff --git a/test/1928-exception-event-exception/expected.txt b/test/1928-exception-event-exception/expected.txt index 1692d042e4..73c69727aa 100644 --- a/test/1928-exception-event-exception/expected.txt +++ b/test/1928-exception-event-exception/expected.txt @@ -2,235 +2,119 @@ Test "art.Test1928$DoThrowClass": Running with handler "art.Test1928$DoNothingHa main: public static void art.Test1928.doThrow() @ line = 110 throws class art.Test1928$TestException: doThrow Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1928.PrintStack() @ line = 35 public static void art.Test1928.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 59 public static void art.Test1928.doThrow() @ line = 110 public void art.Test1928$DoThrowClass.run() @ line = 114 public static void art.Test1928.run() throws java.lang.Exception @ line = 196 Will be caught by: public static void art.Test1928.run() throws java.lang.Exception @ line = 199 -exception is: art.Test1928$TestException: doThrow - at art.Test1928.doThrow(Test1928.java:110) - at art.Test1928$DoThrowClass.run(Test1928.java:114) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) Doing nothing! Test "art.Test1928$DoThrowClass": Caught error art.Test1928$TestException:"doThrow" with handler "art.Test1928$DoNothingHandler" -art.Test1928$TestException: doThrow - at art.Test1928.doThrow(Test1928.java:110) - at art.Test1928$DoThrowClass.run(Test1928.java:114) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) Test "art.Test1928$DoThrowClass": Finished running with handler "art.Test1928$DoNothingHandler" Test "art.Test1928$DoThrowCatchBaseTestException": Running with handler "art.Test1928$DoNothingHandler" main: public static void art.Test1928.throwCatchBaseTestException() @ line = 119 throws class art.Test1928$TestException: throwCatchBaseTestException Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1928.PrintStack() @ line = 35 public static void art.Test1928.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 59 public static void art.Test1928.throwCatchBaseTestException() @ line = 119 public void art.Test1928$DoThrowCatchBaseTestException.run() @ line = 129 public static void art.Test1928.run() throws java.lang.Exception @ line = 196 Will be caught by: public static void art.Test1928.throwCatchBaseTestException() @ line = 120 -exception is: art.Test1928$TestException: throwCatchBaseTestException - at art.Test1928.throwCatchBaseTestException(Test1928.java:119) - at art.Test1928$DoThrowCatchBaseTestException.run(Test1928.java:129) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) Doing nothing! Caught art.Test1928$TestException: "throwCatchBaseTestException" -art.Test1928$TestException: throwCatchBaseTestException - at art.Test1928.throwCatchBaseTestException(Test1928.java:119) - at art.Test1928$DoThrowCatchBaseTestException.run(Test1928.java:129) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) Test "art.Test1928$DoThrowCatchBaseTestException": No error caught with handler "art.Test1928$DoNothingHandler" Test "art.Test1928$DoThrowCatchBaseTestException": Finished running with handler "art.Test1928$DoNothingHandler" Test "art.Test1928$DoThrowCatchTestException": Running with handler "art.Test1928$DoNothingHandler" main: public static void art.Test1928.throwCatchTestException() @ line = 134 throws class art.Test1928$TestException: throwCatchTestException Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1928.PrintStack() @ line = 35 public static void art.Test1928.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 59 public static void art.Test1928.throwCatchTestException() @ line = 134 public void art.Test1928$DoThrowCatchTestException.run() @ line = 144 public static void art.Test1928.run() throws java.lang.Exception @ line = 196 Will be caught by: public static void art.Test1928.throwCatchTestException() @ line = 135 -exception is: art.Test1928$TestException: throwCatchTestException - at art.Test1928.throwCatchTestException(Test1928.java:134) - at art.Test1928$DoThrowCatchTestException.run(Test1928.java:144) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) Doing nothing! Caught art.Test1928$TestException: "throwCatchTestException" -art.Test1928$TestException: throwCatchTestException - at art.Test1928.throwCatchTestException(Test1928.java:134) - at art.Test1928$DoThrowCatchTestException.run(Test1928.java:144) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) Test "art.Test1928$DoThrowCatchTestException": No error caught with handler "art.Test1928$DoNothingHandler" Test "art.Test1928$DoThrowCatchTestException": Finished running with handler "art.Test1928$DoNothingHandler" Test "art.Test1928$DoThrowCatchTestExceptionNoRethrow": Running with handler "art.Test1928$DoNothingHandler" main: public static void art.Test1928.throwCatchTestExceptionNoRethrow() @ line = 149 throws class art.Test1928$TestException: throwCatchTestExceptionNoRethrow Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1928.PrintStack() @ line = 35 public static void art.Test1928.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 59 public static void art.Test1928.throwCatchTestExceptionNoRethrow() @ line = 149 public void art.Test1928$DoThrowCatchTestExceptionNoRethrow.run() @ line = 159 public static void art.Test1928.run() throws java.lang.Exception @ line = 196 Will be caught by: public static void art.Test1928.run() throws java.lang.Exception @ line = 199 -exception is: art.Test1928$TestException: throwCatchTestExceptionNoRethrow - at art.Test1928.throwCatchTestExceptionNoRethrow(Test1928.java:149) - at art.Test1928$DoThrowCatchTestExceptionNoRethrow.run(Test1928.java:159) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) Doing nothing! Test "art.Test1928$DoThrowCatchTestExceptionNoRethrow": Caught error art.Test1928$TestException:"throwCatchTestExceptionNoRethrow" with handler "art.Test1928$DoNothingHandler" -art.Test1928$TestException: throwCatchTestExceptionNoRethrow - at art.Test1928.throwCatchTestExceptionNoRethrow(Test1928.java:149) - at art.Test1928$DoThrowCatchTestExceptionNoRethrow.run(Test1928.java:159) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) Test "art.Test1928$DoThrowCatchTestExceptionNoRethrow": Finished running with handler "art.Test1928$DoNothingHandler" Test "art.Test1928$DoThrowClass": Running with handler "art.Test1928$ThrowCatchBase" main: public static void art.Test1928.doThrow() @ line = 110 throws class art.Test1928$TestException: doThrow Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1928.PrintStack() @ line = 35 public static void art.Test1928.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 59 public static void art.Test1928.doThrow() @ line = 110 public void art.Test1928$DoThrowClass.run() @ line = 114 public static void art.Test1928.run() throws java.lang.Exception @ line = 196 Will be caught by: public static void art.Test1928.run() throws java.lang.Exception @ line = 199 -exception is: art.Test1928$TestException: doThrow - at art.Test1928.doThrow(Test1928.java:110) - at art.Test1928$DoThrowClass.run(Test1928.java:114) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) Throwing BaseTestException and catching it! Caught art.Test1928$BaseTestException: "ThrowBaseHandler during throw from public static void art.Test1928.doThrow() @ line = 110" -art.Test1928$BaseTestException: ThrowBaseHandler during throw from public static void art.Test1928.doThrow() @ line = 110 - at art.Test1928$ThrowCatchBase.exceptionOccurred(Test1928.java:99) - at art.Test1928.ExceptionEvent(Test1928.java:66) - at art.Test1928.doThrow(Test1928.java:110) - at art.Test1928$DoThrowClass.run(Test1928.java:114) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) -Caused by: art.Test1928$TestException: doThrow - ... 4 more Test "art.Test1928$DoThrowClass": Caught error art.Test1928$TestException:"doThrow" with handler "art.Test1928$ThrowCatchBase" -art.Test1928$TestException: doThrow - at art.Test1928.doThrow(Test1928.java:110) - at art.Test1928$DoThrowClass.run(Test1928.java:114) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) Test "art.Test1928$DoThrowClass": Finished running with handler "art.Test1928$ThrowCatchBase" Test "art.Test1928$DoThrowCatchBaseTestException": Running with handler "art.Test1928$ThrowCatchBase" main: public static void art.Test1928.throwCatchBaseTestException() @ line = 119 throws class art.Test1928$TestException: throwCatchBaseTestException Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1928.PrintStack() @ line = 35 public static void art.Test1928.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 59 public static void art.Test1928.throwCatchBaseTestException() @ line = 119 public void art.Test1928$DoThrowCatchBaseTestException.run() @ line = 129 public static void art.Test1928.run() throws java.lang.Exception @ line = 196 Will be caught by: public static void art.Test1928.throwCatchBaseTestException() @ line = 120 -exception is: art.Test1928$TestException: throwCatchBaseTestException - at art.Test1928.throwCatchBaseTestException(Test1928.java:119) - at art.Test1928$DoThrowCatchBaseTestException.run(Test1928.java:129) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) Throwing BaseTestException and catching it! Caught art.Test1928$BaseTestException: "ThrowBaseHandler during throw from public static void art.Test1928.throwCatchBaseTestException() @ line = 119" -art.Test1928$BaseTestException: ThrowBaseHandler during throw from public static void art.Test1928.throwCatchBaseTestException() @ line = 119 - at art.Test1928$ThrowCatchBase.exceptionOccurred(Test1928.java:99) - at art.Test1928.ExceptionEvent(Test1928.java:66) - at art.Test1928.throwCatchBaseTestException(Test1928.java:119) - at art.Test1928$DoThrowCatchBaseTestException.run(Test1928.java:129) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) -Caused by: art.Test1928$TestException: throwCatchBaseTestException - ... 4 more Caught art.Test1928$TestException: "throwCatchBaseTestException" -art.Test1928$TestException: throwCatchBaseTestException - at art.Test1928.throwCatchBaseTestException(Test1928.java:119) - at art.Test1928$DoThrowCatchBaseTestException.run(Test1928.java:129) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) Test "art.Test1928$DoThrowCatchBaseTestException": No error caught with handler "art.Test1928$ThrowCatchBase" Test "art.Test1928$DoThrowCatchBaseTestException": Finished running with handler "art.Test1928$ThrowCatchBase" Test "art.Test1928$DoThrowCatchTestException": Running with handler "art.Test1928$ThrowCatchBase" main: public static void art.Test1928.throwCatchTestException() @ line = 134 throws class art.Test1928$TestException: throwCatchTestException Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1928.PrintStack() @ line = 35 public static void art.Test1928.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 59 public static void art.Test1928.throwCatchTestException() @ line = 134 public void art.Test1928$DoThrowCatchTestException.run() @ line = 144 public static void art.Test1928.run() throws java.lang.Exception @ line = 196 Will be caught by: public static void art.Test1928.throwCatchTestException() @ line = 135 -exception is: art.Test1928$TestException: throwCatchTestException - at art.Test1928.throwCatchTestException(Test1928.java:134) - at art.Test1928$DoThrowCatchTestException.run(Test1928.java:144) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) Throwing BaseTestException and catching it! Caught art.Test1928$BaseTestException: "ThrowBaseHandler during throw from public static void art.Test1928.throwCatchTestException() @ line = 134" -art.Test1928$BaseTestException: ThrowBaseHandler during throw from public static void art.Test1928.throwCatchTestException() @ line = 134 - at art.Test1928$ThrowCatchBase.exceptionOccurred(Test1928.java:99) - at art.Test1928.ExceptionEvent(Test1928.java:66) - at art.Test1928.throwCatchTestException(Test1928.java:134) - at art.Test1928$DoThrowCatchTestException.run(Test1928.java:144) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) -Caused by: art.Test1928$TestException: throwCatchTestException - ... 4 more Caught art.Test1928$TestException: "throwCatchTestException" -art.Test1928$TestException: throwCatchTestException - at art.Test1928.throwCatchTestException(Test1928.java:134) - at art.Test1928$DoThrowCatchTestException.run(Test1928.java:144) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) Test "art.Test1928$DoThrowCatchTestException": No error caught with handler "art.Test1928$ThrowCatchBase" Test "art.Test1928$DoThrowCatchTestException": Finished running with handler "art.Test1928$ThrowCatchBase" Test "art.Test1928$DoThrowCatchTestExceptionNoRethrow": Running with handler "art.Test1928$ThrowCatchBase" main: public static void art.Test1928.throwCatchTestExceptionNoRethrow() @ line = 149 throws class art.Test1928$TestException: throwCatchTestExceptionNoRethrow Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1928.PrintStack() @ line = 35 public static void art.Test1928.ExceptionEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable,java.lang.reflect.Executable,long) @ line = 59 public static void art.Test1928.throwCatchTestExceptionNoRethrow() @ line = 149 public void art.Test1928$DoThrowCatchTestExceptionNoRethrow.run() @ line = 159 public static void art.Test1928.run() throws java.lang.Exception @ line = 196 Will be caught by: public static void art.Test1928.run() throws java.lang.Exception @ line = 199 -exception is: art.Test1928$TestException: throwCatchTestExceptionNoRethrow - at art.Test1928.throwCatchTestExceptionNoRethrow(Test1928.java:149) - at art.Test1928$DoThrowCatchTestExceptionNoRethrow.run(Test1928.java:159) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) Throwing BaseTestException and catching it! Caught art.Test1928$BaseTestException: "ThrowBaseHandler during throw from public static void art.Test1928.throwCatchTestExceptionNoRethrow() @ line = 149" -art.Test1928$BaseTestException: ThrowBaseHandler during throw from public static void art.Test1928.throwCatchTestExceptionNoRethrow() @ line = 149 - at art.Test1928$ThrowCatchBase.exceptionOccurred(Test1928.java:99) - at art.Test1928.ExceptionEvent(Test1928.java:66) - at art.Test1928.throwCatchTestExceptionNoRethrow(Test1928.java:149) - at art.Test1928$DoThrowCatchTestExceptionNoRethrow.run(Test1928.java:159) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) -Caused by: art.Test1928$TestException: throwCatchTestExceptionNoRethrow - ... 4 more Test "art.Test1928$DoThrowCatchTestExceptionNoRethrow": Caught error art.Test1928$TestException:"throwCatchTestExceptionNoRethrow" with handler "art.Test1928$ThrowCatchBase" -art.Test1928$TestException: throwCatchTestExceptionNoRethrow - at art.Test1928.throwCatchTestExceptionNoRethrow(Test1928.java:149) - at art.Test1928$DoThrowCatchTestExceptionNoRethrow.run(Test1928.java:159) - at art.Test1928.run(Test1928.java:196) - at Main.main(Main.java:19) Test "art.Test1928$DoThrowCatchTestExceptionNoRethrow": Finished running with handler "art.Test1928$ThrowCatchBase" diff --git a/test/1928-exception-event-exception/src/art/StackTrace.java b/test/1928-exception-event-exception/src/art/StackTrace.java index b12c3df66b..2ea2f201e8 100644 --- a/test/1928-exception-event-exception/src/art/StackTrace.java +++ b/test/1928-exception-event-exception/src/art/StackTrace.java @@ -53,7 +53,8 @@ public class StackTrace { // consistent we will suspend for the RI. boolean suspend_thread = !System.getProperty("java.vm.name").equals("Dalvik") && - !thr.equals(Thread.currentThread()); + !thr.equals(Thread.currentThread()) && + !Suspension.isSuspended(thr); if (suspend_thread) { Suspension.suspend(thr); } diff --git a/test/1928-exception-event-exception/src/art/Test1928.java b/test/1928-exception-event-exception/src/art/Test1928.java index aec88a4079..864de8ea4d 100644 --- a/test/1928-exception-event-exception/src/art/Test1928.java +++ b/test/1928-exception-event-exception/src/art/Test1928.java @@ -22,7 +22,7 @@ import java.lang.reflect.Executable; import java.lang.reflect.Method; public class Test1928 { - public static boolean PRINT_FULL_EXCEPTION = true; + public static boolean PRINT_FULL_EXCEPTION = false; public static ExceptionHandler HANDLER = null; public static interface ExceptionHandler { diff --git a/test/1929-exception-catch-exception/expected.txt b/test/1929-exception-catch-exception/expected.txt index 7c23a31439..bc5608ac4e 100644 --- a/test/1929-exception-catch-exception/expected.txt +++ b/test/1929-exception-catch-exception/expected.txt @@ -2,7 +2,7 @@ Test "art.Test1929$DoThrowClass": Running breakpoint with handler "art.Test1929$ main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: doThrow Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929.run() throws java.lang.Exception @ line = 283 @@ -12,7 +12,7 @@ Test "art.Test1929$DoThrowCatchBaseTestException": Running breakpoint with handl main: public static void art.Test1929.throwCatchBaseTestException() @ line = 140 caught class art.Test1929$TestException: throwCatchBaseTestException Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929.throwCatchBaseTestException() @ line = 140 @@ -26,7 +26,7 @@ Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Running breakpoint with main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 @@ -40,7 +40,7 @@ Test "art.Test1929$DoThrowCatchTestException": Running breakpoint with handler " main: public static void art.Test1929.throwCatchTestException() @ line = 207 caught class art.Test1929$TestException: throwCatchTestException Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929.throwCatchTestException() @ line = 207 @@ -54,7 +54,7 @@ Test "art.Test1929$DoThrowCatchTestExceptionTwice": Running breakpoint with hand main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 caught class art.Test1929$TestException: throwCatchTestExceptionTwice Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 @@ -68,7 +68,7 @@ Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Running breakpoint with main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929.run() throws java.lang.Exception @ line = 283 @@ -78,7 +78,7 @@ Test "art.Test1929$DoThrowClass": Running breakpoint with handler "art.Test1929$ main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: doThrow Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929.run() throws java.lang.Exception @ line = 283 @@ -88,7 +88,7 @@ Test "art.Test1929$DoThrowCatchBaseTestException": Running breakpoint with handl main: public static void art.Test1929.throwCatchBaseTestException() @ line = 140 caught class art.Test1929$TestException: throwCatchBaseTestException Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929.throwCatchBaseTestException() @ line = 140 @@ -103,7 +103,7 @@ Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Running breakpoint with main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 @@ -117,7 +117,7 @@ Test "art.Test1929$DoThrowCatchTestException": Running breakpoint with handler " main: public static void art.Test1929.throwCatchTestException() @ line = 207 caught class art.Test1929$TestException: throwCatchTestException Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929.throwCatchTestException() @ line = 207 @@ -132,7 +132,7 @@ Test "art.Test1929$DoThrowCatchTestExceptionTwice": Running breakpoint with hand main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 caught class art.Test1929$TestException: throwCatchTestExceptionTwice Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 @@ -146,7 +146,7 @@ Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Running breakpoint with main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929.run() throws java.lang.Exception @ line = 283 @@ -156,7 +156,7 @@ Test "art.Test1929$DoThrowClass": Running breakpoint with handler "art.Test1929$ main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: doThrow Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929.run() throws java.lang.Exception @ line = 283 @@ -166,7 +166,7 @@ Test "art.Test1929$DoThrowCatchBaseTestException": Running breakpoint with handl main: public static void art.Test1929.throwCatchBaseTestException() @ line = 140 caught class art.Test1929$TestException: throwCatchBaseTestException Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929.throwCatchBaseTestException() @ line = 140 @@ -179,7 +179,7 @@ Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Running breakpoint with main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 @@ -193,7 +193,7 @@ Test "art.Test1929$DoThrowCatchTestException": Running breakpoint with handler " main: public static void art.Test1929.throwCatchTestException() @ line = 207 caught class art.Test1929$TestException: throwCatchTestException Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929.throwCatchTestException() @ line = 207 @@ -206,7 +206,7 @@ Test "art.Test1929$DoThrowCatchTestExceptionTwice": Running breakpoint with hand main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 caught class art.Test1929$TestException: throwCatchTestExceptionTwice Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 @@ -220,7 +220,7 @@ Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Running breakpoint with main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929.run() throws java.lang.Exception @ line = 283 @@ -230,7 +230,7 @@ Test "art.Test1929$DoThrowClass": Running breakpoint with handler "art.Test1929$ main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: doThrow Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929.run() throws java.lang.Exception @ line = 283 @@ -240,7 +240,7 @@ Test "art.Test1929$DoThrowCatchBaseTestException": Running breakpoint with handl main: public static void art.Test1929.throwCatchBaseTestException() @ line = 140 caught class art.Test1929$TestException: throwCatchBaseTestException Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929.throwCatchBaseTestException() @ line = 140 @@ -253,7 +253,7 @@ Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Running breakpoint with main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 @@ -267,7 +267,7 @@ Test "art.Test1929$DoThrowCatchTestException": Running breakpoint with handler " main: public static void art.Test1929.throwCatchTestException() @ line = 207 caught class art.Test1929$TestException: throwCatchTestException Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929.throwCatchTestException() @ line = 207 @@ -280,7 +280,7 @@ Test "art.Test1929$DoThrowCatchTestExceptionTwice": Running breakpoint with hand main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 caught class art.Test1929$TestException: throwCatchTestExceptionTwice Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 @@ -294,7 +294,7 @@ Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Running breakpoint with main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow Current Stack: private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1 - public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 60 + public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61 private static void art.Test1929.PrintStack() @ line = 52 public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65 public static void art.Test1929.run() throws java.lang.Exception @ line = 283 diff --git a/test/1929-exception-catch-exception/src/art/StackTrace.java b/test/1929-exception-catch-exception/src/art/StackTrace.java index b12c3df66b..2ea2f201e8 100644 --- a/test/1929-exception-catch-exception/src/art/StackTrace.java +++ b/test/1929-exception-catch-exception/src/art/StackTrace.java @@ -53,7 +53,8 @@ public class StackTrace { // consistent we will suspend for the RI. boolean suspend_thread = !System.getProperty("java.vm.name").equals("Dalvik") && - !thr.equals(Thread.currentThread()); + !thr.equals(Thread.currentThread()) && + !Suspension.isSuspended(thr); if (suspend_thread) { Suspension.suspend(thr); } diff --git a/test/1937-transform-soft-fail/src/art/Test1937.java b/test/1937-transform-soft-fail/src/art/Test1937.java index 7255a5ef96..19fa24e3f8 100644 --- a/test/1937-transform-soft-fail/src/art/Test1937.java +++ b/test/1937-transform-soft-fail/src/art/Test1937.java @@ -19,6 +19,8 @@ package art; import java.util.Base64; public class Test1937 { + private static final boolean PRINT_MESSAGE = false; + static class Transform { public void sayHi() { // Use lower 'h' to make sure the string will have a different string id @@ -83,7 +85,10 @@ public class Test1937 { try { t.sayHi(); } catch (Throwable e) { - System.out.println("Caught exception " + e.getClass().getName() + ": " + e.getMessage()); + System.out.println("Caught exception " + e.getClass().getName()); + if (PRINT_MESSAGE) { + System.out.println("Message: " + e.getMessage()); + } } } } diff --git a/test/1939-proxy-frames/expected.txt b/test/1939-proxy-frames/expected.txt index a4c97c9bbe..3aafd16a08 100644 --- a/test/1939-proxy-frames/expected.txt +++ b/test/1939-proxy-frames/expected.txt @@ -5,4 +5,4 @@ Running public abstract void art.Test1939$Foo.InterfaceProxyMethod(java.lang.Run Running public abstract void art.Test1939$Foo.InterfaceProxyMethod(java.lang.Runnable) with "GetProxyFrameLocation" on remote thread. "GetProxyFrameLocation" on public abstract void art.Test1939$Foo.InterfaceProxyMethod(java.lang.Runnable) got value: -1 Running public abstract void art.Test1939$Foo.InterfaceProxyMethod(java.lang.Runnable) with "GetProxyFrameMethod" on remote thread. -"GetProxyFrameMethod" on public abstract void art.Test1939$Foo.InterfaceProxyMethod(java.lang.Runnable) got value: public final void $Proxy0.InterfaceProxyMethod(java.lang.Runnable) +"GetProxyFrameMethod" on public abstract void art.Test1939$Foo.InterfaceProxyMethod(java.lang.Runnable) got value: public final void $__PROXY__.InterfaceProxyMethod(java.lang.Runnable) diff --git a/test/1939-proxy-frames/src/art/Test1939.java b/test/1939-proxy-frames/src/art/Test1939.java index 83d0d2ca4b..5e86e54c0d 100644 --- a/test/1939-proxy-frames/src/art/Test1939.java +++ b/test/1939-proxy-frames/src/art/Test1939.java @@ -44,12 +44,22 @@ public class Test1939 { public Object GetVar(Thread t, int depth); } + public static String SafeToString(Object o) { + if (o instanceof Method && Proxy.isProxyClass(((Method)o).getDeclaringClass())) { + // TODO This currently only really works on ART. It would be good if we could make it work for + // the RI as well. + return o.toString().replaceFirst("Proxy[0-9]+", "__PROXY__"); + } else { + return o.toString(); + } + } + public static SafepointFunction NamedGet(final String type, final GetterFunction get) { return new SafepointFunction() { public void invoke(Thread t, Method method, int depth) { try { Object res = get.GetVar(t, depth); - System.out.println(this + " on " + method + " got value: " + res); + System.out.println(this + " on " + method + " got value: " + SafeToString(res)); } catch (Exception e) { System.out.println(this + " on " + method + " failed due to " + e.getMessage()); } diff --git a/test/1944-sudden-exit/check b/test/1944-sudden-exit/check new file mode 100755 index 0000000000..591fbb87ee --- /dev/null +++ b/test/1944-sudden-exit/check @@ -0,0 +1,25 @@ +#!/bin/bash +# +# Copyright (C) 2018 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. + +# The number of paused background threads (and therefore InterruptedExceptions) +# can change so we will just delete their lines from the log. + +# Pure virtual function can be printed because sudden exits are not really +# supported. It is an error message but the test is to make sure that we exit +# with the right exit code. +cat "$2" \ + | sed "/Pure virtual function called!/d" \ + | diff --strip-trailing-cr -q "$1" - >/dev/null diff --git a/test/1944-sudden-exit/expected.txt b/test/1944-sudden-exit/expected.txt new file mode 100644 index 0000000000..4c6eb47fa7 --- /dev/null +++ b/test/1944-sudden-exit/expected.txt @@ -0,0 +1,3 @@ +All threads started +Exiting suddenly +exit status: 12 diff --git a/test/1944-sudden-exit/info.txt b/test/1944-sudden-exit/info.txt new file mode 100644 index 0000000000..d575ce5864 --- /dev/null +++ b/test/1944-sudden-exit/info.txt @@ -0,0 +1,5 @@ +Test to make sure the runtime will not crash if an agent calls exit(3) while +other threads are performing operations. + +In this case we have multiple threads all performing single stepping when we +call exit(3). diff --git a/test/1944-sudden-exit/run b/test/1944-sudden-exit/run new file mode 100755 index 0000000000..eb601fd348 --- /dev/null +++ b/test/1944-sudden-exit/run @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Copyright 2017 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. + +# Ask for stack traces to be dumped to a file rather than to stdout. +./default-run "$@" --jvmti +echo "exit status: " $? diff --git a/runtime/native/java_lang_Void.h b/test/1944-sudden-exit/src/Main.java index 8777d8068c..1644c6ef0c 100644 --- a/runtime/native/java_lang_Void.h +++ b/test/1944-sudden-exit/src/Main.java @@ -14,15 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_NATIVE_JAVA_LANG_VOID_H_ -#define ART_RUNTIME_NATIVE_JAVA_LANG_VOID_H_ - -#include <jni.h> - -namespace art { - -void register_java_lang_Void(JNIEnv* env); - -} // namespace art - -#endif // ART_RUNTIME_NATIVE_JAVA_LANG_VOID_H_ +public class Main { + public static void main(String[] args) throws Exception { + art.Test1944.run(); + } +} diff --git a/test/1944-sudden-exit/src/art/Test1944.java b/test/1944-sudden-exit/src/art/Test1944.java new file mode 100644 index 0000000000..36cbb2b390 --- /dev/null +++ b/test/1944-sudden-exit/src/art/Test1944.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +import java.util.Arrays; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.util.concurrent.Semaphore; + +public class Test1944 { + // Just calculate fib forever. + public static void fib(Semaphore started) { + started.release(); + long a = 1; + long b = 1; + while (true) { + long c = a + b; + a = b; + b = c; + } + } + + // Don't bother actually doing anything. + public static void notifySingleStep(Thread thr, Executable e, long loc) { } + + public static native void exitNow(); + + private static int num_threads = 10; + + public static void run() throws Exception { + final Semaphore started = new Semaphore(-(num_threads - 1)); + + Trace.enableSingleStepTracing(Test1944.class, + Test1944.class.getDeclaredMethod( + "notifySingleStep", Thread.class, Executable.class, Long.TYPE), + null); + + Thread[] threads = new Thread[num_threads]; + for (int i = 0; i < num_threads; i++) { + threads[i] = new Thread(() -> { fib(started); }); + // Make half daemons. + threads[i].setDaemon(i % 2 == 0); + threads[i].start(); + } + // Wait for all threads to start. + started.acquire(); + System.out.println("All threads started"); + // sleep a little + Thread.sleep(10); + // Die. + System.out.println("Exiting suddenly"); + exitNow(); + System.out.println("FAILED: Should not reach here!"); + } +} diff --git a/test/1944-sudden-exit/src/art/Trace.java b/test/1944-sudden-exit/src/art/Trace.java new file mode 100644 index 0000000000..8999bb1368 --- /dev/null +++ b/test/1944-sudden-exit/src/art/Trace.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class Trace { + public static native void enableTracing(Class<?> methodClass, + Method entryMethod, + Method exitMethod, + Method fieldAccess, + Method fieldModify, + Method singleStep, + Thread thr); + public static native void disableTracing(Thread thr); + + public static void enableFieldTracing(Class<?> methodClass, + Method fieldAccess, + Method fieldModify, + Thread thr) { + enableTracing(methodClass, null, null, fieldAccess, fieldModify, null, thr); + } + + public static void enableMethodTracing(Class<?> methodClass, + Method entryMethod, + Method exitMethod, + Thread thr) { + enableTracing(methodClass, entryMethod, exitMethod, null, null, null, thr); + } + + public static void enableSingleStepTracing(Class<?> methodClass, + Method singleStep, + Thread thr) { + enableTracing(methodClass, null, null, null, null, singleStep, thr); + } + + public static native void watchFieldAccess(Field f); + public static native void watchFieldModification(Field f); + public static native void watchAllFieldAccesses(); + public static native void watchAllFieldModifications(); + + // the names, arguments, and even line numbers of these functions are embedded in the tests so we + // need to add to the bottom and not modify old ones to maintain compat. + public static native void enableTracing2(Class<?> methodClass, + Method entryMethod, + Method exitMethod, + Method fieldAccess, + Method fieldModify, + Method singleStep, + Method ThreadStart, + Method ThreadEnd, + Thread thr); +} diff --git a/test/983-source-transform-verify/source_transform.h b/test/1944-sudden-exit/sudden_exit.cc index db9415aec1..e0a076efac 100644 --- a/test/983-source-transform-verify/source_transform.h +++ b/test/1944-sudden-exit/sudden_exit.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 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. @@ -14,17 +14,19 @@ * limitations under the License. */ -#ifndef ART_TEST_983_SOURCE_TRANSFORM_VERIFY_SOURCE_TRANSFORM_H_ -#define ART_TEST_983_SOURCE_TRANSFORM_VERIFY_SOURCE_TRANSFORM_H_ - -#include <jni.h> +#include <stdlib.h> +#include "jni.h" namespace art { -namespace Test983SourceTransformVerify { +namespace Test1944SuddenExit { + +extern "C" JNIEXPORT void JNICALL Java_art_Test1944_exitNow(JNIEnv*, jclass) + __attribute__((noreturn)); -jint OnLoad(JavaVM* vm, char* options, void* reserved); +extern "C" JNIEXPORT void JNICALL Java_art_Test1944_exitNow(JNIEnv*, jclass) { + exit(12); +} -} // namespace Test983SourceTransformVerify +} // namespace Test1944SuddenExit } // namespace art -#endif // ART_TEST_983_SOURCE_TRANSFORM_VERIFY_SOURCE_TRANSFORM_H_ diff --git a/test/670-bitstring-type-check/build b/test/670-bitstring-type-check/build new file mode 100644 index 0000000000..38307f2c0f --- /dev/null +++ b/test/670-bitstring-type-check/build @@ -0,0 +1,216 @@ +#!/bin/bash +# +# Copyright (C) 2018 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. + +# Stop if something fails. +set -e + +# Write out the source file. + +mkdir src +cat >src/Main.java <<EOF +/* + * Copyright (C) 2018 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. + */ + +EOF + +for i in {0..8192}; do echo "class Level1Class$i { }" >>src/Main.java; done +for i in {0..1024}; do echo "class Level2Class$i extends Level1Class0 { }" >>src/Main.java; done + +cat >>src/Main.java <<EOF +class Level3Class0 extends Level2Class0 { } +class Level4Class0 extends Level3Class0 { } +class Level5Class0 extends Level4Class0 { } +class Level6Class0 extends Level5Class0 { } +class Level7Class0 extends Level6Class0 { } +class Level8Class0 extends Level7Class0 { } +class Level9Class0 extends Level8Class0 { } + +public class Main { + public static void main(String[] args) throws Exception { + // 8193 classes at level 1 make sure we shall have an overflow if there are 13 or + // less bits for the level 1 character. 1025 classes at level 2 similarly guarantees + // an overflow if the number of bits for level 2 character is 10 or less. To test + // type checks also for the depth overflow, we provide a hierarchy 9 levels deep. + + // Make sure the bitstrings are initialized. + for (int i = 0; i <= 8192; ++i) { + Class.forName("Level1Class" + i).newInstance(); + } + for (int i = 0; i <= 1024; ++i) { + Class.forName("Level2Class" + i).newInstance(); + } + + // Note: Using a different class for tests so that verification of Main.main() does + // not try to resolve classes used by the tests. This guarantees uninitialized type + // check bitstrings when we enter Main.main() and start initializing them above. + Helper.testInstanceOf(); + Helper.testCheckCast(); + } +} + +class Helper { + public static void testInstanceOf() throws Exception { + for (int i = 1; i <= 9; ++i) { + Object o = createInstance("Level" + i + "Class0"); + assertTrue(o instanceof Level1Class0); + if (o instanceof Level2Class0) { + assertFalse(i < 2); + } else { + assertTrue(i < 2); + } + if (o instanceof Level3Class0) { + assertFalse(i < 3); + } else { + assertTrue(i < 3); + } + if (o instanceof Level4Class0) { + assertFalse(i < 4); + } else { + assertTrue(i < 4); + } + if (o instanceof Level5Class0) { + assertFalse(i < 5); + } else { + assertTrue(i < 5); + } + if (o instanceof Level6Class0) { + assertFalse(i < 6); + } else { + assertTrue(i < 6); + } + if (o instanceof Level7Class0) { + assertFalse(i < 7); + } else { + assertTrue(i < 7); + } + if (o instanceof Level8Class0) { + assertFalse(i < 8); + } else { + assertTrue(i < 8); + } + if (o instanceof Level9Class0) { + assertFalse(i < 9); + } else { + assertTrue(i < 9); + } + } + + assertTrue(createInstance("Level1Class8192") instanceof Level1Class8192); + assertFalse(createInstance("Level1Class8192") instanceof Level1Class0); + assertTrue(createInstance("Level2Class1024") instanceof Level2Class1024); + assertTrue(createInstance("Level2Class1024") instanceof Level1Class0); + assertFalse(createInstance("Level2Class1024") instanceof Level2Class0); + } + + public static void testCheckCast() throws Exception { + for (int i = 1; i <= 9; ++i) { + Object o = createInstance("Level" + i + "Class0"); + Level1Class0 l1c0 = (Level1Class0) o; + try { + Level2Class0 l2c0 = (Level2Class0) o; + assertFalse(i < 2); + } catch (ClassCastException cce) { + assertTrue(i < 2); + } + try { + Level3Class0 l3c0 = (Level3Class0) o; + assertFalse(i < 3); + } catch (ClassCastException cce) { + assertTrue(i < 3); + } + try { + Level4Class0 l4c0 = (Level4Class0) o; + assertFalse(i < 4); + } catch (ClassCastException cce) { + assertTrue(i < 4); + } + try { + Level5Class0 l5c0 = (Level5Class0) o; + assertFalse(i < 5); + } catch (ClassCastException cce) { + assertTrue(i < 5); + } + try { + Level6Class0 l6c0 = (Level6Class0) o; + assertFalse(i < 6); + } catch (ClassCastException cce) { + assertTrue(i < 6); + } + try { + Level7Class0 l7c0 = (Level7Class0) o; + assertFalse(i < 7); + } catch (ClassCastException cce) { + assertTrue(i < 7); + } + try { + Level8Class0 l8c0 = (Level8Class0) o; + assertFalse(i < 8); + } catch (ClassCastException cce) { + assertTrue(i < 8); + } + try { + Level9Class0 l9c0 = (Level9Class0) o; + assertFalse(i < 9); + } catch (ClassCastException cce) { + assertTrue(i < 9); + } + } + + Level1Class8192 l1c8192 = (Level1Class8192) createInstance("Level1Class8192"); + try { + Level1Class0 l1c0 = (Level1Class0) createInstance("Level1Class8192"); + throw new AssertionError("Unexpected"); + } catch (ClassCastException expected) {} + Level2Class1024 l2c1024 = (Level2Class1024) createInstance("Level2Class1024"); + Level1Class0 l1c0 = (Level1Class0) createInstance("Level2Class1024"); + try { + Level2Class0 l2c0 = (Level2Class0) createInstance("Level2Class1024"); + throw new AssertionError("Unexpected"); + } catch (ClassCastException expected) {} + } + + public static Object createInstance(String className) throws Exception { + return Class.forName(className).newInstance(); + } + + public static void assertTrue(boolean value) throws Exception { + if (!value) { + throw new AssertionError(); + } + } + + public static void assertFalse(boolean value) throws Exception { + if (value) { + throw new AssertionError(); + } + } +} +EOF + +./default-build "$@" diff --git a/test/670-bitstring-type-check/expected.txt b/test/670-bitstring-type-check/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/670-bitstring-type-check/expected.txt diff --git a/test/670-bitstring-type-check/info.txt b/test/670-bitstring-type-check/info.txt new file mode 100644 index 0000000000..a34ba86171 --- /dev/null +++ b/test/670-bitstring-type-check/info.txt @@ -0,0 +1 @@ +Tests for the bitstring type checks. diff --git a/test/712-varhandle-invocations/build b/test/712-varhandle-invocations/build new file mode 100755 index 0000000000..253765be91 --- /dev/null +++ b/test/712-varhandle-invocations/build @@ -0,0 +1,39 @@ +#!/bin/bash +# +# Copyright 2018 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. + +# Make us exit on a failure +set -e + +# Set variables for source directories. Using src-art so we use +# VarHandles in the bootclasspath and can compile with the Java 8 +# compiler. +MANUAL_SRC=src +GENERATED_SRC=src2 + +# Build the Java files +mkdir -p src2 + +# Collate list of manual test classes +MANUAL_TESTS=$(cd "${MANUAL_SRC}" && find . -name 'Var*Tests.java' | sed -e 's@.*\(Var.*Tests\).*@\1@g' | sort) + +# Generate tests and Main that covers both the generated tests and manual tests +python3 ./util-src/generate_java.py "${GENERATED_SRC}" ${MANUAL_TESTS} + +# Desugar is not happy with our Java 9 byte code, it shouldn't be necessary here anyway. +export USE_DESUGAR=false + +# Invoke default build with increased heap size for dx +./default-build "$@" --experimental var-handles --dx-vm-option -JXmx384m diff --git a/test/712-varhandle-invocations/expected.txt b/test/712-varhandle-invocations/expected.txt new file mode 100644 index 0000000000..af921901f8 --- /dev/null +++ b/test/712-varhandle-invocations/expected.txt @@ -0,0 +1,3183 @@ +FieldGetBoolean...OK +FieldGetByte...OK +FieldGetShort...OK +FieldGetChar...OK +FieldGetInt...OK +FieldGetLong...OK +FieldGetFloat...OK +FieldGetDouble...OK +FieldSetBoolean...OK +FieldSetByte...OK +FieldSetShort...OK +FieldSetChar...OK +FieldSetInt...OK +FieldSetLong...OK +FieldSetFloat...OK +FieldSetDouble...OK +FieldGetVolatileBoolean...OK +FieldGetVolatileByte...OK +FieldGetVolatileShort...OK +FieldGetVolatileChar...OK +FieldGetVolatileInt...OK +FieldGetVolatileLong...OK +FieldGetVolatileFloat...OK +FieldGetVolatileDouble...OK +FieldSetVolatileBoolean...OK +FieldSetVolatileByte...OK +FieldSetVolatileShort...OK +FieldSetVolatileChar...OK +FieldSetVolatileInt...OK +FieldSetVolatileLong...OK +FieldSetVolatileFloat...OK +FieldSetVolatileDouble...OK +FieldGetAcquireBoolean...OK +FieldGetAcquireByte...OK +FieldGetAcquireShort...OK +FieldGetAcquireChar...OK +FieldGetAcquireInt...OK +FieldGetAcquireLong...OK +FieldGetAcquireFloat...OK +FieldGetAcquireDouble...OK +FieldSetReleaseBoolean...OK +FieldSetReleaseByte...OK +FieldSetReleaseShort...OK +FieldSetReleaseChar...OK +FieldSetReleaseInt...OK +FieldSetReleaseLong...OK +FieldSetReleaseFloat...OK +FieldSetReleaseDouble...OK +FieldGetOpaqueBoolean...OK +FieldGetOpaqueByte...OK +FieldGetOpaqueShort...OK +FieldGetOpaqueChar...OK +FieldGetOpaqueInt...OK +FieldGetOpaqueLong...OK +FieldGetOpaqueFloat...OK +FieldGetOpaqueDouble...OK +FieldSetOpaqueBoolean...OK +FieldSetOpaqueByte...OK +FieldSetOpaqueShort...OK +FieldSetOpaqueChar...OK +FieldSetOpaqueInt...OK +FieldSetOpaqueLong...OK +FieldSetOpaqueFloat...OK +FieldSetOpaqueDouble...OK +FieldCompareAndSetBoolean...OK +FieldCompareAndSetByte...OK +FieldCompareAndSetShort...OK +FieldCompareAndSetChar...OK +FieldCompareAndSetInt...OK +FieldCompareAndSetLong...OK +FieldCompareAndSetFloat...OK +FieldCompareAndSetDouble...OK +FieldCompareAndExchangeBoolean...OK +FieldCompareAndExchangeByte...OK +FieldCompareAndExchangeShort...OK +FieldCompareAndExchangeChar...OK +FieldCompareAndExchangeInt...OK +FieldCompareAndExchangeLong...OK +FieldCompareAndExchangeFloat...OK +FieldCompareAndExchangeDouble...OK +FieldCompareAndExchangeAcquireBoolean...OK +FieldCompareAndExchangeAcquireByte...OK +FieldCompareAndExchangeAcquireShort...OK +FieldCompareAndExchangeAcquireChar...OK +FieldCompareAndExchangeAcquireInt...OK +FieldCompareAndExchangeAcquireLong...OK +FieldCompareAndExchangeAcquireFloat...OK +FieldCompareAndExchangeAcquireDouble...OK +FieldCompareAndExchangeReleaseBoolean...OK +FieldCompareAndExchangeReleaseByte...OK +FieldCompareAndExchangeReleaseShort...OK +FieldCompareAndExchangeReleaseChar...OK +FieldCompareAndExchangeReleaseInt...OK +FieldCompareAndExchangeReleaseLong...OK +FieldCompareAndExchangeReleaseFloat...OK +FieldCompareAndExchangeReleaseDouble...OK +FieldWeakCompareAndSetPlainBoolean...OK +FieldWeakCompareAndSetPlainByte...OK +FieldWeakCompareAndSetPlainShort...OK +FieldWeakCompareAndSetPlainChar...OK +FieldWeakCompareAndSetPlainInt...OK +FieldWeakCompareAndSetPlainLong...OK +FieldWeakCompareAndSetPlainFloat...OK +FieldWeakCompareAndSetPlainDouble...OK +FieldWeakCompareAndSetBoolean...OK +FieldWeakCompareAndSetByte...OK +FieldWeakCompareAndSetShort...OK +FieldWeakCompareAndSetChar...OK +FieldWeakCompareAndSetInt...OK +FieldWeakCompareAndSetLong...OK +FieldWeakCompareAndSetFloat...OK +FieldWeakCompareAndSetDouble...OK +FieldWeakCompareAndSetAcquireBoolean...OK +FieldWeakCompareAndSetAcquireByte...OK +FieldWeakCompareAndSetAcquireShort...OK +FieldWeakCompareAndSetAcquireChar...OK +FieldWeakCompareAndSetAcquireInt...OK +FieldWeakCompareAndSetAcquireLong...OK +FieldWeakCompareAndSetAcquireFloat...OK +FieldWeakCompareAndSetAcquireDouble...OK +FieldWeakCompareAndSetReleaseBoolean...OK +FieldWeakCompareAndSetReleaseByte...OK +FieldWeakCompareAndSetReleaseShort...OK +FieldWeakCompareAndSetReleaseChar...OK +FieldWeakCompareAndSetReleaseInt...OK +FieldWeakCompareAndSetReleaseLong...OK +FieldWeakCompareAndSetReleaseFloat...OK +FieldWeakCompareAndSetReleaseDouble...OK +FieldGetAndSetBoolean...OK +FieldGetAndSetByte...OK +FieldGetAndSetShort...OK +FieldGetAndSetChar...OK +FieldGetAndSetInt...OK +FieldGetAndSetLong...OK +FieldGetAndSetFloat...OK +FieldGetAndSetDouble...OK +FieldGetAndSetAcquireBoolean...OK +FieldGetAndSetAcquireByte...OK +FieldGetAndSetAcquireShort...OK +FieldGetAndSetAcquireChar...OK +FieldGetAndSetAcquireInt...OK +FieldGetAndSetAcquireLong...OK +FieldGetAndSetAcquireFloat...OK +FieldGetAndSetAcquireDouble...OK +FieldGetAndSetReleaseBoolean...OK +FieldGetAndSetReleaseByte...OK +FieldGetAndSetReleaseShort...OK +FieldGetAndSetReleaseChar...OK +FieldGetAndSetReleaseInt...OK +FieldGetAndSetReleaseLong...OK +FieldGetAndSetReleaseFloat...OK +FieldGetAndSetReleaseDouble...OK +FieldGetAndAddBoolean...OK +FieldGetAndAddByte...OK +FieldGetAndAddShort...OK +FieldGetAndAddChar...OK +FieldGetAndAddInt...OK +FieldGetAndAddLong...OK +FieldGetAndAddFloat...OK +FieldGetAndAddDouble...OK +FieldGetAndAddAcquireBoolean...OK +FieldGetAndAddAcquireByte...OK +FieldGetAndAddAcquireShort...OK +FieldGetAndAddAcquireChar...OK +FieldGetAndAddAcquireInt...OK +FieldGetAndAddAcquireLong...OK +FieldGetAndAddAcquireFloat...OK +FieldGetAndAddAcquireDouble...OK +FieldGetAndAddReleaseBoolean...OK +FieldGetAndAddReleaseByte...OK +FieldGetAndAddReleaseShort...OK +FieldGetAndAddReleaseChar...OK +FieldGetAndAddReleaseInt...OK +FieldGetAndAddReleaseLong...OK +FieldGetAndAddReleaseFloat...OK +FieldGetAndAddReleaseDouble...OK +FieldGetAndBitwiseOrBoolean...OK +FieldGetAndBitwiseOrByte...OK +FieldGetAndBitwiseOrShort...OK +FieldGetAndBitwiseOrChar...OK +FieldGetAndBitwiseOrInt...OK +FieldGetAndBitwiseOrLong...OK +FieldGetAndBitwiseOrFloat...OK +FieldGetAndBitwiseOrDouble...OK +FieldGetAndBitwiseOrReleaseBoolean...OK +FieldGetAndBitwiseOrReleaseByte...OK +FieldGetAndBitwiseOrReleaseShort...OK +FieldGetAndBitwiseOrReleaseChar...OK +FieldGetAndBitwiseOrReleaseInt...OK +FieldGetAndBitwiseOrReleaseLong...OK +FieldGetAndBitwiseOrReleaseFloat...OK +FieldGetAndBitwiseOrReleaseDouble...OK +FieldGetAndBitwiseOrAcquireBoolean...OK +FieldGetAndBitwiseOrAcquireByte...OK +FieldGetAndBitwiseOrAcquireShort...OK +FieldGetAndBitwiseOrAcquireChar...OK +FieldGetAndBitwiseOrAcquireInt...OK +FieldGetAndBitwiseOrAcquireLong...OK +FieldGetAndBitwiseOrAcquireFloat...OK +FieldGetAndBitwiseOrAcquireDouble...OK +FieldGetAndBitwiseAndBoolean...OK +FieldGetAndBitwiseAndByte...OK +FieldGetAndBitwiseAndShort...OK +FieldGetAndBitwiseAndChar...OK +FieldGetAndBitwiseAndInt...OK +FieldGetAndBitwiseAndLong...OK +FieldGetAndBitwiseAndFloat...OK +FieldGetAndBitwiseAndDouble...OK +FieldGetAndBitwiseAndReleaseBoolean...OK +FieldGetAndBitwiseAndReleaseByte...OK +FieldGetAndBitwiseAndReleaseShort...OK +FieldGetAndBitwiseAndReleaseChar...OK +FieldGetAndBitwiseAndReleaseInt...OK +FieldGetAndBitwiseAndReleaseLong...OK +FieldGetAndBitwiseAndReleaseFloat...OK +FieldGetAndBitwiseAndReleaseDouble...OK +FieldGetAndBitwiseAndAcquireBoolean...OK +FieldGetAndBitwiseAndAcquireByte...OK +FieldGetAndBitwiseAndAcquireShort...OK +FieldGetAndBitwiseAndAcquireChar...OK +FieldGetAndBitwiseAndAcquireInt...OK +FieldGetAndBitwiseAndAcquireLong...OK +FieldGetAndBitwiseAndAcquireFloat...OK +FieldGetAndBitwiseAndAcquireDouble...OK +FieldGetAndBitwiseXorBoolean...OK +FieldGetAndBitwiseXorByte...OK +FieldGetAndBitwiseXorShort...OK +FieldGetAndBitwiseXorChar...OK +FieldGetAndBitwiseXorInt...OK +FieldGetAndBitwiseXorLong...OK +FieldGetAndBitwiseXorFloat...OK +FieldGetAndBitwiseXorDouble...OK +FieldGetAndBitwiseXorReleaseBoolean...OK +FieldGetAndBitwiseXorReleaseByte...OK +FieldGetAndBitwiseXorReleaseShort...OK +FieldGetAndBitwiseXorReleaseChar...OK +FieldGetAndBitwiseXorReleaseInt...OK +FieldGetAndBitwiseXorReleaseLong...OK +FieldGetAndBitwiseXorReleaseFloat...OK +FieldGetAndBitwiseXorReleaseDouble...OK +FieldGetAndBitwiseXorAcquireBoolean...OK +FieldGetAndBitwiseXorAcquireByte...OK +FieldGetAndBitwiseXorAcquireShort...OK +FieldGetAndBitwiseXorAcquireChar...OK +FieldGetAndBitwiseXorAcquireInt...OK +FieldGetAndBitwiseXorAcquireLong...OK +FieldGetAndBitwiseXorAcquireFloat...OK +FieldGetAndBitwiseXorAcquireDouble...OK +FinalFieldGetBoolean...OK +FinalFieldGetByte...OK +FinalFieldGetShort...OK +FinalFieldGetChar...OK +FinalFieldGetInt...OK +FinalFieldGetLong...OK +FinalFieldGetFloat...OK +FinalFieldGetDouble...OK +FinalFieldSetBoolean...OK +FinalFieldSetByte...OK +FinalFieldSetShort...OK +FinalFieldSetChar...OK +FinalFieldSetInt...OK +FinalFieldSetLong...OK +FinalFieldSetFloat...OK +FinalFieldSetDouble...OK +FinalFieldGetVolatileBoolean...OK +FinalFieldGetVolatileByte...OK +FinalFieldGetVolatileShort...OK +FinalFieldGetVolatileChar...OK +FinalFieldGetVolatileInt...OK +FinalFieldGetVolatileLong...OK +FinalFieldGetVolatileFloat...OK +FinalFieldGetVolatileDouble...OK +FinalFieldSetVolatileBoolean...OK +FinalFieldSetVolatileByte...OK +FinalFieldSetVolatileShort...OK +FinalFieldSetVolatileChar...OK +FinalFieldSetVolatileInt...OK +FinalFieldSetVolatileLong...OK +FinalFieldSetVolatileFloat...OK +FinalFieldSetVolatileDouble...OK +FinalFieldGetAcquireBoolean...OK +FinalFieldGetAcquireByte...OK +FinalFieldGetAcquireShort...OK +FinalFieldGetAcquireChar...OK +FinalFieldGetAcquireInt...OK +FinalFieldGetAcquireLong...OK +FinalFieldGetAcquireFloat...OK +FinalFieldGetAcquireDouble...OK +FinalFieldSetReleaseBoolean...OK +FinalFieldSetReleaseByte...OK +FinalFieldSetReleaseShort...OK +FinalFieldSetReleaseChar...OK +FinalFieldSetReleaseInt...OK +FinalFieldSetReleaseLong...OK +FinalFieldSetReleaseFloat...OK +FinalFieldSetReleaseDouble...OK +FinalFieldGetOpaqueBoolean...OK +FinalFieldGetOpaqueByte...OK +FinalFieldGetOpaqueShort...OK +FinalFieldGetOpaqueChar...OK +FinalFieldGetOpaqueInt...OK +FinalFieldGetOpaqueLong...OK +FinalFieldGetOpaqueFloat...OK +FinalFieldGetOpaqueDouble...OK +FinalFieldSetOpaqueBoolean...OK +FinalFieldSetOpaqueByte...OK +FinalFieldSetOpaqueShort...OK +FinalFieldSetOpaqueChar...OK +FinalFieldSetOpaqueInt...OK +FinalFieldSetOpaqueLong...OK +FinalFieldSetOpaqueFloat...OK +FinalFieldSetOpaqueDouble...OK +FinalFieldCompareAndSetBoolean...OK +FinalFieldCompareAndSetByte...OK +FinalFieldCompareAndSetShort...OK +FinalFieldCompareAndSetChar...OK +FinalFieldCompareAndSetInt...OK +FinalFieldCompareAndSetLong...OK +FinalFieldCompareAndSetFloat...OK +FinalFieldCompareAndSetDouble...OK +FinalFieldCompareAndExchangeBoolean...OK +FinalFieldCompareAndExchangeByte...OK +FinalFieldCompareAndExchangeShort...OK +FinalFieldCompareAndExchangeChar...OK +FinalFieldCompareAndExchangeInt...OK +FinalFieldCompareAndExchangeLong...OK +FinalFieldCompareAndExchangeFloat...OK +FinalFieldCompareAndExchangeDouble...OK +FinalFieldCompareAndExchangeAcquireBoolean...OK +FinalFieldCompareAndExchangeAcquireByte...OK +FinalFieldCompareAndExchangeAcquireShort...OK +FinalFieldCompareAndExchangeAcquireChar...OK +FinalFieldCompareAndExchangeAcquireInt...OK +FinalFieldCompareAndExchangeAcquireLong...OK +FinalFieldCompareAndExchangeAcquireFloat...OK +FinalFieldCompareAndExchangeAcquireDouble...OK +FinalFieldCompareAndExchangeReleaseBoolean...OK +FinalFieldCompareAndExchangeReleaseByte...OK +FinalFieldCompareAndExchangeReleaseShort...OK +FinalFieldCompareAndExchangeReleaseChar...OK +FinalFieldCompareAndExchangeReleaseInt...OK +FinalFieldCompareAndExchangeReleaseLong...OK +FinalFieldCompareAndExchangeReleaseFloat...OK +FinalFieldCompareAndExchangeReleaseDouble...OK +FinalFieldWeakCompareAndSetPlainBoolean...OK +FinalFieldWeakCompareAndSetPlainByte...OK +FinalFieldWeakCompareAndSetPlainShort...OK +FinalFieldWeakCompareAndSetPlainChar...OK +FinalFieldWeakCompareAndSetPlainInt...OK +FinalFieldWeakCompareAndSetPlainLong...OK +FinalFieldWeakCompareAndSetPlainFloat...OK +FinalFieldWeakCompareAndSetPlainDouble...OK +FinalFieldWeakCompareAndSetBoolean...OK +FinalFieldWeakCompareAndSetByte...OK +FinalFieldWeakCompareAndSetShort...OK +FinalFieldWeakCompareAndSetChar...OK +FinalFieldWeakCompareAndSetInt...OK +FinalFieldWeakCompareAndSetLong...OK +FinalFieldWeakCompareAndSetFloat...OK +FinalFieldWeakCompareAndSetDouble...OK +FinalFieldWeakCompareAndSetAcquireBoolean...OK +FinalFieldWeakCompareAndSetAcquireByte...OK +FinalFieldWeakCompareAndSetAcquireShort...OK +FinalFieldWeakCompareAndSetAcquireChar...OK +FinalFieldWeakCompareAndSetAcquireInt...OK +FinalFieldWeakCompareAndSetAcquireLong...OK +FinalFieldWeakCompareAndSetAcquireFloat...OK +FinalFieldWeakCompareAndSetAcquireDouble...OK +FinalFieldWeakCompareAndSetReleaseBoolean...OK +FinalFieldWeakCompareAndSetReleaseByte...OK +FinalFieldWeakCompareAndSetReleaseShort...OK +FinalFieldWeakCompareAndSetReleaseChar...OK +FinalFieldWeakCompareAndSetReleaseInt...OK +FinalFieldWeakCompareAndSetReleaseLong...OK +FinalFieldWeakCompareAndSetReleaseFloat...OK +FinalFieldWeakCompareAndSetReleaseDouble...OK +FinalFieldGetAndSetBoolean...OK +FinalFieldGetAndSetByte...OK +FinalFieldGetAndSetShort...OK +FinalFieldGetAndSetChar...OK +FinalFieldGetAndSetInt...OK +FinalFieldGetAndSetLong...OK +FinalFieldGetAndSetFloat...OK +FinalFieldGetAndSetDouble...OK +FinalFieldGetAndSetAcquireBoolean...OK +FinalFieldGetAndSetAcquireByte...OK +FinalFieldGetAndSetAcquireShort...OK +FinalFieldGetAndSetAcquireChar...OK +FinalFieldGetAndSetAcquireInt...OK +FinalFieldGetAndSetAcquireLong...OK +FinalFieldGetAndSetAcquireFloat...OK +FinalFieldGetAndSetAcquireDouble...OK +FinalFieldGetAndSetReleaseBoolean...OK +FinalFieldGetAndSetReleaseByte...OK +FinalFieldGetAndSetReleaseShort...OK +FinalFieldGetAndSetReleaseChar...OK +FinalFieldGetAndSetReleaseInt...OK +FinalFieldGetAndSetReleaseLong...OK +FinalFieldGetAndSetReleaseFloat...OK +FinalFieldGetAndSetReleaseDouble...OK +FinalFieldGetAndAddBoolean...OK +FinalFieldGetAndAddByte...OK +FinalFieldGetAndAddShort...OK +FinalFieldGetAndAddChar...OK +FinalFieldGetAndAddInt...OK +FinalFieldGetAndAddLong...OK +FinalFieldGetAndAddFloat...OK +FinalFieldGetAndAddDouble...OK +FinalFieldGetAndAddAcquireBoolean...OK +FinalFieldGetAndAddAcquireByte...OK +FinalFieldGetAndAddAcquireShort...OK +FinalFieldGetAndAddAcquireChar...OK +FinalFieldGetAndAddAcquireInt...OK +FinalFieldGetAndAddAcquireLong...OK +FinalFieldGetAndAddAcquireFloat...OK +FinalFieldGetAndAddAcquireDouble...OK +FinalFieldGetAndAddReleaseBoolean...OK +FinalFieldGetAndAddReleaseByte...OK +FinalFieldGetAndAddReleaseShort...OK +FinalFieldGetAndAddReleaseChar...OK +FinalFieldGetAndAddReleaseInt...OK +FinalFieldGetAndAddReleaseLong...OK +FinalFieldGetAndAddReleaseFloat...OK +FinalFieldGetAndAddReleaseDouble...OK +FinalFieldGetAndBitwiseOrBoolean...OK +FinalFieldGetAndBitwiseOrByte...OK +FinalFieldGetAndBitwiseOrShort...OK +FinalFieldGetAndBitwiseOrChar...OK +FinalFieldGetAndBitwiseOrInt...OK +FinalFieldGetAndBitwiseOrLong...OK +FinalFieldGetAndBitwiseOrFloat...OK +FinalFieldGetAndBitwiseOrDouble...OK +FinalFieldGetAndBitwiseOrReleaseBoolean...OK +FinalFieldGetAndBitwiseOrReleaseByte...OK +FinalFieldGetAndBitwiseOrReleaseShort...OK +FinalFieldGetAndBitwiseOrReleaseChar...OK +FinalFieldGetAndBitwiseOrReleaseInt...OK +FinalFieldGetAndBitwiseOrReleaseLong...OK +FinalFieldGetAndBitwiseOrReleaseFloat...OK +FinalFieldGetAndBitwiseOrReleaseDouble...OK +FinalFieldGetAndBitwiseOrAcquireBoolean...OK +FinalFieldGetAndBitwiseOrAcquireByte...OK +FinalFieldGetAndBitwiseOrAcquireShort...OK +FinalFieldGetAndBitwiseOrAcquireChar...OK +FinalFieldGetAndBitwiseOrAcquireInt...OK +FinalFieldGetAndBitwiseOrAcquireLong...OK +FinalFieldGetAndBitwiseOrAcquireFloat...OK +FinalFieldGetAndBitwiseOrAcquireDouble...OK +FinalFieldGetAndBitwiseAndBoolean...OK +FinalFieldGetAndBitwiseAndByte...OK +FinalFieldGetAndBitwiseAndShort...OK +FinalFieldGetAndBitwiseAndChar...OK +FinalFieldGetAndBitwiseAndInt...OK +FinalFieldGetAndBitwiseAndLong...OK +FinalFieldGetAndBitwiseAndFloat...OK +FinalFieldGetAndBitwiseAndDouble...OK +FinalFieldGetAndBitwiseAndReleaseBoolean...OK +FinalFieldGetAndBitwiseAndReleaseByte...OK +FinalFieldGetAndBitwiseAndReleaseShort...OK +FinalFieldGetAndBitwiseAndReleaseChar...OK +FinalFieldGetAndBitwiseAndReleaseInt...OK +FinalFieldGetAndBitwiseAndReleaseLong...OK +FinalFieldGetAndBitwiseAndReleaseFloat...OK +FinalFieldGetAndBitwiseAndReleaseDouble...OK +FinalFieldGetAndBitwiseAndAcquireBoolean...OK +FinalFieldGetAndBitwiseAndAcquireByte...OK +FinalFieldGetAndBitwiseAndAcquireShort...OK +FinalFieldGetAndBitwiseAndAcquireChar...OK +FinalFieldGetAndBitwiseAndAcquireInt...OK +FinalFieldGetAndBitwiseAndAcquireLong...OK +FinalFieldGetAndBitwiseAndAcquireFloat...OK +FinalFieldGetAndBitwiseAndAcquireDouble...OK +FinalFieldGetAndBitwiseXorBoolean...OK +FinalFieldGetAndBitwiseXorByte...OK +FinalFieldGetAndBitwiseXorShort...OK +FinalFieldGetAndBitwiseXorChar...OK +FinalFieldGetAndBitwiseXorInt...OK +FinalFieldGetAndBitwiseXorLong...OK +FinalFieldGetAndBitwiseXorFloat...OK +FinalFieldGetAndBitwiseXorDouble...OK +FinalFieldGetAndBitwiseXorReleaseBoolean...OK +FinalFieldGetAndBitwiseXorReleaseByte...OK +FinalFieldGetAndBitwiseXorReleaseShort...OK +FinalFieldGetAndBitwiseXorReleaseChar...OK +FinalFieldGetAndBitwiseXorReleaseInt...OK +FinalFieldGetAndBitwiseXorReleaseLong...OK +FinalFieldGetAndBitwiseXorReleaseFloat...OK +FinalFieldGetAndBitwiseXorReleaseDouble...OK +FinalFieldGetAndBitwiseXorAcquireBoolean...OK +FinalFieldGetAndBitwiseXorAcquireByte...OK +FinalFieldGetAndBitwiseXorAcquireShort...OK +FinalFieldGetAndBitwiseXorAcquireChar...OK +FinalFieldGetAndBitwiseXorAcquireInt...OK +FinalFieldGetAndBitwiseXorAcquireLong...OK +FinalFieldGetAndBitwiseXorAcquireFloat...OK +FinalFieldGetAndBitwiseXorAcquireDouble...OK +StaticFieldGetBoolean...OK +StaticFieldGetByte...OK +StaticFieldGetShort...OK +StaticFieldGetChar...OK +StaticFieldGetInt...OK +StaticFieldGetLong...OK +StaticFieldGetFloat...OK +StaticFieldGetDouble...OK +StaticFieldSetBoolean...OK +StaticFieldSetByte...OK +StaticFieldSetShort...OK +StaticFieldSetChar...OK +StaticFieldSetInt...OK +StaticFieldSetLong...OK +StaticFieldSetFloat...OK +StaticFieldSetDouble...OK +StaticFieldGetVolatileBoolean...OK +StaticFieldGetVolatileByte...OK +StaticFieldGetVolatileShort...OK +StaticFieldGetVolatileChar...OK +StaticFieldGetVolatileInt...OK +StaticFieldGetVolatileLong...OK +StaticFieldGetVolatileFloat...OK +StaticFieldGetVolatileDouble...OK +StaticFieldSetVolatileBoolean...OK +StaticFieldSetVolatileByte...OK +StaticFieldSetVolatileShort...OK +StaticFieldSetVolatileChar...OK +StaticFieldSetVolatileInt...OK +StaticFieldSetVolatileLong...OK +StaticFieldSetVolatileFloat...OK +StaticFieldSetVolatileDouble...OK +StaticFieldGetAcquireBoolean...OK +StaticFieldGetAcquireByte...OK +StaticFieldGetAcquireShort...OK +StaticFieldGetAcquireChar...OK +StaticFieldGetAcquireInt...OK +StaticFieldGetAcquireLong...OK +StaticFieldGetAcquireFloat...OK +StaticFieldGetAcquireDouble...OK +StaticFieldSetReleaseBoolean...OK +StaticFieldSetReleaseByte...OK +StaticFieldSetReleaseShort...OK +StaticFieldSetReleaseChar...OK +StaticFieldSetReleaseInt...OK +StaticFieldSetReleaseLong...OK +StaticFieldSetReleaseFloat...OK +StaticFieldSetReleaseDouble...OK +StaticFieldGetOpaqueBoolean...OK +StaticFieldGetOpaqueByte...OK +StaticFieldGetOpaqueShort...OK +StaticFieldGetOpaqueChar...OK +StaticFieldGetOpaqueInt...OK +StaticFieldGetOpaqueLong...OK +StaticFieldGetOpaqueFloat...OK +StaticFieldGetOpaqueDouble...OK +StaticFieldSetOpaqueBoolean...OK +StaticFieldSetOpaqueByte...OK +StaticFieldSetOpaqueShort...OK +StaticFieldSetOpaqueChar...OK +StaticFieldSetOpaqueInt...OK +StaticFieldSetOpaqueLong...OK +StaticFieldSetOpaqueFloat...OK +StaticFieldSetOpaqueDouble...OK +StaticFieldCompareAndSetBoolean...OK +StaticFieldCompareAndSetByte...OK +StaticFieldCompareAndSetShort...OK +StaticFieldCompareAndSetChar...OK +StaticFieldCompareAndSetInt...OK +StaticFieldCompareAndSetLong...OK +StaticFieldCompareAndSetFloat...OK +StaticFieldCompareAndSetDouble...OK +StaticFieldCompareAndExchangeBoolean...OK +StaticFieldCompareAndExchangeByte...OK +StaticFieldCompareAndExchangeShort...OK +StaticFieldCompareAndExchangeChar...OK +StaticFieldCompareAndExchangeInt...OK +StaticFieldCompareAndExchangeLong...OK +StaticFieldCompareAndExchangeFloat...OK +StaticFieldCompareAndExchangeDouble...OK +StaticFieldCompareAndExchangeAcquireBoolean...OK +StaticFieldCompareAndExchangeAcquireByte...OK +StaticFieldCompareAndExchangeAcquireShort...OK +StaticFieldCompareAndExchangeAcquireChar...OK +StaticFieldCompareAndExchangeAcquireInt...OK +StaticFieldCompareAndExchangeAcquireLong...OK +StaticFieldCompareAndExchangeAcquireFloat...OK +StaticFieldCompareAndExchangeAcquireDouble...OK +StaticFieldCompareAndExchangeReleaseBoolean...OK +StaticFieldCompareAndExchangeReleaseByte...OK +StaticFieldCompareAndExchangeReleaseShort...OK +StaticFieldCompareAndExchangeReleaseChar...OK +StaticFieldCompareAndExchangeReleaseInt...OK +StaticFieldCompareAndExchangeReleaseLong...OK +StaticFieldCompareAndExchangeReleaseFloat...OK +StaticFieldCompareAndExchangeReleaseDouble...OK +StaticFieldWeakCompareAndSetPlainBoolean...OK +StaticFieldWeakCompareAndSetPlainByte...OK +StaticFieldWeakCompareAndSetPlainShort...OK +StaticFieldWeakCompareAndSetPlainChar...OK +StaticFieldWeakCompareAndSetPlainInt...OK +StaticFieldWeakCompareAndSetPlainLong...OK +StaticFieldWeakCompareAndSetPlainFloat...OK +StaticFieldWeakCompareAndSetPlainDouble...OK +StaticFieldWeakCompareAndSetBoolean...OK +StaticFieldWeakCompareAndSetByte...OK +StaticFieldWeakCompareAndSetShort...OK +StaticFieldWeakCompareAndSetChar...OK +StaticFieldWeakCompareAndSetInt...OK +StaticFieldWeakCompareAndSetLong...OK +StaticFieldWeakCompareAndSetFloat...OK +StaticFieldWeakCompareAndSetDouble...OK +StaticFieldWeakCompareAndSetAcquireBoolean...OK +StaticFieldWeakCompareAndSetAcquireByte...OK +StaticFieldWeakCompareAndSetAcquireShort...OK +StaticFieldWeakCompareAndSetAcquireChar...OK +StaticFieldWeakCompareAndSetAcquireInt...OK +StaticFieldWeakCompareAndSetAcquireLong...OK +StaticFieldWeakCompareAndSetAcquireFloat...OK +StaticFieldWeakCompareAndSetAcquireDouble...OK +StaticFieldWeakCompareAndSetReleaseBoolean...OK +StaticFieldWeakCompareAndSetReleaseByte...OK +StaticFieldWeakCompareAndSetReleaseShort...OK +StaticFieldWeakCompareAndSetReleaseChar...OK +StaticFieldWeakCompareAndSetReleaseInt...OK +StaticFieldWeakCompareAndSetReleaseLong...OK +StaticFieldWeakCompareAndSetReleaseFloat...OK +StaticFieldWeakCompareAndSetReleaseDouble...OK +StaticFieldGetAndSetBoolean...OK +StaticFieldGetAndSetByte...OK +StaticFieldGetAndSetShort...OK +StaticFieldGetAndSetChar...OK +StaticFieldGetAndSetInt...OK +StaticFieldGetAndSetLong...OK +StaticFieldGetAndSetFloat...OK +StaticFieldGetAndSetDouble...OK +StaticFieldGetAndSetAcquireBoolean...OK +StaticFieldGetAndSetAcquireByte...OK +StaticFieldGetAndSetAcquireShort...OK +StaticFieldGetAndSetAcquireChar...OK +StaticFieldGetAndSetAcquireInt...OK +StaticFieldGetAndSetAcquireLong...OK +StaticFieldGetAndSetAcquireFloat...OK +StaticFieldGetAndSetAcquireDouble...OK +StaticFieldGetAndSetReleaseBoolean...OK +StaticFieldGetAndSetReleaseByte...OK +StaticFieldGetAndSetReleaseShort...OK +StaticFieldGetAndSetReleaseChar...OK +StaticFieldGetAndSetReleaseInt...OK +StaticFieldGetAndSetReleaseLong...OK +StaticFieldGetAndSetReleaseFloat...OK +StaticFieldGetAndSetReleaseDouble...OK +StaticFieldGetAndAddBoolean...OK +StaticFieldGetAndAddByte...OK +StaticFieldGetAndAddShort...OK +StaticFieldGetAndAddChar...OK +StaticFieldGetAndAddInt...OK +StaticFieldGetAndAddLong...OK +StaticFieldGetAndAddFloat...OK +StaticFieldGetAndAddDouble...OK +StaticFieldGetAndAddAcquireBoolean...OK +StaticFieldGetAndAddAcquireByte...OK +StaticFieldGetAndAddAcquireShort...OK +StaticFieldGetAndAddAcquireChar...OK +StaticFieldGetAndAddAcquireInt...OK +StaticFieldGetAndAddAcquireLong...OK +StaticFieldGetAndAddAcquireFloat...OK +StaticFieldGetAndAddAcquireDouble...OK +StaticFieldGetAndAddReleaseBoolean...OK +StaticFieldGetAndAddReleaseByte...OK +StaticFieldGetAndAddReleaseShort...OK +StaticFieldGetAndAddReleaseChar...OK +StaticFieldGetAndAddReleaseInt...OK +StaticFieldGetAndAddReleaseLong...OK +StaticFieldGetAndAddReleaseFloat...OK +StaticFieldGetAndAddReleaseDouble...OK +StaticFieldGetAndBitwiseOrBoolean...OK +StaticFieldGetAndBitwiseOrByte...OK +StaticFieldGetAndBitwiseOrShort...OK +StaticFieldGetAndBitwiseOrChar...OK +StaticFieldGetAndBitwiseOrInt...OK +StaticFieldGetAndBitwiseOrLong...OK +StaticFieldGetAndBitwiseOrFloat...OK +StaticFieldGetAndBitwiseOrDouble...OK +StaticFieldGetAndBitwiseOrReleaseBoolean...OK +StaticFieldGetAndBitwiseOrReleaseByte...OK +StaticFieldGetAndBitwiseOrReleaseShort...OK +StaticFieldGetAndBitwiseOrReleaseChar...OK +StaticFieldGetAndBitwiseOrReleaseInt...OK +StaticFieldGetAndBitwiseOrReleaseLong...OK +StaticFieldGetAndBitwiseOrReleaseFloat...OK +StaticFieldGetAndBitwiseOrReleaseDouble...OK +StaticFieldGetAndBitwiseOrAcquireBoolean...OK +StaticFieldGetAndBitwiseOrAcquireByte...OK +StaticFieldGetAndBitwiseOrAcquireShort...OK +StaticFieldGetAndBitwiseOrAcquireChar...OK +StaticFieldGetAndBitwiseOrAcquireInt...OK +StaticFieldGetAndBitwiseOrAcquireLong...OK +StaticFieldGetAndBitwiseOrAcquireFloat...OK +StaticFieldGetAndBitwiseOrAcquireDouble...OK +StaticFieldGetAndBitwiseAndBoolean...OK +StaticFieldGetAndBitwiseAndByte...OK +StaticFieldGetAndBitwiseAndShort...OK +StaticFieldGetAndBitwiseAndChar...OK +StaticFieldGetAndBitwiseAndInt...OK +StaticFieldGetAndBitwiseAndLong...OK +StaticFieldGetAndBitwiseAndFloat...OK +StaticFieldGetAndBitwiseAndDouble...OK +StaticFieldGetAndBitwiseAndReleaseBoolean...OK +StaticFieldGetAndBitwiseAndReleaseByte...OK +StaticFieldGetAndBitwiseAndReleaseShort...OK +StaticFieldGetAndBitwiseAndReleaseChar...OK +StaticFieldGetAndBitwiseAndReleaseInt...OK +StaticFieldGetAndBitwiseAndReleaseLong...OK +StaticFieldGetAndBitwiseAndReleaseFloat...OK +StaticFieldGetAndBitwiseAndReleaseDouble...OK +StaticFieldGetAndBitwiseAndAcquireBoolean...OK +StaticFieldGetAndBitwiseAndAcquireByte...OK +StaticFieldGetAndBitwiseAndAcquireShort...OK +StaticFieldGetAndBitwiseAndAcquireChar...OK +StaticFieldGetAndBitwiseAndAcquireInt...OK +StaticFieldGetAndBitwiseAndAcquireLong...OK +StaticFieldGetAndBitwiseAndAcquireFloat...OK +StaticFieldGetAndBitwiseAndAcquireDouble...OK +StaticFieldGetAndBitwiseXorBoolean...OK +StaticFieldGetAndBitwiseXorByte...OK +StaticFieldGetAndBitwiseXorShort...OK +StaticFieldGetAndBitwiseXorChar...OK +StaticFieldGetAndBitwiseXorInt...OK +StaticFieldGetAndBitwiseXorLong...OK +StaticFieldGetAndBitwiseXorFloat...OK +StaticFieldGetAndBitwiseXorDouble...OK +StaticFieldGetAndBitwiseXorReleaseBoolean...OK +StaticFieldGetAndBitwiseXorReleaseByte...OK +StaticFieldGetAndBitwiseXorReleaseShort...OK +StaticFieldGetAndBitwiseXorReleaseChar...OK +StaticFieldGetAndBitwiseXorReleaseInt...OK +StaticFieldGetAndBitwiseXorReleaseLong...OK +StaticFieldGetAndBitwiseXorReleaseFloat...OK +StaticFieldGetAndBitwiseXorReleaseDouble...OK +StaticFieldGetAndBitwiseXorAcquireBoolean...OK +StaticFieldGetAndBitwiseXorAcquireByte...OK +StaticFieldGetAndBitwiseXorAcquireShort...OK +StaticFieldGetAndBitwiseXorAcquireChar...OK +StaticFieldGetAndBitwiseXorAcquireInt...OK +StaticFieldGetAndBitwiseXorAcquireLong...OK +StaticFieldGetAndBitwiseXorAcquireFloat...OK +StaticFieldGetAndBitwiseXorAcquireDouble...OK +StaticFinalFieldGetBoolean...OK +StaticFinalFieldGetByte...OK +StaticFinalFieldGetShort...OK +StaticFinalFieldGetChar...OK +StaticFinalFieldGetInt...OK +StaticFinalFieldGetLong...OK +StaticFinalFieldGetFloat...OK +StaticFinalFieldGetDouble...OK +StaticFinalFieldSetBoolean...OK +StaticFinalFieldSetByte...OK +StaticFinalFieldSetShort...OK +StaticFinalFieldSetChar...OK +StaticFinalFieldSetInt...OK +StaticFinalFieldSetLong...OK +StaticFinalFieldSetFloat...OK +StaticFinalFieldSetDouble...OK +StaticFinalFieldGetVolatileBoolean...OK +StaticFinalFieldGetVolatileByte...OK +StaticFinalFieldGetVolatileShort...OK +StaticFinalFieldGetVolatileChar...OK +StaticFinalFieldGetVolatileInt...OK +StaticFinalFieldGetVolatileLong...OK +StaticFinalFieldGetVolatileFloat...OK +StaticFinalFieldGetVolatileDouble...OK +StaticFinalFieldSetVolatileBoolean...OK +StaticFinalFieldSetVolatileByte...OK +StaticFinalFieldSetVolatileShort...OK +StaticFinalFieldSetVolatileChar...OK +StaticFinalFieldSetVolatileInt...OK +StaticFinalFieldSetVolatileLong...OK +StaticFinalFieldSetVolatileFloat...OK +StaticFinalFieldSetVolatileDouble...OK +StaticFinalFieldGetAcquireBoolean...OK +StaticFinalFieldGetAcquireByte...OK +StaticFinalFieldGetAcquireShort...OK +StaticFinalFieldGetAcquireChar...OK +StaticFinalFieldGetAcquireInt...OK +StaticFinalFieldGetAcquireLong...OK +StaticFinalFieldGetAcquireFloat...OK +StaticFinalFieldGetAcquireDouble...OK +StaticFinalFieldSetReleaseBoolean...OK +StaticFinalFieldSetReleaseByte...OK +StaticFinalFieldSetReleaseShort...OK +StaticFinalFieldSetReleaseChar...OK +StaticFinalFieldSetReleaseInt...OK +StaticFinalFieldSetReleaseLong...OK +StaticFinalFieldSetReleaseFloat...OK +StaticFinalFieldSetReleaseDouble...OK +StaticFinalFieldGetOpaqueBoolean...OK +StaticFinalFieldGetOpaqueByte...OK +StaticFinalFieldGetOpaqueShort...OK +StaticFinalFieldGetOpaqueChar...OK +StaticFinalFieldGetOpaqueInt...OK +StaticFinalFieldGetOpaqueLong...OK +StaticFinalFieldGetOpaqueFloat...OK +StaticFinalFieldGetOpaqueDouble...OK +StaticFinalFieldSetOpaqueBoolean...OK +StaticFinalFieldSetOpaqueByte...OK +StaticFinalFieldSetOpaqueShort...OK +StaticFinalFieldSetOpaqueChar...OK +StaticFinalFieldSetOpaqueInt...OK +StaticFinalFieldSetOpaqueLong...OK +StaticFinalFieldSetOpaqueFloat...OK +StaticFinalFieldSetOpaqueDouble...OK +StaticFinalFieldCompareAndSetBoolean...OK +StaticFinalFieldCompareAndSetByte...OK +StaticFinalFieldCompareAndSetShort...OK +StaticFinalFieldCompareAndSetChar...OK +StaticFinalFieldCompareAndSetInt...OK +StaticFinalFieldCompareAndSetLong...OK +StaticFinalFieldCompareAndSetFloat...OK +StaticFinalFieldCompareAndSetDouble...OK +StaticFinalFieldCompareAndExchangeBoolean...OK +StaticFinalFieldCompareAndExchangeByte...OK +StaticFinalFieldCompareAndExchangeShort...OK +StaticFinalFieldCompareAndExchangeChar...OK +StaticFinalFieldCompareAndExchangeInt...OK +StaticFinalFieldCompareAndExchangeLong...OK +StaticFinalFieldCompareAndExchangeFloat...OK +StaticFinalFieldCompareAndExchangeDouble...OK +StaticFinalFieldCompareAndExchangeAcquireBoolean...OK +StaticFinalFieldCompareAndExchangeAcquireByte...OK +StaticFinalFieldCompareAndExchangeAcquireShort...OK +StaticFinalFieldCompareAndExchangeAcquireChar...OK +StaticFinalFieldCompareAndExchangeAcquireInt...OK +StaticFinalFieldCompareAndExchangeAcquireLong...OK +StaticFinalFieldCompareAndExchangeAcquireFloat...OK +StaticFinalFieldCompareAndExchangeAcquireDouble...OK +StaticFinalFieldCompareAndExchangeReleaseBoolean...OK +StaticFinalFieldCompareAndExchangeReleaseByte...OK +StaticFinalFieldCompareAndExchangeReleaseShort...OK +StaticFinalFieldCompareAndExchangeReleaseChar...OK +StaticFinalFieldCompareAndExchangeReleaseInt...OK +StaticFinalFieldCompareAndExchangeReleaseLong...OK +StaticFinalFieldCompareAndExchangeReleaseFloat...OK +StaticFinalFieldCompareAndExchangeReleaseDouble...OK +StaticFinalFieldWeakCompareAndSetPlainBoolean...OK +StaticFinalFieldWeakCompareAndSetPlainByte...OK +StaticFinalFieldWeakCompareAndSetPlainShort...OK +StaticFinalFieldWeakCompareAndSetPlainChar...OK +StaticFinalFieldWeakCompareAndSetPlainInt...OK +StaticFinalFieldWeakCompareAndSetPlainLong...OK +StaticFinalFieldWeakCompareAndSetPlainFloat...OK +StaticFinalFieldWeakCompareAndSetPlainDouble...OK +StaticFinalFieldWeakCompareAndSetBoolean...OK +StaticFinalFieldWeakCompareAndSetByte...OK +StaticFinalFieldWeakCompareAndSetShort...OK +StaticFinalFieldWeakCompareAndSetChar...OK +StaticFinalFieldWeakCompareAndSetInt...OK +StaticFinalFieldWeakCompareAndSetLong...OK +StaticFinalFieldWeakCompareAndSetFloat...OK +StaticFinalFieldWeakCompareAndSetDouble...OK +StaticFinalFieldWeakCompareAndSetAcquireBoolean...OK +StaticFinalFieldWeakCompareAndSetAcquireByte...OK +StaticFinalFieldWeakCompareAndSetAcquireShort...OK +StaticFinalFieldWeakCompareAndSetAcquireChar...OK +StaticFinalFieldWeakCompareAndSetAcquireInt...OK +StaticFinalFieldWeakCompareAndSetAcquireLong...OK +StaticFinalFieldWeakCompareAndSetAcquireFloat...OK +StaticFinalFieldWeakCompareAndSetAcquireDouble...OK +StaticFinalFieldWeakCompareAndSetReleaseBoolean...OK +StaticFinalFieldWeakCompareAndSetReleaseByte...OK +StaticFinalFieldWeakCompareAndSetReleaseShort...OK +StaticFinalFieldWeakCompareAndSetReleaseChar...OK +StaticFinalFieldWeakCompareAndSetReleaseInt...OK +StaticFinalFieldWeakCompareAndSetReleaseLong...OK +StaticFinalFieldWeakCompareAndSetReleaseFloat...OK +StaticFinalFieldWeakCompareAndSetReleaseDouble...OK +StaticFinalFieldGetAndSetBoolean...OK +StaticFinalFieldGetAndSetByte...OK +StaticFinalFieldGetAndSetShort...OK +StaticFinalFieldGetAndSetChar...OK +StaticFinalFieldGetAndSetInt...OK +StaticFinalFieldGetAndSetLong...OK +StaticFinalFieldGetAndSetFloat...OK +StaticFinalFieldGetAndSetDouble...OK +StaticFinalFieldGetAndSetAcquireBoolean...OK +StaticFinalFieldGetAndSetAcquireByte...OK +StaticFinalFieldGetAndSetAcquireShort...OK +StaticFinalFieldGetAndSetAcquireChar...OK +StaticFinalFieldGetAndSetAcquireInt...OK +StaticFinalFieldGetAndSetAcquireLong...OK +StaticFinalFieldGetAndSetAcquireFloat...OK +StaticFinalFieldGetAndSetAcquireDouble...OK +StaticFinalFieldGetAndSetReleaseBoolean...OK +StaticFinalFieldGetAndSetReleaseByte...OK +StaticFinalFieldGetAndSetReleaseShort...OK +StaticFinalFieldGetAndSetReleaseChar...OK +StaticFinalFieldGetAndSetReleaseInt...OK +StaticFinalFieldGetAndSetReleaseLong...OK +StaticFinalFieldGetAndSetReleaseFloat...OK +StaticFinalFieldGetAndSetReleaseDouble...OK +StaticFinalFieldGetAndAddBoolean...OK +StaticFinalFieldGetAndAddByte...OK +StaticFinalFieldGetAndAddShort...OK +StaticFinalFieldGetAndAddChar...OK +StaticFinalFieldGetAndAddInt...OK +StaticFinalFieldGetAndAddLong...OK +StaticFinalFieldGetAndAddFloat...OK +StaticFinalFieldGetAndAddDouble...OK +StaticFinalFieldGetAndAddAcquireBoolean...OK +StaticFinalFieldGetAndAddAcquireByte...OK +StaticFinalFieldGetAndAddAcquireShort...OK +StaticFinalFieldGetAndAddAcquireChar...OK +StaticFinalFieldGetAndAddAcquireInt...OK +StaticFinalFieldGetAndAddAcquireLong...OK +StaticFinalFieldGetAndAddAcquireFloat...OK +StaticFinalFieldGetAndAddAcquireDouble...OK +StaticFinalFieldGetAndAddReleaseBoolean...OK +StaticFinalFieldGetAndAddReleaseByte...OK +StaticFinalFieldGetAndAddReleaseShort...OK +StaticFinalFieldGetAndAddReleaseChar...OK +StaticFinalFieldGetAndAddReleaseInt...OK +StaticFinalFieldGetAndAddReleaseLong...OK +StaticFinalFieldGetAndAddReleaseFloat...OK +StaticFinalFieldGetAndAddReleaseDouble...OK +StaticFinalFieldGetAndBitwiseOrBoolean...OK +StaticFinalFieldGetAndBitwiseOrByte...OK +StaticFinalFieldGetAndBitwiseOrShort...OK +StaticFinalFieldGetAndBitwiseOrChar...OK +StaticFinalFieldGetAndBitwiseOrInt...OK +StaticFinalFieldGetAndBitwiseOrLong...OK +StaticFinalFieldGetAndBitwiseOrFloat...OK +StaticFinalFieldGetAndBitwiseOrDouble...OK +StaticFinalFieldGetAndBitwiseOrReleaseBoolean...OK +StaticFinalFieldGetAndBitwiseOrReleaseByte...OK +StaticFinalFieldGetAndBitwiseOrReleaseShort...OK +StaticFinalFieldGetAndBitwiseOrReleaseChar...OK +StaticFinalFieldGetAndBitwiseOrReleaseInt...OK +StaticFinalFieldGetAndBitwiseOrReleaseLong...OK +StaticFinalFieldGetAndBitwiseOrReleaseFloat...OK +StaticFinalFieldGetAndBitwiseOrReleaseDouble...OK +StaticFinalFieldGetAndBitwiseOrAcquireBoolean...OK +StaticFinalFieldGetAndBitwiseOrAcquireByte...OK +StaticFinalFieldGetAndBitwiseOrAcquireShort...OK +StaticFinalFieldGetAndBitwiseOrAcquireChar...OK +StaticFinalFieldGetAndBitwiseOrAcquireInt...OK +StaticFinalFieldGetAndBitwiseOrAcquireLong...OK +StaticFinalFieldGetAndBitwiseOrAcquireFloat...OK +StaticFinalFieldGetAndBitwiseOrAcquireDouble...OK +StaticFinalFieldGetAndBitwiseAndBoolean...OK +StaticFinalFieldGetAndBitwiseAndByte...OK +StaticFinalFieldGetAndBitwiseAndShort...OK +StaticFinalFieldGetAndBitwiseAndChar...OK +StaticFinalFieldGetAndBitwiseAndInt...OK +StaticFinalFieldGetAndBitwiseAndLong...OK +StaticFinalFieldGetAndBitwiseAndFloat...OK +StaticFinalFieldGetAndBitwiseAndDouble...OK +StaticFinalFieldGetAndBitwiseAndReleaseBoolean...OK +StaticFinalFieldGetAndBitwiseAndReleaseByte...OK +StaticFinalFieldGetAndBitwiseAndReleaseShort...OK +StaticFinalFieldGetAndBitwiseAndReleaseChar...OK +StaticFinalFieldGetAndBitwiseAndReleaseInt...OK +StaticFinalFieldGetAndBitwiseAndReleaseLong...OK +StaticFinalFieldGetAndBitwiseAndReleaseFloat...OK +StaticFinalFieldGetAndBitwiseAndReleaseDouble...OK +StaticFinalFieldGetAndBitwiseAndAcquireBoolean...OK +StaticFinalFieldGetAndBitwiseAndAcquireByte...OK +StaticFinalFieldGetAndBitwiseAndAcquireShort...OK +StaticFinalFieldGetAndBitwiseAndAcquireChar...OK +StaticFinalFieldGetAndBitwiseAndAcquireInt...OK +StaticFinalFieldGetAndBitwiseAndAcquireLong...OK +StaticFinalFieldGetAndBitwiseAndAcquireFloat...OK +StaticFinalFieldGetAndBitwiseAndAcquireDouble...OK +StaticFinalFieldGetAndBitwiseXorBoolean...OK +StaticFinalFieldGetAndBitwiseXorByte...OK +StaticFinalFieldGetAndBitwiseXorShort...OK +StaticFinalFieldGetAndBitwiseXorChar...OK +StaticFinalFieldGetAndBitwiseXorInt...OK +StaticFinalFieldGetAndBitwiseXorLong...OK +StaticFinalFieldGetAndBitwiseXorFloat...OK +StaticFinalFieldGetAndBitwiseXorDouble...OK +StaticFinalFieldGetAndBitwiseXorReleaseBoolean...OK +StaticFinalFieldGetAndBitwiseXorReleaseByte...OK +StaticFinalFieldGetAndBitwiseXorReleaseShort...OK +StaticFinalFieldGetAndBitwiseXorReleaseChar...OK +StaticFinalFieldGetAndBitwiseXorReleaseInt...OK +StaticFinalFieldGetAndBitwiseXorReleaseLong...OK +StaticFinalFieldGetAndBitwiseXorReleaseFloat...OK +StaticFinalFieldGetAndBitwiseXorReleaseDouble...OK +StaticFinalFieldGetAndBitwiseXorAcquireBoolean...OK +StaticFinalFieldGetAndBitwiseXorAcquireByte...OK +StaticFinalFieldGetAndBitwiseXorAcquireShort...OK +StaticFinalFieldGetAndBitwiseXorAcquireChar...OK +StaticFinalFieldGetAndBitwiseXorAcquireInt...OK +StaticFinalFieldGetAndBitwiseXorAcquireLong...OK +StaticFinalFieldGetAndBitwiseXorAcquireFloat...OK +StaticFinalFieldGetAndBitwiseXorAcquireDouble...OK +ArrayElementGetBoolean...OK +ArrayElementGetByte...OK +ArrayElementGetShort...OK +ArrayElementGetChar...OK +ArrayElementGetInt...OK +ArrayElementGetLong...OK +ArrayElementGetFloat...OK +ArrayElementGetDouble...OK +ArrayElementSetBoolean...OK +ArrayElementSetByte...OK +ArrayElementSetShort...OK +ArrayElementSetChar...OK +ArrayElementSetInt...OK +ArrayElementSetLong...OK +ArrayElementSetFloat...OK +ArrayElementSetDouble...OK +ArrayElementGetVolatileBoolean...OK +ArrayElementGetVolatileByte...OK +ArrayElementGetVolatileShort...OK +ArrayElementGetVolatileChar...OK +ArrayElementGetVolatileInt...OK +ArrayElementGetVolatileLong...OK +ArrayElementGetVolatileFloat...OK +ArrayElementGetVolatileDouble...OK +ArrayElementSetVolatileBoolean...OK +ArrayElementSetVolatileByte...OK +ArrayElementSetVolatileShort...OK +ArrayElementSetVolatileChar...OK +ArrayElementSetVolatileInt...OK +ArrayElementSetVolatileLong...OK +ArrayElementSetVolatileFloat...OK +ArrayElementSetVolatileDouble...OK +ArrayElementGetAcquireBoolean...OK +ArrayElementGetAcquireByte...OK +ArrayElementGetAcquireShort...OK +ArrayElementGetAcquireChar...OK +ArrayElementGetAcquireInt...OK +ArrayElementGetAcquireLong...OK +ArrayElementGetAcquireFloat...OK +ArrayElementGetAcquireDouble...OK +ArrayElementSetReleaseBoolean...OK +ArrayElementSetReleaseByte...OK +ArrayElementSetReleaseShort...OK +ArrayElementSetReleaseChar...OK +ArrayElementSetReleaseInt...OK +ArrayElementSetReleaseLong...OK +ArrayElementSetReleaseFloat...OK +ArrayElementSetReleaseDouble...OK +ArrayElementGetOpaqueBoolean...OK +ArrayElementGetOpaqueByte...OK +ArrayElementGetOpaqueShort...OK +ArrayElementGetOpaqueChar...OK +ArrayElementGetOpaqueInt...OK +ArrayElementGetOpaqueLong...OK +ArrayElementGetOpaqueFloat...OK +ArrayElementGetOpaqueDouble...OK +ArrayElementSetOpaqueBoolean...OK +ArrayElementSetOpaqueByte...OK +ArrayElementSetOpaqueShort...OK +ArrayElementSetOpaqueChar...OK +ArrayElementSetOpaqueInt...OK +ArrayElementSetOpaqueLong...OK +ArrayElementSetOpaqueFloat...OK +ArrayElementSetOpaqueDouble...OK +ArrayElementCompareAndSetBoolean...OK +ArrayElementCompareAndSetByte...OK +ArrayElementCompareAndSetShort...OK +ArrayElementCompareAndSetChar...OK +ArrayElementCompareAndSetInt...OK +ArrayElementCompareAndSetLong...OK +ArrayElementCompareAndSetFloat...OK +ArrayElementCompareAndSetDouble...OK +ArrayElementCompareAndExchangeBoolean...OK +ArrayElementCompareAndExchangeByte...OK +ArrayElementCompareAndExchangeShort...OK +ArrayElementCompareAndExchangeChar...OK +ArrayElementCompareAndExchangeInt...OK +ArrayElementCompareAndExchangeLong...OK +ArrayElementCompareAndExchangeFloat...OK +ArrayElementCompareAndExchangeDouble...OK +ArrayElementCompareAndExchangeAcquireBoolean...OK +ArrayElementCompareAndExchangeAcquireByte...OK +ArrayElementCompareAndExchangeAcquireShort...OK +ArrayElementCompareAndExchangeAcquireChar...OK +ArrayElementCompareAndExchangeAcquireInt...OK +ArrayElementCompareAndExchangeAcquireLong...OK +ArrayElementCompareAndExchangeAcquireFloat...OK +ArrayElementCompareAndExchangeAcquireDouble...OK +ArrayElementCompareAndExchangeReleaseBoolean...OK +ArrayElementCompareAndExchangeReleaseByte...OK +ArrayElementCompareAndExchangeReleaseShort...OK +ArrayElementCompareAndExchangeReleaseChar...OK +ArrayElementCompareAndExchangeReleaseInt...OK +ArrayElementCompareAndExchangeReleaseLong...OK +ArrayElementCompareAndExchangeReleaseFloat...OK +ArrayElementCompareAndExchangeReleaseDouble...OK +ArrayElementWeakCompareAndSetPlainBoolean...OK +ArrayElementWeakCompareAndSetPlainByte...OK +ArrayElementWeakCompareAndSetPlainShort...OK +ArrayElementWeakCompareAndSetPlainChar...OK +ArrayElementWeakCompareAndSetPlainInt...OK +ArrayElementWeakCompareAndSetPlainLong...OK +ArrayElementWeakCompareAndSetPlainFloat...OK +ArrayElementWeakCompareAndSetPlainDouble...OK +ArrayElementWeakCompareAndSetBoolean...OK +ArrayElementWeakCompareAndSetByte...OK +ArrayElementWeakCompareAndSetShort...OK +ArrayElementWeakCompareAndSetChar...OK +ArrayElementWeakCompareAndSetInt...OK +ArrayElementWeakCompareAndSetLong...OK +ArrayElementWeakCompareAndSetFloat...OK +ArrayElementWeakCompareAndSetDouble...OK +ArrayElementWeakCompareAndSetAcquireBoolean...OK +ArrayElementWeakCompareAndSetAcquireByte...OK +ArrayElementWeakCompareAndSetAcquireShort...OK +ArrayElementWeakCompareAndSetAcquireChar...OK +ArrayElementWeakCompareAndSetAcquireInt...OK +ArrayElementWeakCompareAndSetAcquireLong...OK +ArrayElementWeakCompareAndSetAcquireFloat...OK +ArrayElementWeakCompareAndSetAcquireDouble...OK +ArrayElementWeakCompareAndSetReleaseBoolean...OK +ArrayElementWeakCompareAndSetReleaseByte...OK +ArrayElementWeakCompareAndSetReleaseShort...OK +ArrayElementWeakCompareAndSetReleaseChar...OK +ArrayElementWeakCompareAndSetReleaseInt...OK +ArrayElementWeakCompareAndSetReleaseLong...OK +ArrayElementWeakCompareAndSetReleaseFloat...OK +ArrayElementWeakCompareAndSetReleaseDouble...OK +ArrayElementGetAndSetBoolean...OK +ArrayElementGetAndSetByte...OK +ArrayElementGetAndSetShort...OK +ArrayElementGetAndSetChar...OK +ArrayElementGetAndSetInt...OK +ArrayElementGetAndSetLong...OK +ArrayElementGetAndSetFloat...OK +ArrayElementGetAndSetDouble...OK +ArrayElementGetAndSetAcquireBoolean...OK +ArrayElementGetAndSetAcquireByte...OK +ArrayElementGetAndSetAcquireShort...OK +ArrayElementGetAndSetAcquireChar...OK +ArrayElementGetAndSetAcquireInt...OK +ArrayElementGetAndSetAcquireLong...OK +ArrayElementGetAndSetAcquireFloat...OK +ArrayElementGetAndSetAcquireDouble...OK +ArrayElementGetAndSetReleaseBoolean...OK +ArrayElementGetAndSetReleaseByte...OK +ArrayElementGetAndSetReleaseShort...OK +ArrayElementGetAndSetReleaseChar...OK +ArrayElementGetAndSetReleaseInt...OK +ArrayElementGetAndSetReleaseLong...OK +ArrayElementGetAndSetReleaseFloat...OK +ArrayElementGetAndSetReleaseDouble...OK +ArrayElementGetAndAddBoolean...OK +ArrayElementGetAndAddByte...OK +ArrayElementGetAndAddShort...OK +ArrayElementGetAndAddChar...OK +ArrayElementGetAndAddInt...OK +ArrayElementGetAndAddLong...OK +ArrayElementGetAndAddFloat...OK +ArrayElementGetAndAddDouble...OK +ArrayElementGetAndAddAcquireBoolean...OK +ArrayElementGetAndAddAcquireByte...OK +ArrayElementGetAndAddAcquireShort...OK +ArrayElementGetAndAddAcquireChar...OK +ArrayElementGetAndAddAcquireInt...OK +ArrayElementGetAndAddAcquireLong...OK +ArrayElementGetAndAddAcquireFloat...OK +ArrayElementGetAndAddAcquireDouble...OK +ArrayElementGetAndAddReleaseBoolean...OK +ArrayElementGetAndAddReleaseByte...OK +ArrayElementGetAndAddReleaseShort...OK +ArrayElementGetAndAddReleaseChar...OK +ArrayElementGetAndAddReleaseInt...OK +ArrayElementGetAndAddReleaseLong...OK +ArrayElementGetAndAddReleaseFloat...OK +ArrayElementGetAndAddReleaseDouble...OK +ArrayElementGetAndBitwiseOrBoolean...OK +ArrayElementGetAndBitwiseOrByte...OK +ArrayElementGetAndBitwiseOrShort...OK +ArrayElementGetAndBitwiseOrChar...OK +ArrayElementGetAndBitwiseOrInt...OK +ArrayElementGetAndBitwiseOrLong...OK +ArrayElementGetAndBitwiseOrFloat...OK +ArrayElementGetAndBitwiseOrDouble...OK +ArrayElementGetAndBitwiseOrReleaseBoolean...OK +ArrayElementGetAndBitwiseOrReleaseByte...OK +ArrayElementGetAndBitwiseOrReleaseShort...OK +ArrayElementGetAndBitwiseOrReleaseChar...OK +ArrayElementGetAndBitwiseOrReleaseInt...OK +ArrayElementGetAndBitwiseOrReleaseLong...OK +ArrayElementGetAndBitwiseOrReleaseFloat...OK +ArrayElementGetAndBitwiseOrReleaseDouble...OK +ArrayElementGetAndBitwiseOrAcquireBoolean...OK +ArrayElementGetAndBitwiseOrAcquireByte...OK +ArrayElementGetAndBitwiseOrAcquireShort...OK +ArrayElementGetAndBitwiseOrAcquireChar...OK +ArrayElementGetAndBitwiseOrAcquireInt...OK +ArrayElementGetAndBitwiseOrAcquireLong...OK +ArrayElementGetAndBitwiseOrAcquireFloat...OK +ArrayElementGetAndBitwiseOrAcquireDouble...OK +ArrayElementGetAndBitwiseAndBoolean...OK +ArrayElementGetAndBitwiseAndByte...OK +ArrayElementGetAndBitwiseAndShort...OK +ArrayElementGetAndBitwiseAndChar...OK +ArrayElementGetAndBitwiseAndInt...OK +ArrayElementGetAndBitwiseAndLong...OK +ArrayElementGetAndBitwiseAndFloat...OK +ArrayElementGetAndBitwiseAndDouble...OK +ArrayElementGetAndBitwiseAndReleaseBoolean...OK +ArrayElementGetAndBitwiseAndReleaseByte...OK +ArrayElementGetAndBitwiseAndReleaseShort...OK +ArrayElementGetAndBitwiseAndReleaseChar...OK +ArrayElementGetAndBitwiseAndReleaseInt...OK +ArrayElementGetAndBitwiseAndReleaseLong...OK +ArrayElementGetAndBitwiseAndReleaseFloat...OK +ArrayElementGetAndBitwiseAndReleaseDouble...OK +ArrayElementGetAndBitwiseAndAcquireBoolean...OK +ArrayElementGetAndBitwiseAndAcquireByte...OK +ArrayElementGetAndBitwiseAndAcquireShort...OK +ArrayElementGetAndBitwiseAndAcquireChar...OK +ArrayElementGetAndBitwiseAndAcquireInt...OK +ArrayElementGetAndBitwiseAndAcquireLong...OK +ArrayElementGetAndBitwiseAndAcquireFloat...OK +ArrayElementGetAndBitwiseAndAcquireDouble...OK +ArrayElementGetAndBitwiseXorBoolean...OK +ArrayElementGetAndBitwiseXorByte...OK +ArrayElementGetAndBitwiseXorShort...OK +ArrayElementGetAndBitwiseXorChar...OK +ArrayElementGetAndBitwiseXorInt...OK +ArrayElementGetAndBitwiseXorLong...OK +ArrayElementGetAndBitwiseXorFloat...OK +ArrayElementGetAndBitwiseXorDouble...OK +ArrayElementGetAndBitwiseXorReleaseBoolean...OK +ArrayElementGetAndBitwiseXorReleaseByte...OK +ArrayElementGetAndBitwiseXorReleaseShort...OK +ArrayElementGetAndBitwiseXorReleaseChar...OK +ArrayElementGetAndBitwiseXorReleaseInt...OK +ArrayElementGetAndBitwiseXorReleaseLong...OK +ArrayElementGetAndBitwiseXorReleaseFloat...OK +ArrayElementGetAndBitwiseXorReleaseDouble...OK +ArrayElementGetAndBitwiseXorAcquireBoolean...OK +ArrayElementGetAndBitwiseXorAcquireByte...OK +ArrayElementGetAndBitwiseXorAcquireShort...OK +ArrayElementGetAndBitwiseXorAcquireChar...OK +ArrayElementGetAndBitwiseXorAcquireInt...OK +ArrayElementGetAndBitwiseXorAcquireLong...OK +ArrayElementGetAndBitwiseXorAcquireFloat...OK +ArrayElementGetAndBitwiseXorAcquireDouble...OK +ByteArrayViewLEGetShort...OK +ByteArrayViewLEGetChar...OK +ByteArrayViewLEGetInt...OK +ByteArrayViewLEGetLong...OK +ByteArrayViewLEGetFloat...OK +ByteArrayViewLEGetDouble...OK +ByteArrayViewLESetShort...OK +ByteArrayViewLESetChar...OK +ByteArrayViewLESetInt...OK +ByteArrayViewLESetLong...OK +ByteArrayViewLESetFloat...OK +ByteArrayViewLESetDouble...OK +ByteArrayViewLEGetVolatileShort...OK +ByteArrayViewLEGetVolatileChar...OK +ByteArrayViewLEGetVolatileInt...OK +ByteArrayViewLEGetVolatileLong...OK +ByteArrayViewLEGetVolatileFloat...OK +ByteArrayViewLEGetVolatileDouble...OK +ByteArrayViewLESetVolatileShort...OK +ByteArrayViewLESetVolatileChar...OK +ByteArrayViewLESetVolatileInt...OK +ByteArrayViewLESetVolatileLong...OK +ByteArrayViewLESetVolatileFloat...OK +ByteArrayViewLESetVolatileDouble...OK +ByteArrayViewLEGetAcquireShort...OK +ByteArrayViewLEGetAcquireChar...OK +ByteArrayViewLEGetAcquireInt...OK +ByteArrayViewLEGetAcquireLong...OK +ByteArrayViewLEGetAcquireFloat...OK +ByteArrayViewLEGetAcquireDouble...OK +ByteArrayViewLESetReleaseShort...OK +ByteArrayViewLESetReleaseChar...OK +ByteArrayViewLESetReleaseInt...OK +ByteArrayViewLESetReleaseLong...OK +ByteArrayViewLESetReleaseFloat...OK +ByteArrayViewLESetReleaseDouble...OK +ByteArrayViewLEGetOpaqueShort...OK +ByteArrayViewLEGetOpaqueChar...OK +ByteArrayViewLEGetOpaqueInt...OK +ByteArrayViewLEGetOpaqueLong...OK +ByteArrayViewLEGetOpaqueFloat...OK +ByteArrayViewLEGetOpaqueDouble...OK +ByteArrayViewLESetOpaqueShort...OK +ByteArrayViewLESetOpaqueChar...OK +ByteArrayViewLESetOpaqueInt...OK +ByteArrayViewLESetOpaqueLong...OK +ByteArrayViewLESetOpaqueFloat...OK +ByteArrayViewLESetOpaqueDouble...OK +ByteArrayViewLECompareAndSetShort...OK +ByteArrayViewLECompareAndSetChar...OK +ByteArrayViewLECompareAndSetInt...OK +ByteArrayViewLECompareAndSetLong...OK +ByteArrayViewLECompareAndSetFloat...OK +ByteArrayViewLECompareAndSetDouble...OK +ByteArrayViewLECompareAndExchangeShort...OK +ByteArrayViewLECompareAndExchangeChar...OK +ByteArrayViewLECompareAndExchangeInt...OK +ByteArrayViewLECompareAndExchangeLong...OK +ByteArrayViewLECompareAndExchangeFloat...OK +ByteArrayViewLECompareAndExchangeDouble...OK +ByteArrayViewLECompareAndExchangeAcquireShort...OK +ByteArrayViewLECompareAndExchangeAcquireChar...OK +ByteArrayViewLECompareAndExchangeAcquireInt...OK +ByteArrayViewLECompareAndExchangeAcquireLong...OK +ByteArrayViewLECompareAndExchangeAcquireFloat...OK +ByteArrayViewLECompareAndExchangeAcquireDouble...OK +ByteArrayViewLECompareAndExchangeReleaseShort...OK +ByteArrayViewLECompareAndExchangeReleaseChar...OK +ByteArrayViewLECompareAndExchangeReleaseInt...OK +ByteArrayViewLECompareAndExchangeReleaseLong...OK +ByteArrayViewLECompareAndExchangeReleaseFloat...OK +ByteArrayViewLECompareAndExchangeReleaseDouble...OK +ByteArrayViewLEWeakCompareAndSetPlainShort...OK +ByteArrayViewLEWeakCompareAndSetPlainChar...OK +ByteArrayViewLEWeakCompareAndSetPlainInt...OK +ByteArrayViewLEWeakCompareAndSetPlainLong...OK +ByteArrayViewLEWeakCompareAndSetPlainFloat...OK +ByteArrayViewLEWeakCompareAndSetPlainDouble...OK +ByteArrayViewLEWeakCompareAndSetShort...OK +ByteArrayViewLEWeakCompareAndSetChar...OK +ByteArrayViewLEWeakCompareAndSetInt...OK +ByteArrayViewLEWeakCompareAndSetLong...OK +ByteArrayViewLEWeakCompareAndSetFloat...OK +ByteArrayViewLEWeakCompareAndSetDouble...OK +ByteArrayViewLEWeakCompareAndSetAcquireShort...OK +ByteArrayViewLEWeakCompareAndSetAcquireChar...OK +ByteArrayViewLEWeakCompareAndSetAcquireInt...OK +ByteArrayViewLEWeakCompareAndSetAcquireLong...OK +ByteArrayViewLEWeakCompareAndSetAcquireFloat...OK +ByteArrayViewLEWeakCompareAndSetAcquireDouble...OK +ByteArrayViewLEWeakCompareAndSetReleaseShort...OK +ByteArrayViewLEWeakCompareAndSetReleaseChar...OK +ByteArrayViewLEWeakCompareAndSetReleaseInt...OK +ByteArrayViewLEWeakCompareAndSetReleaseLong...OK +ByteArrayViewLEWeakCompareAndSetReleaseFloat...OK +ByteArrayViewLEWeakCompareAndSetReleaseDouble...OK +ByteArrayViewLEGetAndSetShort...OK +ByteArrayViewLEGetAndSetChar...OK +ByteArrayViewLEGetAndSetInt...OK +ByteArrayViewLEGetAndSetLong...OK +ByteArrayViewLEGetAndSetFloat...OK +ByteArrayViewLEGetAndSetDouble...OK +ByteArrayViewLEGetAndSetAcquireShort...OK +ByteArrayViewLEGetAndSetAcquireChar...OK +ByteArrayViewLEGetAndSetAcquireInt...OK +ByteArrayViewLEGetAndSetAcquireLong...OK +ByteArrayViewLEGetAndSetAcquireFloat...OK +ByteArrayViewLEGetAndSetAcquireDouble...OK +ByteArrayViewLEGetAndSetReleaseShort...OK +ByteArrayViewLEGetAndSetReleaseChar...OK +ByteArrayViewLEGetAndSetReleaseInt...OK +ByteArrayViewLEGetAndSetReleaseLong...OK +ByteArrayViewLEGetAndSetReleaseFloat...OK +ByteArrayViewLEGetAndSetReleaseDouble...OK +ByteArrayViewLEGetAndAddShort...OK +ByteArrayViewLEGetAndAddChar...OK +ByteArrayViewLEGetAndAddInt...OK +ByteArrayViewLEGetAndAddLong...OK +ByteArrayViewLEGetAndAddFloat...OK +ByteArrayViewLEGetAndAddDouble...OK +ByteArrayViewLEGetAndAddAcquireShort...OK +ByteArrayViewLEGetAndAddAcquireChar...OK +ByteArrayViewLEGetAndAddAcquireInt...OK +ByteArrayViewLEGetAndAddAcquireLong...OK +ByteArrayViewLEGetAndAddAcquireFloat...OK +ByteArrayViewLEGetAndAddAcquireDouble...OK +ByteArrayViewLEGetAndAddReleaseShort...OK +ByteArrayViewLEGetAndAddReleaseChar...OK +ByteArrayViewLEGetAndAddReleaseInt...OK +ByteArrayViewLEGetAndAddReleaseLong...OK +ByteArrayViewLEGetAndAddReleaseFloat...OK +ByteArrayViewLEGetAndAddReleaseDouble...OK +ByteArrayViewLEGetAndBitwiseOrShort...OK +ByteArrayViewLEGetAndBitwiseOrChar...OK +ByteArrayViewLEGetAndBitwiseOrInt...OK +ByteArrayViewLEGetAndBitwiseOrLong...OK +ByteArrayViewLEGetAndBitwiseOrFloat...OK +ByteArrayViewLEGetAndBitwiseOrDouble...OK +ByteArrayViewLEGetAndBitwiseOrReleaseShort...OK +ByteArrayViewLEGetAndBitwiseOrReleaseChar...OK +ByteArrayViewLEGetAndBitwiseOrReleaseInt...OK +ByteArrayViewLEGetAndBitwiseOrReleaseLong...OK +ByteArrayViewLEGetAndBitwiseOrReleaseFloat...OK +ByteArrayViewLEGetAndBitwiseOrReleaseDouble...OK +ByteArrayViewLEGetAndBitwiseOrAcquireShort...OK +ByteArrayViewLEGetAndBitwiseOrAcquireChar...OK +ByteArrayViewLEGetAndBitwiseOrAcquireInt...OK +ByteArrayViewLEGetAndBitwiseOrAcquireLong...OK +ByteArrayViewLEGetAndBitwiseOrAcquireFloat...OK +ByteArrayViewLEGetAndBitwiseOrAcquireDouble...OK +ByteArrayViewLEGetAndBitwiseAndShort...OK +ByteArrayViewLEGetAndBitwiseAndChar...OK +ByteArrayViewLEGetAndBitwiseAndInt...OK +ByteArrayViewLEGetAndBitwiseAndLong...OK +ByteArrayViewLEGetAndBitwiseAndFloat...OK +ByteArrayViewLEGetAndBitwiseAndDouble...OK +ByteArrayViewLEGetAndBitwiseAndReleaseShort...OK +ByteArrayViewLEGetAndBitwiseAndReleaseChar...OK +ByteArrayViewLEGetAndBitwiseAndReleaseInt...OK +ByteArrayViewLEGetAndBitwiseAndReleaseLong...OK +ByteArrayViewLEGetAndBitwiseAndReleaseFloat...OK +ByteArrayViewLEGetAndBitwiseAndReleaseDouble...OK +ByteArrayViewLEGetAndBitwiseAndAcquireShort...OK +ByteArrayViewLEGetAndBitwiseAndAcquireChar...OK +ByteArrayViewLEGetAndBitwiseAndAcquireInt...OK +ByteArrayViewLEGetAndBitwiseAndAcquireLong...OK +ByteArrayViewLEGetAndBitwiseAndAcquireFloat...OK +ByteArrayViewLEGetAndBitwiseAndAcquireDouble...OK +ByteArrayViewLEGetAndBitwiseXorShort...OK +ByteArrayViewLEGetAndBitwiseXorChar...OK +ByteArrayViewLEGetAndBitwiseXorInt...OK +ByteArrayViewLEGetAndBitwiseXorLong...OK +ByteArrayViewLEGetAndBitwiseXorFloat...OK +ByteArrayViewLEGetAndBitwiseXorDouble...OK +ByteArrayViewLEGetAndBitwiseXorReleaseShort...OK +ByteArrayViewLEGetAndBitwiseXorReleaseChar...OK +ByteArrayViewLEGetAndBitwiseXorReleaseInt...OK +ByteArrayViewLEGetAndBitwiseXorReleaseLong...OK +ByteArrayViewLEGetAndBitwiseXorReleaseFloat...OK +ByteArrayViewLEGetAndBitwiseXorReleaseDouble...OK +ByteArrayViewLEGetAndBitwiseXorAcquireShort...OK +ByteArrayViewLEGetAndBitwiseXorAcquireChar...OK +ByteArrayViewLEGetAndBitwiseXorAcquireInt...OK +ByteArrayViewLEGetAndBitwiseXorAcquireLong...OK +ByteArrayViewLEGetAndBitwiseXorAcquireFloat...OK +ByteArrayViewLEGetAndBitwiseXorAcquireDouble...OK +ByteArrayViewBEGetShort...OK +ByteArrayViewBEGetChar...OK +ByteArrayViewBEGetInt...OK +ByteArrayViewBEGetLong...OK +ByteArrayViewBEGetFloat...OK +ByteArrayViewBEGetDouble...OK +ByteArrayViewBESetShort...OK +ByteArrayViewBESetChar...OK +ByteArrayViewBESetInt...OK +ByteArrayViewBESetLong...OK +ByteArrayViewBESetFloat...OK +ByteArrayViewBESetDouble...OK +ByteArrayViewBEGetVolatileShort...OK +ByteArrayViewBEGetVolatileChar...OK +ByteArrayViewBEGetVolatileInt...OK +ByteArrayViewBEGetVolatileLong...OK +ByteArrayViewBEGetVolatileFloat...OK +ByteArrayViewBEGetVolatileDouble...OK +ByteArrayViewBESetVolatileShort...OK +ByteArrayViewBESetVolatileChar...OK +ByteArrayViewBESetVolatileInt...OK +ByteArrayViewBESetVolatileLong...OK +ByteArrayViewBESetVolatileFloat...OK +ByteArrayViewBESetVolatileDouble...OK +ByteArrayViewBEGetAcquireShort...OK +ByteArrayViewBEGetAcquireChar...OK +ByteArrayViewBEGetAcquireInt...OK +ByteArrayViewBEGetAcquireLong...OK +ByteArrayViewBEGetAcquireFloat...OK +ByteArrayViewBEGetAcquireDouble...OK +ByteArrayViewBESetReleaseShort...OK +ByteArrayViewBESetReleaseChar...OK +ByteArrayViewBESetReleaseInt...OK +ByteArrayViewBESetReleaseLong...OK +ByteArrayViewBESetReleaseFloat...OK +ByteArrayViewBESetReleaseDouble...OK +ByteArrayViewBEGetOpaqueShort...OK +ByteArrayViewBEGetOpaqueChar...OK +ByteArrayViewBEGetOpaqueInt...OK +ByteArrayViewBEGetOpaqueLong...OK +ByteArrayViewBEGetOpaqueFloat...OK +ByteArrayViewBEGetOpaqueDouble...OK +ByteArrayViewBESetOpaqueShort...OK +ByteArrayViewBESetOpaqueChar...OK +ByteArrayViewBESetOpaqueInt...OK +ByteArrayViewBESetOpaqueLong...OK +ByteArrayViewBESetOpaqueFloat...OK +ByteArrayViewBESetOpaqueDouble...OK +ByteArrayViewBECompareAndSetShort...OK +ByteArrayViewBECompareAndSetChar...OK +ByteArrayViewBECompareAndSetInt...OK +ByteArrayViewBECompareAndSetLong...OK +ByteArrayViewBECompareAndSetFloat...OK +ByteArrayViewBECompareAndSetDouble...OK +ByteArrayViewBECompareAndExchangeShort...OK +ByteArrayViewBECompareAndExchangeChar...OK +ByteArrayViewBECompareAndExchangeInt...OK +ByteArrayViewBECompareAndExchangeLong...OK +ByteArrayViewBECompareAndExchangeFloat...OK +ByteArrayViewBECompareAndExchangeDouble...OK +ByteArrayViewBECompareAndExchangeAcquireShort...OK +ByteArrayViewBECompareAndExchangeAcquireChar...OK +ByteArrayViewBECompareAndExchangeAcquireInt...OK +ByteArrayViewBECompareAndExchangeAcquireLong...OK +ByteArrayViewBECompareAndExchangeAcquireFloat...OK +ByteArrayViewBECompareAndExchangeAcquireDouble...OK +ByteArrayViewBECompareAndExchangeReleaseShort...OK +ByteArrayViewBECompareAndExchangeReleaseChar...OK +ByteArrayViewBECompareAndExchangeReleaseInt...OK +ByteArrayViewBECompareAndExchangeReleaseLong...OK +ByteArrayViewBECompareAndExchangeReleaseFloat...OK +ByteArrayViewBECompareAndExchangeReleaseDouble...OK +ByteArrayViewBEWeakCompareAndSetPlainShort...OK +ByteArrayViewBEWeakCompareAndSetPlainChar...OK +ByteArrayViewBEWeakCompareAndSetPlainInt...OK +ByteArrayViewBEWeakCompareAndSetPlainLong...OK +ByteArrayViewBEWeakCompareAndSetPlainFloat...OK +ByteArrayViewBEWeakCompareAndSetPlainDouble...OK +ByteArrayViewBEWeakCompareAndSetShort...OK +ByteArrayViewBEWeakCompareAndSetChar...OK +ByteArrayViewBEWeakCompareAndSetInt...OK +ByteArrayViewBEWeakCompareAndSetLong...OK +ByteArrayViewBEWeakCompareAndSetFloat...OK +ByteArrayViewBEWeakCompareAndSetDouble...OK +ByteArrayViewBEWeakCompareAndSetAcquireShort...OK +ByteArrayViewBEWeakCompareAndSetAcquireChar...OK +ByteArrayViewBEWeakCompareAndSetAcquireInt...OK +ByteArrayViewBEWeakCompareAndSetAcquireLong...OK +ByteArrayViewBEWeakCompareAndSetAcquireFloat...OK +ByteArrayViewBEWeakCompareAndSetAcquireDouble...OK +ByteArrayViewBEWeakCompareAndSetReleaseShort...OK +ByteArrayViewBEWeakCompareAndSetReleaseChar...OK +ByteArrayViewBEWeakCompareAndSetReleaseInt...OK +ByteArrayViewBEWeakCompareAndSetReleaseLong...OK +ByteArrayViewBEWeakCompareAndSetReleaseFloat...OK +ByteArrayViewBEWeakCompareAndSetReleaseDouble...OK +ByteArrayViewBEGetAndSetShort...OK +ByteArrayViewBEGetAndSetChar...OK +ByteArrayViewBEGetAndSetInt...OK +ByteArrayViewBEGetAndSetLong...OK +ByteArrayViewBEGetAndSetFloat...OK +ByteArrayViewBEGetAndSetDouble...OK +ByteArrayViewBEGetAndSetAcquireShort...OK +ByteArrayViewBEGetAndSetAcquireChar...OK +ByteArrayViewBEGetAndSetAcquireInt...OK +ByteArrayViewBEGetAndSetAcquireLong...OK +ByteArrayViewBEGetAndSetAcquireFloat...OK +ByteArrayViewBEGetAndSetAcquireDouble...OK +ByteArrayViewBEGetAndSetReleaseShort...OK +ByteArrayViewBEGetAndSetReleaseChar...OK +ByteArrayViewBEGetAndSetReleaseInt...OK +ByteArrayViewBEGetAndSetReleaseLong...OK +ByteArrayViewBEGetAndSetReleaseFloat...OK +ByteArrayViewBEGetAndSetReleaseDouble...OK +ByteArrayViewBEGetAndAddShort...OK +ByteArrayViewBEGetAndAddChar...OK +ByteArrayViewBEGetAndAddInt...OK +ByteArrayViewBEGetAndAddLong...OK +ByteArrayViewBEGetAndAddFloat...OK +ByteArrayViewBEGetAndAddDouble...OK +ByteArrayViewBEGetAndAddAcquireShort...OK +ByteArrayViewBEGetAndAddAcquireChar...OK +ByteArrayViewBEGetAndAddAcquireInt...OK +ByteArrayViewBEGetAndAddAcquireLong...OK +ByteArrayViewBEGetAndAddAcquireFloat...OK +ByteArrayViewBEGetAndAddAcquireDouble...OK +ByteArrayViewBEGetAndAddReleaseShort...OK +ByteArrayViewBEGetAndAddReleaseChar...OK +ByteArrayViewBEGetAndAddReleaseInt...OK +ByteArrayViewBEGetAndAddReleaseLong...OK +ByteArrayViewBEGetAndAddReleaseFloat...OK +ByteArrayViewBEGetAndAddReleaseDouble...OK +ByteArrayViewBEGetAndBitwiseOrShort...OK +ByteArrayViewBEGetAndBitwiseOrChar...OK +ByteArrayViewBEGetAndBitwiseOrInt...OK +ByteArrayViewBEGetAndBitwiseOrLong...OK +ByteArrayViewBEGetAndBitwiseOrFloat...OK +ByteArrayViewBEGetAndBitwiseOrDouble...OK +ByteArrayViewBEGetAndBitwiseOrReleaseShort...OK +ByteArrayViewBEGetAndBitwiseOrReleaseChar...OK +ByteArrayViewBEGetAndBitwiseOrReleaseInt...OK +ByteArrayViewBEGetAndBitwiseOrReleaseLong...OK +ByteArrayViewBEGetAndBitwiseOrReleaseFloat...OK +ByteArrayViewBEGetAndBitwiseOrReleaseDouble...OK +ByteArrayViewBEGetAndBitwiseOrAcquireShort...OK +ByteArrayViewBEGetAndBitwiseOrAcquireChar...OK +ByteArrayViewBEGetAndBitwiseOrAcquireInt...OK +ByteArrayViewBEGetAndBitwiseOrAcquireLong...OK +ByteArrayViewBEGetAndBitwiseOrAcquireFloat...OK +ByteArrayViewBEGetAndBitwiseOrAcquireDouble...OK +ByteArrayViewBEGetAndBitwiseAndShort...OK +ByteArrayViewBEGetAndBitwiseAndChar...OK +ByteArrayViewBEGetAndBitwiseAndInt...OK +ByteArrayViewBEGetAndBitwiseAndLong...OK +ByteArrayViewBEGetAndBitwiseAndFloat...OK +ByteArrayViewBEGetAndBitwiseAndDouble...OK +ByteArrayViewBEGetAndBitwiseAndReleaseShort...OK +ByteArrayViewBEGetAndBitwiseAndReleaseChar...OK +ByteArrayViewBEGetAndBitwiseAndReleaseInt...OK +ByteArrayViewBEGetAndBitwiseAndReleaseLong...OK +ByteArrayViewBEGetAndBitwiseAndReleaseFloat...OK +ByteArrayViewBEGetAndBitwiseAndReleaseDouble...OK +ByteArrayViewBEGetAndBitwiseAndAcquireShort...OK +ByteArrayViewBEGetAndBitwiseAndAcquireChar...OK +ByteArrayViewBEGetAndBitwiseAndAcquireInt...OK +ByteArrayViewBEGetAndBitwiseAndAcquireLong...OK +ByteArrayViewBEGetAndBitwiseAndAcquireFloat...OK +ByteArrayViewBEGetAndBitwiseAndAcquireDouble...OK +ByteArrayViewBEGetAndBitwiseXorShort...OK +ByteArrayViewBEGetAndBitwiseXorChar...OK +ByteArrayViewBEGetAndBitwiseXorInt...OK +ByteArrayViewBEGetAndBitwiseXorLong...OK +ByteArrayViewBEGetAndBitwiseXorFloat...OK +ByteArrayViewBEGetAndBitwiseXorDouble...OK +ByteArrayViewBEGetAndBitwiseXorReleaseShort...OK +ByteArrayViewBEGetAndBitwiseXorReleaseChar...OK +ByteArrayViewBEGetAndBitwiseXorReleaseInt...OK +ByteArrayViewBEGetAndBitwiseXorReleaseLong...OK +ByteArrayViewBEGetAndBitwiseXorReleaseFloat...OK +ByteArrayViewBEGetAndBitwiseXorReleaseDouble...OK +ByteArrayViewBEGetAndBitwiseXorAcquireShort...OK +ByteArrayViewBEGetAndBitwiseXorAcquireChar...OK +ByteArrayViewBEGetAndBitwiseXorAcquireInt...OK +ByteArrayViewBEGetAndBitwiseXorAcquireLong...OK +ByteArrayViewBEGetAndBitwiseXorAcquireFloat...OK +ByteArrayViewBEGetAndBitwiseXorAcquireDouble...OK +DirectByteBufferViewLEGetShort...OK +DirectByteBufferViewLEGetChar...OK +DirectByteBufferViewLEGetInt...OK +DirectByteBufferViewLEGetLong...OK +DirectByteBufferViewLEGetFloat...OK +DirectByteBufferViewLEGetDouble...OK +DirectByteBufferViewLESetShort...OK +DirectByteBufferViewLESetChar...OK +DirectByteBufferViewLESetInt...OK +DirectByteBufferViewLESetLong...OK +DirectByteBufferViewLESetFloat...OK +DirectByteBufferViewLESetDouble...OK +DirectByteBufferViewLEGetVolatileShort...OK +DirectByteBufferViewLEGetVolatileChar...OK +DirectByteBufferViewLEGetVolatileInt...OK +DirectByteBufferViewLEGetVolatileLong...OK +DirectByteBufferViewLEGetVolatileFloat...OK +DirectByteBufferViewLEGetVolatileDouble...OK +DirectByteBufferViewLESetVolatileShort...OK +DirectByteBufferViewLESetVolatileChar...OK +DirectByteBufferViewLESetVolatileInt...OK +DirectByteBufferViewLESetVolatileLong...OK +DirectByteBufferViewLESetVolatileFloat...OK +DirectByteBufferViewLESetVolatileDouble...OK +DirectByteBufferViewLEGetAcquireShort...OK +DirectByteBufferViewLEGetAcquireChar...OK +DirectByteBufferViewLEGetAcquireInt...OK +DirectByteBufferViewLEGetAcquireLong...OK +DirectByteBufferViewLEGetAcquireFloat...OK +DirectByteBufferViewLEGetAcquireDouble...OK +DirectByteBufferViewLESetReleaseShort...OK +DirectByteBufferViewLESetReleaseChar...OK +DirectByteBufferViewLESetReleaseInt...OK +DirectByteBufferViewLESetReleaseLong...OK +DirectByteBufferViewLESetReleaseFloat...OK +DirectByteBufferViewLESetReleaseDouble...OK +DirectByteBufferViewLEGetOpaqueShort...OK +DirectByteBufferViewLEGetOpaqueChar...OK +DirectByteBufferViewLEGetOpaqueInt...OK +DirectByteBufferViewLEGetOpaqueLong...OK +DirectByteBufferViewLEGetOpaqueFloat...OK +DirectByteBufferViewLEGetOpaqueDouble...OK +DirectByteBufferViewLESetOpaqueShort...OK +DirectByteBufferViewLESetOpaqueChar...OK +DirectByteBufferViewLESetOpaqueInt...OK +DirectByteBufferViewLESetOpaqueLong...OK +DirectByteBufferViewLESetOpaqueFloat...OK +DirectByteBufferViewLESetOpaqueDouble...OK +DirectByteBufferViewLECompareAndSetShort...OK +DirectByteBufferViewLECompareAndSetChar...OK +DirectByteBufferViewLECompareAndSetInt...OK +DirectByteBufferViewLECompareAndSetLong...OK +DirectByteBufferViewLECompareAndSetFloat...OK +DirectByteBufferViewLECompareAndSetDouble...OK +DirectByteBufferViewLECompareAndExchangeShort...OK +DirectByteBufferViewLECompareAndExchangeChar...OK +DirectByteBufferViewLECompareAndExchangeInt...OK +DirectByteBufferViewLECompareAndExchangeLong...OK +DirectByteBufferViewLECompareAndExchangeFloat...OK +DirectByteBufferViewLECompareAndExchangeDouble...OK +DirectByteBufferViewLECompareAndExchangeAcquireShort...OK +DirectByteBufferViewLECompareAndExchangeAcquireChar...OK +DirectByteBufferViewLECompareAndExchangeAcquireInt...OK +DirectByteBufferViewLECompareAndExchangeAcquireLong...OK +DirectByteBufferViewLECompareAndExchangeAcquireFloat...OK +DirectByteBufferViewLECompareAndExchangeAcquireDouble...OK +DirectByteBufferViewLECompareAndExchangeReleaseShort...OK +DirectByteBufferViewLECompareAndExchangeReleaseChar...OK +DirectByteBufferViewLECompareAndExchangeReleaseInt...OK +DirectByteBufferViewLECompareAndExchangeReleaseLong...OK +DirectByteBufferViewLECompareAndExchangeReleaseFloat...OK +DirectByteBufferViewLECompareAndExchangeReleaseDouble...OK +DirectByteBufferViewLEWeakCompareAndSetPlainShort...OK +DirectByteBufferViewLEWeakCompareAndSetPlainChar...OK +DirectByteBufferViewLEWeakCompareAndSetPlainInt...OK +DirectByteBufferViewLEWeakCompareAndSetPlainLong...OK +DirectByteBufferViewLEWeakCompareAndSetPlainFloat...OK +DirectByteBufferViewLEWeakCompareAndSetPlainDouble...OK +DirectByteBufferViewLEWeakCompareAndSetShort...OK +DirectByteBufferViewLEWeakCompareAndSetChar...OK +DirectByteBufferViewLEWeakCompareAndSetInt...OK +DirectByteBufferViewLEWeakCompareAndSetLong...OK +DirectByteBufferViewLEWeakCompareAndSetFloat...OK +DirectByteBufferViewLEWeakCompareAndSetDouble...OK +DirectByteBufferViewLEWeakCompareAndSetAcquireShort...OK +DirectByteBufferViewLEWeakCompareAndSetAcquireChar...OK +DirectByteBufferViewLEWeakCompareAndSetAcquireInt...OK +DirectByteBufferViewLEWeakCompareAndSetAcquireLong...OK +DirectByteBufferViewLEWeakCompareAndSetAcquireFloat...OK +DirectByteBufferViewLEWeakCompareAndSetAcquireDouble...OK +DirectByteBufferViewLEWeakCompareAndSetReleaseShort...OK +DirectByteBufferViewLEWeakCompareAndSetReleaseChar...OK +DirectByteBufferViewLEWeakCompareAndSetReleaseInt...OK +DirectByteBufferViewLEWeakCompareAndSetReleaseLong...OK +DirectByteBufferViewLEWeakCompareAndSetReleaseFloat...OK +DirectByteBufferViewLEWeakCompareAndSetReleaseDouble...OK +DirectByteBufferViewLEGetAndSetShort...OK +DirectByteBufferViewLEGetAndSetChar...OK +DirectByteBufferViewLEGetAndSetInt...OK +DirectByteBufferViewLEGetAndSetLong...OK +DirectByteBufferViewLEGetAndSetFloat...OK +DirectByteBufferViewLEGetAndSetDouble...OK +DirectByteBufferViewLEGetAndSetAcquireShort...OK +DirectByteBufferViewLEGetAndSetAcquireChar...OK +DirectByteBufferViewLEGetAndSetAcquireInt...OK +DirectByteBufferViewLEGetAndSetAcquireLong...OK +DirectByteBufferViewLEGetAndSetAcquireFloat...OK +DirectByteBufferViewLEGetAndSetAcquireDouble...OK +DirectByteBufferViewLEGetAndSetReleaseShort...OK +DirectByteBufferViewLEGetAndSetReleaseChar...OK +DirectByteBufferViewLEGetAndSetReleaseInt...OK +DirectByteBufferViewLEGetAndSetReleaseLong...OK +DirectByteBufferViewLEGetAndSetReleaseFloat...OK +DirectByteBufferViewLEGetAndSetReleaseDouble...OK +DirectByteBufferViewLEGetAndAddShort...OK +DirectByteBufferViewLEGetAndAddChar...OK +DirectByteBufferViewLEGetAndAddInt...OK +DirectByteBufferViewLEGetAndAddLong...OK +DirectByteBufferViewLEGetAndAddFloat...OK +DirectByteBufferViewLEGetAndAddDouble...OK +DirectByteBufferViewLEGetAndAddAcquireShort...OK +DirectByteBufferViewLEGetAndAddAcquireChar...OK +DirectByteBufferViewLEGetAndAddAcquireInt...OK +DirectByteBufferViewLEGetAndAddAcquireLong...OK +DirectByteBufferViewLEGetAndAddAcquireFloat...OK +DirectByteBufferViewLEGetAndAddAcquireDouble...OK +DirectByteBufferViewLEGetAndAddReleaseShort...OK +DirectByteBufferViewLEGetAndAddReleaseChar...OK +DirectByteBufferViewLEGetAndAddReleaseInt...OK +DirectByteBufferViewLEGetAndAddReleaseLong...OK +DirectByteBufferViewLEGetAndAddReleaseFloat...OK +DirectByteBufferViewLEGetAndAddReleaseDouble...OK +DirectByteBufferViewLEGetAndBitwiseOrShort...OK +DirectByteBufferViewLEGetAndBitwiseOrChar...OK +DirectByteBufferViewLEGetAndBitwiseOrInt...OK +DirectByteBufferViewLEGetAndBitwiseOrLong...OK +DirectByteBufferViewLEGetAndBitwiseOrFloat...OK +DirectByteBufferViewLEGetAndBitwiseOrDouble...OK +DirectByteBufferViewLEGetAndBitwiseOrReleaseShort...OK +DirectByteBufferViewLEGetAndBitwiseOrReleaseChar...OK +DirectByteBufferViewLEGetAndBitwiseOrReleaseInt...OK +DirectByteBufferViewLEGetAndBitwiseOrReleaseLong...OK +DirectByteBufferViewLEGetAndBitwiseOrReleaseFloat...OK +DirectByteBufferViewLEGetAndBitwiseOrReleaseDouble...OK +DirectByteBufferViewLEGetAndBitwiseOrAcquireShort...OK +DirectByteBufferViewLEGetAndBitwiseOrAcquireChar...OK +DirectByteBufferViewLEGetAndBitwiseOrAcquireInt...OK +DirectByteBufferViewLEGetAndBitwiseOrAcquireLong...OK +DirectByteBufferViewLEGetAndBitwiseOrAcquireFloat...OK +DirectByteBufferViewLEGetAndBitwiseOrAcquireDouble...OK +DirectByteBufferViewLEGetAndBitwiseAndShort...OK +DirectByteBufferViewLEGetAndBitwiseAndChar...OK +DirectByteBufferViewLEGetAndBitwiseAndInt...OK +DirectByteBufferViewLEGetAndBitwiseAndLong...OK +DirectByteBufferViewLEGetAndBitwiseAndFloat...OK +DirectByteBufferViewLEGetAndBitwiseAndDouble...OK +DirectByteBufferViewLEGetAndBitwiseAndReleaseShort...OK +DirectByteBufferViewLEGetAndBitwiseAndReleaseChar...OK +DirectByteBufferViewLEGetAndBitwiseAndReleaseInt...OK +DirectByteBufferViewLEGetAndBitwiseAndReleaseLong...OK +DirectByteBufferViewLEGetAndBitwiseAndReleaseFloat...OK +DirectByteBufferViewLEGetAndBitwiseAndReleaseDouble...OK +DirectByteBufferViewLEGetAndBitwiseAndAcquireShort...OK +DirectByteBufferViewLEGetAndBitwiseAndAcquireChar...OK +DirectByteBufferViewLEGetAndBitwiseAndAcquireInt...OK +DirectByteBufferViewLEGetAndBitwiseAndAcquireLong...OK +DirectByteBufferViewLEGetAndBitwiseAndAcquireFloat...OK +DirectByteBufferViewLEGetAndBitwiseAndAcquireDouble...OK +DirectByteBufferViewLEGetAndBitwiseXorShort...OK +DirectByteBufferViewLEGetAndBitwiseXorChar...OK +DirectByteBufferViewLEGetAndBitwiseXorInt...OK +DirectByteBufferViewLEGetAndBitwiseXorLong...OK +DirectByteBufferViewLEGetAndBitwiseXorFloat...OK +DirectByteBufferViewLEGetAndBitwiseXorDouble...OK +DirectByteBufferViewLEGetAndBitwiseXorReleaseShort...OK +DirectByteBufferViewLEGetAndBitwiseXorReleaseChar...OK +DirectByteBufferViewLEGetAndBitwiseXorReleaseInt...OK +DirectByteBufferViewLEGetAndBitwiseXorReleaseLong...OK +DirectByteBufferViewLEGetAndBitwiseXorReleaseFloat...OK +DirectByteBufferViewLEGetAndBitwiseXorReleaseDouble...OK +DirectByteBufferViewLEGetAndBitwiseXorAcquireShort...OK +DirectByteBufferViewLEGetAndBitwiseXorAcquireChar...OK +DirectByteBufferViewLEGetAndBitwiseXorAcquireInt...OK +DirectByteBufferViewLEGetAndBitwiseXorAcquireLong...OK +DirectByteBufferViewLEGetAndBitwiseXorAcquireFloat...OK +DirectByteBufferViewLEGetAndBitwiseXorAcquireDouble...OK +DirectByteBufferViewBEGetShort...OK +DirectByteBufferViewBEGetChar...OK +DirectByteBufferViewBEGetInt...OK +DirectByteBufferViewBEGetLong...OK +DirectByteBufferViewBEGetFloat...OK +DirectByteBufferViewBEGetDouble...OK +DirectByteBufferViewBESetShort...OK +DirectByteBufferViewBESetChar...OK +DirectByteBufferViewBESetInt...OK +DirectByteBufferViewBESetLong...OK +DirectByteBufferViewBESetFloat...OK +DirectByteBufferViewBESetDouble...OK +DirectByteBufferViewBEGetVolatileShort...OK +DirectByteBufferViewBEGetVolatileChar...OK +DirectByteBufferViewBEGetVolatileInt...OK +DirectByteBufferViewBEGetVolatileLong...OK +DirectByteBufferViewBEGetVolatileFloat...OK +DirectByteBufferViewBEGetVolatileDouble...OK +DirectByteBufferViewBESetVolatileShort...OK +DirectByteBufferViewBESetVolatileChar...OK +DirectByteBufferViewBESetVolatileInt...OK +DirectByteBufferViewBESetVolatileLong...OK +DirectByteBufferViewBESetVolatileFloat...OK +DirectByteBufferViewBESetVolatileDouble...OK +DirectByteBufferViewBEGetAcquireShort...OK +DirectByteBufferViewBEGetAcquireChar...OK +DirectByteBufferViewBEGetAcquireInt...OK +DirectByteBufferViewBEGetAcquireLong...OK +DirectByteBufferViewBEGetAcquireFloat...OK +DirectByteBufferViewBEGetAcquireDouble...OK +DirectByteBufferViewBESetReleaseShort...OK +DirectByteBufferViewBESetReleaseChar...OK +DirectByteBufferViewBESetReleaseInt...OK +DirectByteBufferViewBESetReleaseLong...OK +DirectByteBufferViewBESetReleaseFloat...OK +DirectByteBufferViewBESetReleaseDouble...OK +DirectByteBufferViewBEGetOpaqueShort...OK +DirectByteBufferViewBEGetOpaqueChar...OK +DirectByteBufferViewBEGetOpaqueInt...OK +DirectByteBufferViewBEGetOpaqueLong...OK +DirectByteBufferViewBEGetOpaqueFloat...OK +DirectByteBufferViewBEGetOpaqueDouble...OK +DirectByteBufferViewBESetOpaqueShort...OK +DirectByteBufferViewBESetOpaqueChar...OK +DirectByteBufferViewBESetOpaqueInt...OK +DirectByteBufferViewBESetOpaqueLong...OK +DirectByteBufferViewBESetOpaqueFloat...OK +DirectByteBufferViewBESetOpaqueDouble...OK +DirectByteBufferViewBECompareAndSetShort...OK +DirectByteBufferViewBECompareAndSetChar...OK +DirectByteBufferViewBECompareAndSetInt...OK +DirectByteBufferViewBECompareAndSetLong...OK +DirectByteBufferViewBECompareAndSetFloat...OK +DirectByteBufferViewBECompareAndSetDouble...OK +DirectByteBufferViewBECompareAndExchangeShort...OK +DirectByteBufferViewBECompareAndExchangeChar...OK +DirectByteBufferViewBECompareAndExchangeInt...OK +DirectByteBufferViewBECompareAndExchangeLong...OK +DirectByteBufferViewBECompareAndExchangeFloat...OK +DirectByteBufferViewBECompareAndExchangeDouble...OK +DirectByteBufferViewBECompareAndExchangeAcquireShort...OK +DirectByteBufferViewBECompareAndExchangeAcquireChar...OK +DirectByteBufferViewBECompareAndExchangeAcquireInt...OK +DirectByteBufferViewBECompareAndExchangeAcquireLong...OK +DirectByteBufferViewBECompareAndExchangeAcquireFloat...OK +DirectByteBufferViewBECompareAndExchangeAcquireDouble...OK +DirectByteBufferViewBECompareAndExchangeReleaseShort...OK +DirectByteBufferViewBECompareAndExchangeReleaseChar...OK +DirectByteBufferViewBECompareAndExchangeReleaseInt...OK +DirectByteBufferViewBECompareAndExchangeReleaseLong...OK +DirectByteBufferViewBECompareAndExchangeReleaseFloat...OK +DirectByteBufferViewBECompareAndExchangeReleaseDouble...OK +DirectByteBufferViewBEWeakCompareAndSetPlainShort...OK +DirectByteBufferViewBEWeakCompareAndSetPlainChar...OK +DirectByteBufferViewBEWeakCompareAndSetPlainInt...OK +DirectByteBufferViewBEWeakCompareAndSetPlainLong...OK +DirectByteBufferViewBEWeakCompareAndSetPlainFloat...OK +DirectByteBufferViewBEWeakCompareAndSetPlainDouble...OK +DirectByteBufferViewBEWeakCompareAndSetShort...OK +DirectByteBufferViewBEWeakCompareAndSetChar...OK +DirectByteBufferViewBEWeakCompareAndSetInt...OK +DirectByteBufferViewBEWeakCompareAndSetLong...OK +DirectByteBufferViewBEWeakCompareAndSetFloat...OK +DirectByteBufferViewBEWeakCompareAndSetDouble...OK +DirectByteBufferViewBEWeakCompareAndSetAcquireShort...OK +DirectByteBufferViewBEWeakCompareAndSetAcquireChar...OK +DirectByteBufferViewBEWeakCompareAndSetAcquireInt...OK +DirectByteBufferViewBEWeakCompareAndSetAcquireLong...OK +DirectByteBufferViewBEWeakCompareAndSetAcquireFloat...OK +DirectByteBufferViewBEWeakCompareAndSetAcquireDouble...OK +DirectByteBufferViewBEWeakCompareAndSetReleaseShort...OK +DirectByteBufferViewBEWeakCompareAndSetReleaseChar...OK +DirectByteBufferViewBEWeakCompareAndSetReleaseInt...OK +DirectByteBufferViewBEWeakCompareAndSetReleaseLong...OK +DirectByteBufferViewBEWeakCompareAndSetReleaseFloat...OK +DirectByteBufferViewBEWeakCompareAndSetReleaseDouble...OK +DirectByteBufferViewBEGetAndSetShort...OK +DirectByteBufferViewBEGetAndSetChar...OK +DirectByteBufferViewBEGetAndSetInt...OK +DirectByteBufferViewBEGetAndSetLong...OK +DirectByteBufferViewBEGetAndSetFloat...OK +DirectByteBufferViewBEGetAndSetDouble...OK +DirectByteBufferViewBEGetAndSetAcquireShort...OK +DirectByteBufferViewBEGetAndSetAcquireChar...OK +DirectByteBufferViewBEGetAndSetAcquireInt...OK +DirectByteBufferViewBEGetAndSetAcquireLong...OK +DirectByteBufferViewBEGetAndSetAcquireFloat...OK +DirectByteBufferViewBEGetAndSetAcquireDouble...OK +DirectByteBufferViewBEGetAndSetReleaseShort...OK +DirectByteBufferViewBEGetAndSetReleaseChar...OK +DirectByteBufferViewBEGetAndSetReleaseInt...OK +DirectByteBufferViewBEGetAndSetReleaseLong...OK +DirectByteBufferViewBEGetAndSetReleaseFloat...OK +DirectByteBufferViewBEGetAndSetReleaseDouble...OK +DirectByteBufferViewBEGetAndAddShort...OK +DirectByteBufferViewBEGetAndAddChar...OK +DirectByteBufferViewBEGetAndAddInt...OK +DirectByteBufferViewBEGetAndAddLong...OK +DirectByteBufferViewBEGetAndAddFloat...OK +DirectByteBufferViewBEGetAndAddDouble...OK +DirectByteBufferViewBEGetAndAddAcquireShort...OK +DirectByteBufferViewBEGetAndAddAcquireChar...OK +DirectByteBufferViewBEGetAndAddAcquireInt...OK +DirectByteBufferViewBEGetAndAddAcquireLong...OK +DirectByteBufferViewBEGetAndAddAcquireFloat...OK +DirectByteBufferViewBEGetAndAddAcquireDouble...OK +DirectByteBufferViewBEGetAndAddReleaseShort...OK +DirectByteBufferViewBEGetAndAddReleaseChar...OK +DirectByteBufferViewBEGetAndAddReleaseInt...OK +DirectByteBufferViewBEGetAndAddReleaseLong...OK +DirectByteBufferViewBEGetAndAddReleaseFloat...OK +DirectByteBufferViewBEGetAndAddReleaseDouble...OK +DirectByteBufferViewBEGetAndBitwiseOrShort...OK +DirectByteBufferViewBEGetAndBitwiseOrChar...OK +DirectByteBufferViewBEGetAndBitwiseOrInt...OK +DirectByteBufferViewBEGetAndBitwiseOrLong...OK +DirectByteBufferViewBEGetAndBitwiseOrFloat...OK +DirectByteBufferViewBEGetAndBitwiseOrDouble...OK +DirectByteBufferViewBEGetAndBitwiseOrReleaseShort...OK +DirectByteBufferViewBEGetAndBitwiseOrReleaseChar...OK +DirectByteBufferViewBEGetAndBitwiseOrReleaseInt...OK +DirectByteBufferViewBEGetAndBitwiseOrReleaseLong...OK +DirectByteBufferViewBEGetAndBitwiseOrReleaseFloat...OK +DirectByteBufferViewBEGetAndBitwiseOrReleaseDouble...OK +DirectByteBufferViewBEGetAndBitwiseOrAcquireShort...OK +DirectByteBufferViewBEGetAndBitwiseOrAcquireChar...OK +DirectByteBufferViewBEGetAndBitwiseOrAcquireInt...OK +DirectByteBufferViewBEGetAndBitwiseOrAcquireLong...OK +DirectByteBufferViewBEGetAndBitwiseOrAcquireFloat...OK +DirectByteBufferViewBEGetAndBitwiseOrAcquireDouble...OK +DirectByteBufferViewBEGetAndBitwiseAndShort...OK +DirectByteBufferViewBEGetAndBitwiseAndChar...OK +DirectByteBufferViewBEGetAndBitwiseAndInt...OK +DirectByteBufferViewBEGetAndBitwiseAndLong...OK +DirectByteBufferViewBEGetAndBitwiseAndFloat...OK +DirectByteBufferViewBEGetAndBitwiseAndDouble...OK +DirectByteBufferViewBEGetAndBitwiseAndReleaseShort...OK +DirectByteBufferViewBEGetAndBitwiseAndReleaseChar...OK +DirectByteBufferViewBEGetAndBitwiseAndReleaseInt...OK +DirectByteBufferViewBEGetAndBitwiseAndReleaseLong...OK +DirectByteBufferViewBEGetAndBitwiseAndReleaseFloat...OK +DirectByteBufferViewBEGetAndBitwiseAndReleaseDouble...OK +DirectByteBufferViewBEGetAndBitwiseAndAcquireShort...OK +DirectByteBufferViewBEGetAndBitwiseAndAcquireChar...OK +DirectByteBufferViewBEGetAndBitwiseAndAcquireInt...OK +DirectByteBufferViewBEGetAndBitwiseAndAcquireLong...OK +DirectByteBufferViewBEGetAndBitwiseAndAcquireFloat...OK +DirectByteBufferViewBEGetAndBitwiseAndAcquireDouble...OK +DirectByteBufferViewBEGetAndBitwiseXorShort...OK +DirectByteBufferViewBEGetAndBitwiseXorChar...OK +DirectByteBufferViewBEGetAndBitwiseXorInt...OK +DirectByteBufferViewBEGetAndBitwiseXorLong...OK +DirectByteBufferViewBEGetAndBitwiseXorFloat...OK +DirectByteBufferViewBEGetAndBitwiseXorDouble...OK +DirectByteBufferViewBEGetAndBitwiseXorReleaseShort...OK +DirectByteBufferViewBEGetAndBitwiseXorReleaseChar...OK +DirectByteBufferViewBEGetAndBitwiseXorReleaseInt...OK +DirectByteBufferViewBEGetAndBitwiseXorReleaseLong...OK +DirectByteBufferViewBEGetAndBitwiseXorReleaseFloat...OK +DirectByteBufferViewBEGetAndBitwiseXorReleaseDouble...OK +DirectByteBufferViewBEGetAndBitwiseXorAcquireShort...OK +DirectByteBufferViewBEGetAndBitwiseXorAcquireChar...OK +DirectByteBufferViewBEGetAndBitwiseXorAcquireInt...OK +DirectByteBufferViewBEGetAndBitwiseXorAcquireLong...OK +DirectByteBufferViewBEGetAndBitwiseXorAcquireFloat...OK +DirectByteBufferViewBEGetAndBitwiseXorAcquireDouble...OK +HeapByteBufferViewLEGetShort...OK +HeapByteBufferViewLEGetChar...OK +HeapByteBufferViewLEGetInt...OK +HeapByteBufferViewLEGetLong...OK +HeapByteBufferViewLEGetFloat...OK +HeapByteBufferViewLEGetDouble...OK +HeapByteBufferViewLESetShort...OK +HeapByteBufferViewLESetChar...OK +HeapByteBufferViewLESetInt...OK +HeapByteBufferViewLESetLong...OK +HeapByteBufferViewLESetFloat...OK +HeapByteBufferViewLESetDouble...OK +HeapByteBufferViewLEGetVolatileShort...OK +HeapByteBufferViewLEGetVolatileChar...OK +HeapByteBufferViewLEGetVolatileInt...OK +HeapByteBufferViewLEGetVolatileLong...OK +HeapByteBufferViewLEGetVolatileFloat...OK +HeapByteBufferViewLEGetVolatileDouble...OK +HeapByteBufferViewLESetVolatileShort...OK +HeapByteBufferViewLESetVolatileChar...OK +HeapByteBufferViewLESetVolatileInt...OK +HeapByteBufferViewLESetVolatileLong...OK +HeapByteBufferViewLESetVolatileFloat...OK +HeapByteBufferViewLESetVolatileDouble...OK +HeapByteBufferViewLEGetAcquireShort...OK +HeapByteBufferViewLEGetAcquireChar...OK +HeapByteBufferViewLEGetAcquireInt...OK +HeapByteBufferViewLEGetAcquireLong...OK +HeapByteBufferViewLEGetAcquireFloat...OK +HeapByteBufferViewLEGetAcquireDouble...OK +HeapByteBufferViewLESetReleaseShort...OK +HeapByteBufferViewLESetReleaseChar...OK +HeapByteBufferViewLESetReleaseInt...OK +HeapByteBufferViewLESetReleaseLong...OK +HeapByteBufferViewLESetReleaseFloat...OK +HeapByteBufferViewLESetReleaseDouble...OK +HeapByteBufferViewLEGetOpaqueShort...OK +HeapByteBufferViewLEGetOpaqueChar...OK +HeapByteBufferViewLEGetOpaqueInt...OK +HeapByteBufferViewLEGetOpaqueLong...OK +HeapByteBufferViewLEGetOpaqueFloat...OK +HeapByteBufferViewLEGetOpaqueDouble...OK +HeapByteBufferViewLESetOpaqueShort...OK +HeapByteBufferViewLESetOpaqueChar...OK +HeapByteBufferViewLESetOpaqueInt...OK +HeapByteBufferViewLESetOpaqueLong...OK +HeapByteBufferViewLESetOpaqueFloat...OK +HeapByteBufferViewLESetOpaqueDouble...OK +HeapByteBufferViewLECompareAndSetShort...OK +HeapByteBufferViewLECompareAndSetChar...OK +HeapByteBufferViewLECompareAndSetInt...OK +HeapByteBufferViewLECompareAndSetLong...OK +HeapByteBufferViewLECompareAndSetFloat...OK +HeapByteBufferViewLECompareAndSetDouble...OK +HeapByteBufferViewLECompareAndExchangeShort...OK +HeapByteBufferViewLECompareAndExchangeChar...OK +HeapByteBufferViewLECompareAndExchangeInt...OK +HeapByteBufferViewLECompareAndExchangeLong...OK +HeapByteBufferViewLECompareAndExchangeFloat...OK +HeapByteBufferViewLECompareAndExchangeDouble...OK +HeapByteBufferViewLECompareAndExchangeAcquireShort...OK +HeapByteBufferViewLECompareAndExchangeAcquireChar...OK +HeapByteBufferViewLECompareAndExchangeAcquireInt...OK +HeapByteBufferViewLECompareAndExchangeAcquireLong...OK +HeapByteBufferViewLECompareAndExchangeAcquireFloat...OK +HeapByteBufferViewLECompareAndExchangeAcquireDouble...OK +HeapByteBufferViewLECompareAndExchangeReleaseShort...OK +HeapByteBufferViewLECompareAndExchangeReleaseChar...OK +HeapByteBufferViewLECompareAndExchangeReleaseInt...OK +HeapByteBufferViewLECompareAndExchangeReleaseLong...OK +HeapByteBufferViewLECompareAndExchangeReleaseFloat...OK +HeapByteBufferViewLECompareAndExchangeReleaseDouble...OK +HeapByteBufferViewLEWeakCompareAndSetPlainShort...OK +HeapByteBufferViewLEWeakCompareAndSetPlainChar...OK +HeapByteBufferViewLEWeakCompareAndSetPlainInt...OK +HeapByteBufferViewLEWeakCompareAndSetPlainLong...OK +HeapByteBufferViewLEWeakCompareAndSetPlainFloat...OK +HeapByteBufferViewLEWeakCompareAndSetPlainDouble...OK +HeapByteBufferViewLEWeakCompareAndSetShort...OK +HeapByteBufferViewLEWeakCompareAndSetChar...OK +HeapByteBufferViewLEWeakCompareAndSetInt...OK +HeapByteBufferViewLEWeakCompareAndSetLong...OK +HeapByteBufferViewLEWeakCompareAndSetFloat...OK +HeapByteBufferViewLEWeakCompareAndSetDouble...OK +HeapByteBufferViewLEWeakCompareAndSetAcquireShort...OK +HeapByteBufferViewLEWeakCompareAndSetAcquireChar...OK +HeapByteBufferViewLEWeakCompareAndSetAcquireInt...OK +HeapByteBufferViewLEWeakCompareAndSetAcquireLong...OK +HeapByteBufferViewLEWeakCompareAndSetAcquireFloat...OK +HeapByteBufferViewLEWeakCompareAndSetAcquireDouble...OK +HeapByteBufferViewLEWeakCompareAndSetReleaseShort...OK +HeapByteBufferViewLEWeakCompareAndSetReleaseChar...OK +HeapByteBufferViewLEWeakCompareAndSetReleaseInt...OK +HeapByteBufferViewLEWeakCompareAndSetReleaseLong...OK +HeapByteBufferViewLEWeakCompareAndSetReleaseFloat...OK +HeapByteBufferViewLEWeakCompareAndSetReleaseDouble...OK +HeapByteBufferViewLEGetAndSetShort...OK +HeapByteBufferViewLEGetAndSetChar...OK +HeapByteBufferViewLEGetAndSetInt...OK +HeapByteBufferViewLEGetAndSetLong...OK +HeapByteBufferViewLEGetAndSetFloat...OK +HeapByteBufferViewLEGetAndSetDouble...OK +HeapByteBufferViewLEGetAndSetAcquireShort...OK +HeapByteBufferViewLEGetAndSetAcquireChar...OK +HeapByteBufferViewLEGetAndSetAcquireInt...OK +HeapByteBufferViewLEGetAndSetAcquireLong...OK +HeapByteBufferViewLEGetAndSetAcquireFloat...OK +HeapByteBufferViewLEGetAndSetAcquireDouble...OK +HeapByteBufferViewLEGetAndSetReleaseShort...OK +HeapByteBufferViewLEGetAndSetReleaseChar...OK +HeapByteBufferViewLEGetAndSetReleaseInt...OK +HeapByteBufferViewLEGetAndSetReleaseLong...OK +HeapByteBufferViewLEGetAndSetReleaseFloat...OK +HeapByteBufferViewLEGetAndSetReleaseDouble...OK +HeapByteBufferViewLEGetAndAddShort...OK +HeapByteBufferViewLEGetAndAddChar...OK +HeapByteBufferViewLEGetAndAddInt...OK +HeapByteBufferViewLEGetAndAddLong...OK +HeapByteBufferViewLEGetAndAddFloat...OK +HeapByteBufferViewLEGetAndAddDouble...OK +HeapByteBufferViewLEGetAndAddAcquireShort...OK +HeapByteBufferViewLEGetAndAddAcquireChar...OK +HeapByteBufferViewLEGetAndAddAcquireInt...OK +HeapByteBufferViewLEGetAndAddAcquireLong...OK +HeapByteBufferViewLEGetAndAddAcquireFloat...OK +HeapByteBufferViewLEGetAndAddAcquireDouble...OK +HeapByteBufferViewLEGetAndAddReleaseShort...OK +HeapByteBufferViewLEGetAndAddReleaseChar...OK +HeapByteBufferViewLEGetAndAddReleaseInt...OK +HeapByteBufferViewLEGetAndAddReleaseLong...OK +HeapByteBufferViewLEGetAndAddReleaseFloat...OK +HeapByteBufferViewLEGetAndAddReleaseDouble...OK +HeapByteBufferViewLEGetAndBitwiseOrShort...OK +HeapByteBufferViewLEGetAndBitwiseOrChar...OK +HeapByteBufferViewLEGetAndBitwiseOrInt...OK +HeapByteBufferViewLEGetAndBitwiseOrLong...OK +HeapByteBufferViewLEGetAndBitwiseOrFloat...OK +HeapByteBufferViewLEGetAndBitwiseOrDouble...OK +HeapByteBufferViewLEGetAndBitwiseOrReleaseShort...OK +HeapByteBufferViewLEGetAndBitwiseOrReleaseChar...OK +HeapByteBufferViewLEGetAndBitwiseOrReleaseInt...OK +HeapByteBufferViewLEGetAndBitwiseOrReleaseLong...OK +HeapByteBufferViewLEGetAndBitwiseOrReleaseFloat...OK +HeapByteBufferViewLEGetAndBitwiseOrReleaseDouble...OK +HeapByteBufferViewLEGetAndBitwiseOrAcquireShort...OK +HeapByteBufferViewLEGetAndBitwiseOrAcquireChar...OK +HeapByteBufferViewLEGetAndBitwiseOrAcquireInt...OK +HeapByteBufferViewLEGetAndBitwiseOrAcquireLong...OK +HeapByteBufferViewLEGetAndBitwiseOrAcquireFloat...OK +HeapByteBufferViewLEGetAndBitwiseOrAcquireDouble...OK +HeapByteBufferViewLEGetAndBitwiseAndShort...OK +HeapByteBufferViewLEGetAndBitwiseAndChar...OK +HeapByteBufferViewLEGetAndBitwiseAndInt...OK +HeapByteBufferViewLEGetAndBitwiseAndLong...OK +HeapByteBufferViewLEGetAndBitwiseAndFloat...OK +HeapByteBufferViewLEGetAndBitwiseAndDouble...OK +HeapByteBufferViewLEGetAndBitwiseAndReleaseShort...OK +HeapByteBufferViewLEGetAndBitwiseAndReleaseChar...OK +HeapByteBufferViewLEGetAndBitwiseAndReleaseInt...OK +HeapByteBufferViewLEGetAndBitwiseAndReleaseLong...OK +HeapByteBufferViewLEGetAndBitwiseAndReleaseFloat...OK +HeapByteBufferViewLEGetAndBitwiseAndReleaseDouble...OK +HeapByteBufferViewLEGetAndBitwiseAndAcquireShort...OK +HeapByteBufferViewLEGetAndBitwiseAndAcquireChar...OK +HeapByteBufferViewLEGetAndBitwiseAndAcquireInt...OK +HeapByteBufferViewLEGetAndBitwiseAndAcquireLong...OK +HeapByteBufferViewLEGetAndBitwiseAndAcquireFloat...OK +HeapByteBufferViewLEGetAndBitwiseAndAcquireDouble...OK +HeapByteBufferViewLEGetAndBitwiseXorShort...OK +HeapByteBufferViewLEGetAndBitwiseXorChar...OK +HeapByteBufferViewLEGetAndBitwiseXorInt...OK +HeapByteBufferViewLEGetAndBitwiseXorLong...OK +HeapByteBufferViewLEGetAndBitwiseXorFloat...OK +HeapByteBufferViewLEGetAndBitwiseXorDouble...OK +HeapByteBufferViewLEGetAndBitwiseXorReleaseShort...OK +HeapByteBufferViewLEGetAndBitwiseXorReleaseChar...OK +HeapByteBufferViewLEGetAndBitwiseXorReleaseInt...OK +HeapByteBufferViewLEGetAndBitwiseXorReleaseLong...OK +HeapByteBufferViewLEGetAndBitwiseXorReleaseFloat...OK +HeapByteBufferViewLEGetAndBitwiseXorReleaseDouble...OK +HeapByteBufferViewLEGetAndBitwiseXorAcquireShort...OK +HeapByteBufferViewLEGetAndBitwiseXorAcquireChar...OK +HeapByteBufferViewLEGetAndBitwiseXorAcquireInt...OK +HeapByteBufferViewLEGetAndBitwiseXorAcquireLong...OK +HeapByteBufferViewLEGetAndBitwiseXorAcquireFloat...OK +HeapByteBufferViewLEGetAndBitwiseXorAcquireDouble...OK +HeapByteBufferViewBEGetShort...OK +HeapByteBufferViewBEGetChar...OK +HeapByteBufferViewBEGetInt...OK +HeapByteBufferViewBEGetLong...OK +HeapByteBufferViewBEGetFloat...OK +HeapByteBufferViewBEGetDouble...OK +HeapByteBufferViewBESetShort...OK +HeapByteBufferViewBESetChar...OK +HeapByteBufferViewBESetInt...OK +HeapByteBufferViewBESetLong...OK +HeapByteBufferViewBESetFloat...OK +HeapByteBufferViewBESetDouble...OK +HeapByteBufferViewBEGetVolatileShort...OK +HeapByteBufferViewBEGetVolatileChar...OK +HeapByteBufferViewBEGetVolatileInt...OK +HeapByteBufferViewBEGetVolatileLong...OK +HeapByteBufferViewBEGetVolatileFloat...OK +HeapByteBufferViewBEGetVolatileDouble...OK +HeapByteBufferViewBESetVolatileShort...OK +HeapByteBufferViewBESetVolatileChar...OK +HeapByteBufferViewBESetVolatileInt...OK +HeapByteBufferViewBESetVolatileLong...OK +HeapByteBufferViewBESetVolatileFloat...OK +HeapByteBufferViewBESetVolatileDouble...OK +HeapByteBufferViewBEGetAcquireShort...OK +HeapByteBufferViewBEGetAcquireChar...OK +HeapByteBufferViewBEGetAcquireInt...OK +HeapByteBufferViewBEGetAcquireLong...OK +HeapByteBufferViewBEGetAcquireFloat...OK +HeapByteBufferViewBEGetAcquireDouble...OK +HeapByteBufferViewBESetReleaseShort...OK +HeapByteBufferViewBESetReleaseChar...OK +HeapByteBufferViewBESetReleaseInt...OK +HeapByteBufferViewBESetReleaseLong...OK +HeapByteBufferViewBESetReleaseFloat...OK +HeapByteBufferViewBESetReleaseDouble...OK +HeapByteBufferViewBEGetOpaqueShort...OK +HeapByteBufferViewBEGetOpaqueChar...OK +HeapByteBufferViewBEGetOpaqueInt...OK +HeapByteBufferViewBEGetOpaqueLong...OK +HeapByteBufferViewBEGetOpaqueFloat...OK +HeapByteBufferViewBEGetOpaqueDouble...OK +HeapByteBufferViewBESetOpaqueShort...OK +HeapByteBufferViewBESetOpaqueChar...OK +HeapByteBufferViewBESetOpaqueInt...OK +HeapByteBufferViewBESetOpaqueLong...OK +HeapByteBufferViewBESetOpaqueFloat...OK +HeapByteBufferViewBESetOpaqueDouble...OK +HeapByteBufferViewBECompareAndSetShort...OK +HeapByteBufferViewBECompareAndSetChar...OK +HeapByteBufferViewBECompareAndSetInt...OK +HeapByteBufferViewBECompareAndSetLong...OK +HeapByteBufferViewBECompareAndSetFloat...OK +HeapByteBufferViewBECompareAndSetDouble...OK +HeapByteBufferViewBECompareAndExchangeShort...OK +HeapByteBufferViewBECompareAndExchangeChar...OK +HeapByteBufferViewBECompareAndExchangeInt...OK +HeapByteBufferViewBECompareAndExchangeLong...OK +HeapByteBufferViewBECompareAndExchangeFloat...OK +HeapByteBufferViewBECompareAndExchangeDouble...OK +HeapByteBufferViewBECompareAndExchangeAcquireShort...OK +HeapByteBufferViewBECompareAndExchangeAcquireChar...OK +HeapByteBufferViewBECompareAndExchangeAcquireInt...OK +HeapByteBufferViewBECompareAndExchangeAcquireLong...OK +HeapByteBufferViewBECompareAndExchangeAcquireFloat...OK +HeapByteBufferViewBECompareAndExchangeAcquireDouble...OK +HeapByteBufferViewBECompareAndExchangeReleaseShort...OK +HeapByteBufferViewBECompareAndExchangeReleaseChar...OK +HeapByteBufferViewBECompareAndExchangeReleaseInt...OK +HeapByteBufferViewBECompareAndExchangeReleaseLong...OK +HeapByteBufferViewBECompareAndExchangeReleaseFloat...OK +HeapByteBufferViewBECompareAndExchangeReleaseDouble...OK +HeapByteBufferViewBEWeakCompareAndSetPlainShort...OK +HeapByteBufferViewBEWeakCompareAndSetPlainChar...OK +HeapByteBufferViewBEWeakCompareAndSetPlainInt...OK +HeapByteBufferViewBEWeakCompareAndSetPlainLong...OK +HeapByteBufferViewBEWeakCompareAndSetPlainFloat...OK +HeapByteBufferViewBEWeakCompareAndSetPlainDouble...OK +HeapByteBufferViewBEWeakCompareAndSetShort...OK +HeapByteBufferViewBEWeakCompareAndSetChar...OK +HeapByteBufferViewBEWeakCompareAndSetInt...OK +HeapByteBufferViewBEWeakCompareAndSetLong...OK +HeapByteBufferViewBEWeakCompareAndSetFloat...OK +HeapByteBufferViewBEWeakCompareAndSetDouble...OK +HeapByteBufferViewBEWeakCompareAndSetAcquireShort...OK +HeapByteBufferViewBEWeakCompareAndSetAcquireChar...OK +HeapByteBufferViewBEWeakCompareAndSetAcquireInt...OK +HeapByteBufferViewBEWeakCompareAndSetAcquireLong...OK +HeapByteBufferViewBEWeakCompareAndSetAcquireFloat...OK +HeapByteBufferViewBEWeakCompareAndSetAcquireDouble...OK +HeapByteBufferViewBEWeakCompareAndSetReleaseShort...OK +HeapByteBufferViewBEWeakCompareAndSetReleaseChar...OK +HeapByteBufferViewBEWeakCompareAndSetReleaseInt...OK +HeapByteBufferViewBEWeakCompareAndSetReleaseLong...OK +HeapByteBufferViewBEWeakCompareAndSetReleaseFloat...OK +HeapByteBufferViewBEWeakCompareAndSetReleaseDouble...OK +HeapByteBufferViewBEGetAndSetShort...OK +HeapByteBufferViewBEGetAndSetChar...OK +HeapByteBufferViewBEGetAndSetInt...OK +HeapByteBufferViewBEGetAndSetLong...OK +HeapByteBufferViewBEGetAndSetFloat...OK +HeapByteBufferViewBEGetAndSetDouble...OK +HeapByteBufferViewBEGetAndSetAcquireShort...OK +HeapByteBufferViewBEGetAndSetAcquireChar...OK +HeapByteBufferViewBEGetAndSetAcquireInt...OK +HeapByteBufferViewBEGetAndSetAcquireLong...OK +HeapByteBufferViewBEGetAndSetAcquireFloat...OK +HeapByteBufferViewBEGetAndSetAcquireDouble...OK +HeapByteBufferViewBEGetAndSetReleaseShort...OK +HeapByteBufferViewBEGetAndSetReleaseChar...OK +HeapByteBufferViewBEGetAndSetReleaseInt...OK +HeapByteBufferViewBEGetAndSetReleaseLong...OK +HeapByteBufferViewBEGetAndSetReleaseFloat...OK +HeapByteBufferViewBEGetAndSetReleaseDouble...OK +HeapByteBufferViewBEGetAndAddShort...OK +HeapByteBufferViewBEGetAndAddChar...OK +HeapByteBufferViewBEGetAndAddInt...OK +HeapByteBufferViewBEGetAndAddLong...OK +HeapByteBufferViewBEGetAndAddFloat...OK +HeapByteBufferViewBEGetAndAddDouble...OK +HeapByteBufferViewBEGetAndAddAcquireShort...OK +HeapByteBufferViewBEGetAndAddAcquireChar...OK +HeapByteBufferViewBEGetAndAddAcquireInt...OK +HeapByteBufferViewBEGetAndAddAcquireLong...OK +HeapByteBufferViewBEGetAndAddAcquireFloat...OK +HeapByteBufferViewBEGetAndAddAcquireDouble...OK +HeapByteBufferViewBEGetAndAddReleaseShort...OK +HeapByteBufferViewBEGetAndAddReleaseChar...OK +HeapByteBufferViewBEGetAndAddReleaseInt...OK +HeapByteBufferViewBEGetAndAddReleaseLong...OK +HeapByteBufferViewBEGetAndAddReleaseFloat...OK +HeapByteBufferViewBEGetAndAddReleaseDouble...OK +HeapByteBufferViewBEGetAndBitwiseOrShort...OK +HeapByteBufferViewBEGetAndBitwiseOrChar...OK +HeapByteBufferViewBEGetAndBitwiseOrInt...OK +HeapByteBufferViewBEGetAndBitwiseOrLong...OK +HeapByteBufferViewBEGetAndBitwiseOrFloat...OK +HeapByteBufferViewBEGetAndBitwiseOrDouble...OK +HeapByteBufferViewBEGetAndBitwiseOrReleaseShort...OK +HeapByteBufferViewBEGetAndBitwiseOrReleaseChar...OK +HeapByteBufferViewBEGetAndBitwiseOrReleaseInt...OK +HeapByteBufferViewBEGetAndBitwiseOrReleaseLong...OK +HeapByteBufferViewBEGetAndBitwiseOrReleaseFloat...OK +HeapByteBufferViewBEGetAndBitwiseOrReleaseDouble...OK +HeapByteBufferViewBEGetAndBitwiseOrAcquireShort...OK +HeapByteBufferViewBEGetAndBitwiseOrAcquireChar...OK +HeapByteBufferViewBEGetAndBitwiseOrAcquireInt...OK +HeapByteBufferViewBEGetAndBitwiseOrAcquireLong...OK +HeapByteBufferViewBEGetAndBitwiseOrAcquireFloat...OK +HeapByteBufferViewBEGetAndBitwiseOrAcquireDouble...OK +HeapByteBufferViewBEGetAndBitwiseAndShort...OK +HeapByteBufferViewBEGetAndBitwiseAndChar...OK +HeapByteBufferViewBEGetAndBitwiseAndInt...OK +HeapByteBufferViewBEGetAndBitwiseAndLong...OK +HeapByteBufferViewBEGetAndBitwiseAndFloat...OK +HeapByteBufferViewBEGetAndBitwiseAndDouble...OK +HeapByteBufferViewBEGetAndBitwiseAndReleaseShort...OK +HeapByteBufferViewBEGetAndBitwiseAndReleaseChar...OK +HeapByteBufferViewBEGetAndBitwiseAndReleaseInt...OK +HeapByteBufferViewBEGetAndBitwiseAndReleaseLong...OK +HeapByteBufferViewBEGetAndBitwiseAndReleaseFloat...OK +HeapByteBufferViewBEGetAndBitwiseAndReleaseDouble...OK +HeapByteBufferViewBEGetAndBitwiseAndAcquireShort...OK +HeapByteBufferViewBEGetAndBitwiseAndAcquireChar...OK +HeapByteBufferViewBEGetAndBitwiseAndAcquireInt...OK +HeapByteBufferViewBEGetAndBitwiseAndAcquireLong...OK +HeapByteBufferViewBEGetAndBitwiseAndAcquireFloat...OK +HeapByteBufferViewBEGetAndBitwiseAndAcquireDouble...OK +HeapByteBufferViewBEGetAndBitwiseXorShort...OK +HeapByteBufferViewBEGetAndBitwiseXorChar...OK +HeapByteBufferViewBEGetAndBitwiseXorInt...OK +HeapByteBufferViewBEGetAndBitwiseXorLong...OK +HeapByteBufferViewBEGetAndBitwiseXorFloat...OK +HeapByteBufferViewBEGetAndBitwiseXorDouble...OK +HeapByteBufferViewBEGetAndBitwiseXorReleaseShort...OK +HeapByteBufferViewBEGetAndBitwiseXorReleaseChar...OK +HeapByteBufferViewBEGetAndBitwiseXorReleaseInt...OK +HeapByteBufferViewBEGetAndBitwiseXorReleaseLong...OK +HeapByteBufferViewBEGetAndBitwiseXorReleaseFloat...OK +HeapByteBufferViewBEGetAndBitwiseXorReleaseDouble...OK +HeapByteBufferViewBEGetAndBitwiseXorAcquireShort...OK +HeapByteBufferViewBEGetAndBitwiseXorAcquireChar...OK +HeapByteBufferViewBEGetAndBitwiseXorAcquireInt...OK +HeapByteBufferViewBEGetAndBitwiseXorAcquireLong...OK +HeapByteBufferViewBEGetAndBitwiseXorAcquireFloat...OK +HeapByteBufferViewBEGetAndBitwiseXorAcquireDouble...OK +HeapByteBufferReadOnlyViewLEGetShort...OK +HeapByteBufferReadOnlyViewLEGetChar...OK +HeapByteBufferReadOnlyViewLEGetInt...OK +HeapByteBufferReadOnlyViewLEGetLong...OK +HeapByteBufferReadOnlyViewLEGetFloat...OK +HeapByteBufferReadOnlyViewLEGetDouble...OK +HeapByteBufferReadOnlyViewLESetShort...OK +HeapByteBufferReadOnlyViewLESetChar...OK +HeapByteBufferReadOnlyViewLESetInt...OK +HeapByteBufferReadOnlyViewLESetLong...OK +HeapByteBufferReadOnlyViewLESetFloat...OK +HeapByteBufferReadOnlyViewLESetDouble...OK +HeapByteBufferReadOnlyViewLEGetVolatileShort...OK +HeapByteBufferReadOnlyViewLEGetVolatileChar...OK +HeapByteBufferReadOnlyViewLEGetVolatileInt...OK +HeapByteBufferReadOnlyViewLEGetVolatileLong...OK +HeapByteBufferReadOnlyViewLEGetVolatileFloat...OK +HeapByteBufferReadOnlyViewLEGetVolatileDouble...OK +HeapByteBufferReadOnlyViewLESetVolatileShort...OK +HeapByteBufferReadOnlyViewLESetVolatileChar...OK +HeapByteBufferReadOnlyViewLESetVolatileInt...OK +HeapByteBufferReadOnlyViewLESetVolatileLong...OK +HeapByteBufferReadOnlyViewLESetVolatileFloat...OK +HeapByteBufferReadOnlyViewLESetVolatileDouble...OK +HeapByteBufferReadOnlyViewLEGetAcquireShort...OK +HeapByteBufferReadOnlyViewLEGetAcquireChar...OK +HeapByteBufferReadOnlyViewLEGetAcquireInt...OK +HeapByteBufferReadOnlyViewLEGetAcquireLong...OK +HeapByteBufferReadOnlyViewLEGetAcquireFloat...OK +HeapByteBufferReadOnlyViewLEGetAcquireDouble...OK +HeapByteBufferReadOnlyViewLESetReleaseShort...OK +HeapByteBufferReadOnlyViewLESetReleaseChar...OK +HeapByteBufferReadOnlyViewLESetReleaseInt...OK +HeapByteBufferReadOnlyViewLESetReleaseLong...OK +HeapByteBufferReadOnlyViewLESetReleaseFloat...OK +HeapByteBufferReadOnlyViewLESetReleaseDouble...OK +HeapByteBufferReadOnlyViewLEGetOpaqueShort...OK +HeapByteBufferReadOnlyViewLEGetOpaqueChar...OK +HeapByteBufferReadOnlyViewLEGetOpaqueInt...OK +HeapByteBufferReadOnlyViewLEGetOpaqueLong...OK +HeapByteBufferReadOnlyViewLEGetOpaqueFloat...OK +HeapByteBufferReadOnlyViewLEGetOpaqueDouble...OK +HeapByteBufferReadOnlyViewLESetOpaqueShort...OK +HeapByteBufferReadOnlyViewLESetOpaqueChar...OK +HeapByteBufferReadOnlyViewLESetOpaqueInt...OK +HeapByteBufferReadOnlyViewLESetOpaqueLong...OK +HeapByteBufferReadOnlyViewLESetOpaqueFloat...OK +HeapByteBufferReadOnlyViewLESetOpaqueDouble...OK +HeapByteBufferReadOnlyViewLECompareAndSetShort...OK +HeapByteBufferReadOnlyViewLECompareAndSetChar...OK +HeapByteBufferReadOnlyViewLECompareAndSetInt...OK +HeapByteBufferReadOnlyViewLECompareAndSetLong...OK +HeapByteBufferReadOnlyViewLECompareAndSetFloat...OK +HeapByteBufferReadOnlyViewLECompareAndSetDouble...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeShort...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeChar...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeInt...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeLong...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeFloat...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeDouble...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeAcquireShort...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeAcquireChar...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeAcquireInt...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeAcquireLong...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeAcquireFloat...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeAcquireDouble...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeReleaseShort...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeReleaseChar...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeReleaseInt...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeReleaseLong...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeReleaseFloat...OK +HeapByteBufferReadOnlyViewLECompareAndExchangeReleaseDouble...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetPlainShort...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetPlainChar...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetPlainInt...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetPlainLong...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetPlainFloat...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetPlainDouble...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetShort...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetChar...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetInt...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetLong...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetFloat...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetDouble...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetAcquireShort...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetAcquireChar...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetAcquireInt...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetAcquireLong...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetAcquireFloat...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetAcquireDouble...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetReleaseShort...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetReleaseChar...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetReleaseInt...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetReleaseLong...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetReleaseFloat...OK +HeapByteBufferReadOnlyViewLEWeakCompareAndSetReleaseDouble...OK +HeapByteBufferReadOnlyViewLEGetAndSetShort...OK +HeapByteBufferReadOnlyViewLEGetAndSetChar...OK +HeapByteBufferReadOnlyViewLEGetAndSetInt...OK +HeapByteBufferReadOnlyViewLEGetAndSetLong...OK +HeapByteBufferReadOnlyViewLEGetAndSetFloat...OK +HeapByteBufferReadOnlyViewLEGetAndSetDouble...OK +HeapByteBufferReadOnlyViewLEGetAndSetAcquireShort...OK +HeapByteBufferReadOnlyViewLEGetAndSetAcquireChar...OK +HeapByteBufferReadOnlyViewLEGetAndSetAcquireInt...OK +HeapByteBufferReadOnlyViewLEGetAndSetAcquireLong...OK +HeapByteBufferReadOnlyViewLEGetAndSetAcquireFloat...OK +HeapByteBufferReadOnlyViewLEGetAndSetAcquireDouble...OK +HeapByteBufferReadOnlyViewLEGetAndSetReleaseShort...OK +HeapByteBufferReadOnlyViewLEGetAndSetReleaseChar...OK +HeapByteBufferReadOnlyViewLEGetAndSetReleaseInt...OK +HeapByteBufferReadOnlyViewLEGetAndSetReleaseLong...OK +HeapByteBufferReadOnlyViewLEGetAndSetReleaseFloat...OK +HeapByteBufferReadOnlyViewLEGetAndSetReleaseDouble...OK +HeapByteBufferReadOnlyViewLEGetAndAddShort...OK +HeapByteBufferReadOnlyViewLEGetAndAddChar...OK +HeapByteBufferReadOnlyViewLEGetAndAddInt...OK +HeapByteBufferReadOnlyViewLEGetAndAddLong...OK +HeapByteBufferReadOnlyViewLEGetAndAddFloat...OK +HeapByteBufferReadOnlyViewLEGetAndAddDouble...OK +HeapByteBufferReadOnlyViewLEGetAndAddAcquireShort...OK +HeapByteBufferReadOnlyViewLEGetAndAddAcquireChar...OK +HeapByteBufferReadOnlyViewLEGetAndAddAcquireInt...OK +HeapByteBufferReadOnlyViewLEGetAndAddAcquireLong...OK +HeapByteBufferReadOnlyViewLEGetAndAddAcquireFloat...OK +HeapByteBufferReadOnlyViewLEGetAndAddAcquireDouble...OK +HeapByteBufferReadOnlyViewLEGetAndAddReleaseShort...OK +HeapByteBufferReadOnlyViewLEGetAndAddReleaseChar...OK +HeapByteBufferReadOnlyViewLEGetAndAddReleaseInt...OK +HeapByteBufferReadOnlyViewLEGetAndAddReleaseLong...OK +HeapByteBufferReadOnlyViewLEGetAndAddReleaseFloat...OK +HeapByteBufferReadOnlyViewLEGetAndAddReleaseDouble...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrShort...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrChar...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrInt...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrLong...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrFloat...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrDouble...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrReleaseShort...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrReleaseChar...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrReleaseInt...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrReleaseLong...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrReleaseFloat...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrReleaseDouble...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrAcquireShort...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrAcquireChar...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrAcquireInt...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrAcquireLong...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrAcquireFloat...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseOrAcquireDouble...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndShort...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndChar...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndInt...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndLong...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndFloat...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndDouble...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndReleaseShort...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndReleaseChar...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndReleaseInt...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndReleaseLong...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndReleaseFloat...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndReleaseDouble...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndAcquireShort...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndAcquireChar...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndAcquireInt...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndAcquireLong...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndAcquireFloat...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseAndAcquireDouble...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorShort...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorChar...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorInt...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorLong...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorFloat...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorDouble...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorReleaseShort...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorReleaseChar...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorReleaseInt...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorReleaseLong...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorReleaseFloat...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorReleaseDouble...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorAcquireShort...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorAcquireChar...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorAcquireInt...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorAcquireLong...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorAcquireFloat...OK +HeapByteBufferReadOnlyViewLEGetAndBitwiseXorAcquireDouble...OK +HeapByteBufferReadOnlyViewBEGetShort...OK +HeapByteBufferReadOnlyViewBEGetChar...OK +HeapByteBufferReadOnlyViewBEGetInt...OK +HeapByteBufferReadOnlyViewBEGetLong...OK +HeapByteBufferReadOnlyViewBEGetFloat...OK +HeapByteBufferReadOnlyViewBEGetDouble...OK +HeapByteBufferReadOnlyViewBESetShort...OK +HeapByteBufferReadOnlyViewBESetChar...OK +HeapByteBufferReadOnlyViewBESetInt...OK +HeapByteBufferReadOnlyViewBESetLong...OK +HeapByteBufferReadOnlyViewBESetFloat...OK +HeapByteBufferReadOnlyViewBESetDouble...OK +HeapByteBufferReadOnlyViewBEGetVolatileShort...OK +HeapByteBufferReadOnlyViewBEGetVolatileChar...OK +HeapByteBufferReadOnlyViewBEGetVolatileInt...OK +HeapByteBufferReadOnlyViewBEGetVolatileLong...OK +HeapByteBufferReadOnlyViewBEGetVolatileFloat...OK +HeapByteBufferReadOnlyViewBEGetVolatileDouble...OK +HeapByteBufferReadOnlyViewBESetVolatileShort...OK +HeapByteBufferReadOnlyViewBESetVolatileChar...OK +HeapByteBufferReadOnlyViewBESetVolatileInt...OK +HeapByteBufferReadOnlyViewBESetVolatileLong...OK +HeapByteBufferReadOnlyViewBESetVolatileFloat...OK +HeapByteBufferReadOnlyViewBESetVolatileDouble...OK +HeapByteBufferReadOnlyViewBEGetAcquireShort...OK +HeapByteBufferReadOnlyViewBEGetAcquireChar...OK +HeapByteBufferReadOnlyViewBEGetAcquireInt...OK +HeapByteBufferReadOnlyViewBEGetAcquireLong...OK +HeapByteBufferReadOnlyViewBEGetAcquireFloat...OK +HeapByteBufferReadOnlyViewBEGetAcquireDouble...OK +HeapByteBufferReadOnlyViewBESetReleaseShort...OK +HeapByteBufferReadOnlyViewBESetReleaseChar...OK +HeapByteBufferReadOnlyViewBESetReleaseInt...OK +HeapByteBufferReadOnlyViewBESetReleaseLong...OK +HeapByteBufferReadOnlyViewBESetReleaseFloat...OK +HeapByteBufferReadOnlyViewBESetReleaseDouble...OK +HeapByteBufferReadOnlyViewBEGetOpaqueShort...OK +HeapByteBufferReadOnlyViewBEGetOpaqueChar...OK +HeapByteBufferReadOnlyViewBEGetOpaqueInt...OK +HeapByteBufferReadOnlyViewBEGetOpaqueLong...OK +HeapByteBufferReadOnlyViewBEGetOpaqueFloat...OK +HeapByteBufferReadOnlyViewBEGetOpaqueDouble...OK +HeapByteBufferReadOnlyViewBESetOpaqueShort...OK +HeapByteBufferReadOnlyViewBESetOpaqueChar...OK +HeapByteBufferReadOnlyViewBESetOpaqueInt...OK +HeapByteBufferReadOnlyViewBESetOpaqueLong...OK +HeapByteBufferReadOnlyViewBESetOpaqueFloat...OK +HeapByteBufferReadOnlyViewBESetOpaqueDouble...OK +HeapByteBufferReadOnlyViewBECompareAndSetShort...OK +HeapByteBufferReadOnlyViewBECompareAndSetChar...OK +HeapByteBufferReadOnlyViewBECompareAndSetInt...OK +HeapByteBufferReadOnlyViewBECompareAndSetLong...OK +HeapByteBufferReadOnlyViewBECompareAndSetFloat...OK +HeapByteBufferReadOnlyViewBECompareAndSetDouble...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeShort...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeChar...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeInt...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeLong...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeFloat...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeDouble...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeAcquireShort...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeAcquireChar...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeAcquireInt...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeAcquireLong...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeAcquireFloat...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeAcquireDouble...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeReleaseShort...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeReleaseChar...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeReleaseInt...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeReleaseLong...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeReleaseFloat...OK +HeapByteBufferReadOnlyViewBECompareAndExchangeReleaseDouble...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetPlainShort...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetPlainChar...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetPlainInt...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetPlainLong...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetPlainFloat...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetPlainDouble...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetShort...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetChar...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetInt...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetLong...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetFloat...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetDouble...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetAcquireShort...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetAcquireChar...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetAcquireInt...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetAcquireLong...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetAcquireFloat...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetAcquireDouble...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetReleaseShort...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetReleaseChar...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetReleaseInt...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetReleaseLong...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetReleaseFloat...OK +HeapByteBufferReadOnlyViewBEWeakCompareAndSetReleaseDouble...OK +HeapByteBufferReadOnlyViewBEGetAndSetShort...OK +HeapByteBufferReadOnlyViewBEGetAndSetChar...OK +HeapByteBufferReadOnlyViewBEGetAndSetInt...OK +HeapByteBufferReadOnlyViewBEGetAndSetLong...OK +HeapByteBufferReadOnlyViewBEGetAndSetFloat...OK +HeapByteBufferReadOnlyViewBEGetAndSetDouble...OK +HeapByteBufferReadOnlyViewBEGetAndSetAcquireShort...OK +HeapByteBufferReadOnlyViewBEGetAndSetAcquireChar...OK +HeapByteBufferReadOnlyViewBEGetAndSetAcquireInt...OK +HeapByteBufferReadOnlyViewBEGetAndSetAcquireLong...OK +HeapByteBufferReadOnlyViewBEGetAndSetAcquireFloat...OK +HeapByteBufferReadOnlyViewBEGetAndSetAcquireDouble...OK +HeapByteBufferReadOnlyViewBEGetAndSetReleaseShort...OK +HeapByteBufferReadOnlyViewBEGetAndSetReleaseChar...OK +HeapByteBufferReadOnlyViewBEGetAndSetReleaseInt...OK +HeapByteBufferReadOnlyViewBEGetAndSetReleaseLong...OK +HeapByteBufferReadOnlyViewBEGetAndSetReleaseFloat...OK +HeapByteBufferReadOnlyViewBEGetAndSetReleaseDouble...OK +HeapByteBufferReadOnlyViewBEGetAndAddShort...OK +HeapByteBufferReadOnlyViewBEGetAndAddChar...OK +HeapByteBufferReadOnlyViewBEGetAndAddInt...OK +HeapByteBufferReadOnlyViewBEGetAndAddLong...OK +HeapByteBufferReadOnlyViewBEGetAndAddFloat...OK +HeapByteBufferReadOnlyViewBEGetAndAddDouble...OK +HeapByteBufferReadOnlyViewBEGetAndAddAcquireShort...OK +HeapByteBufferReadOnlyViewBEGetAndAddAcquireChar...OK +HeapByteBufferReadOnlyViewBEGetAndAddAcquireInt...OK +HeapByteBufferReadOnlyViewBEGetAndAddAcquireLong...OK +HeapByteBufferReadOnlyViewBEGetAndAddAcquireFloat...OK +HeapByteBufferReadOnlyViewBEGetAndAddAcquireDouble...OK +HeapByteBufferReadOnlyViewBEGetAndAddReleaseShort...OK +HeapByteBufferReadOnlyViewBEGetAndAddReleaseChar...OK +HeapByteBufferReadOnlyViewBEGetAndAddReleaseInt...OK +HeapByteBufferReadOnlyViewBEGetAndAddReleaseLong...OK +HeapByteBufferReadOnlyViewBEGetAndAddReleaseFloat...OK +HeapByteBufferReadOnlyViewBEGetAndAddReleaseDouble...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrShort...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrChar...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrInt...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrLong...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrFloat...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrDouble...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrReleaseShort...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrReleaseChar...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrReleaseInt...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrReleaseLong...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrReleaseFloat...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrReleaseDouble...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrAcquireShort...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrAcquireChar...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrAcquireInt...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrAcquireLong...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrAcquireFloat...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseOrAcquireDouble...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndShort...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndChar...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndInt...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndLong...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndFloat...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndDouble...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndReleaseShort...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndReleaseChar...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndReleaseInt...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndReleaseLong...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndReleaseFloat...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndReleaseDouble...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndAcquireShort...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndAcquireChar...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndAcquireInt...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndAcquireLong...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndAcquireFloat...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseAndAcquireDouble...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorShort...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorChar...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorInt...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorLong...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorFloat...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorDouble...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorReleaseShort...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorReleaseChar...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorReleaseInt...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorReleaseLong...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorReleaseFloat...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorReleaseDouble...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorAcquireShort...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorAcquireChar...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorAcquireInt...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorAcquireLong...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorAcquireFloat...OK +HeapByteBufferReadOnlyViewBEGetAndBitwiseXorAcquireDouble...OK +FieldGetWidget...OK +FieldSetWidget...OK +FieldGetVolatileWidget...OK +FieldSetVolatileWidget...OK +FieldGetAcquireWidget...OK +FieldSetReleaseWidget...OK +FieldGetOpaqueWidget...OK +FieldSetOpaqueWidget...OK +FieldCompareAndSetWidget...OK +FieldCompareAndExchangeWidget...OK +FieldCompareAndExchangeAcquireWidget...OK +FieldCompareAndExchangeReleaseWidget...OK +FieldWeakCompareAndSetPlainWidget...OK +FieldWeakCompareAndSetWidget...OK +FieldWeakCompareAndSetAcquireWidget...OK +FieldWeakCompareAndSetReleaseWidget...OK +FieldGetAndSetWidget...OK +FieldGetAndSetAcquireWidget...OK +FieldGetAndSetReleaseWidget...OK +FieldGetAndAddWidget...OK +FieldGetAndAddAcquireWidget...OK +FieldGetAndAddReleaseWidget...OK +FieldGetAndBitwiseOrWidget...OK +FieldGetAndBitwiseOrReleaseWidget...OK +FieldGetAndBitwiseOrAcquireWidget...OK +FieldGetAndBitwiseAndWidget...OK +FieldGetAndBitwiseAndReleaseWidget...OK +FieldGetAndBitwiseAndAcquireWidget...OK +FieldGetAndBitwiseXorWidget...OK +FieldGetAndBitwiseXorReleaseWidget...OK +FieldGetAndBitwiseXorAcquireWidget...OK +FinalFieldGetWidget...OK +FinalFieldSetWidget...OK +FinalFieldGetVolatileWidget...OK +FinalFieldSetVolatileWidget...OK +FinalFieldGetAcquireWidget...OK +FinalFieldSetReleaseWidget...OK +FinalFieldGetOpaqueWidget...OK +FinalFieldSetOpaqueWidget...OK +FinalFieldCompareAndSetWidget...OK +FinalFieldCompareAndExchangeWidget...OK +FinalFieldCompareAndExchangeAcquireWidget...OK +FinalFieldCompareAndExchangeReleaseWidget...OK +FinalFieldWeakCompareAndSetPlainWidget...OK +FinalFieldWeakCompareAndSetWidget...OK +FinalFieldWeakCompareAndSetAcquireWidget...OK +FinalFieldWeakCompareAndSetReleaseWidget...OK +FinalFieldGetAndSetWidget...OK +FinalFieldGetAndSetAcquireWidget...OK +FinalFieldGetAndSetReleaseWidget...OK +FinalFieldGetAndAddWidget...OK +FinalFieldGetAndAddAcquireWidget...OK +FinalFieldGetAndAddReleaseWidget...OK +FinalFieldGetAndBitwiseOrWidget...OK +FinalFieldGetAndBitwiseOrReleaseWidget...OK +FinalFieldGetAndBitwiseOrAcquireWidget...OK +FinalFieldGetAndBitwiseAndWidget...OK +FinalFieldGetAndBitwiseAndReleaseWidget...OK +FinalFieldGetAndBitwiseAndAcquireWidget...OK +FinalFieldGetAndBitwiseXorWidget...OK +FinalFieldGetAndBitwiseXorReleaseWidget...OK +FinalFieldGetAndBitwiseXorAcquireWidget...OK +StaticFieldGetWidget...OK +StaticFieldSetWidget...OK +StaticFieldGetVolatileWidget...OK +StaticFieldSetVolatileWidget...OK +StaticFieldGetAcquireWidget...OK +StaticFieldSetReleaseWidget...OK +StaticFieldGetOpaqueWidget...OK +StaticFieldSetOpaqueWidget...OK +StaticFieldCompareAndSetWidget...OK +StaticFieldCompareAndExchangeWidget...OK +StaticFieldCompareAndExchangeAcquireWidget...OK +StaticFieldCompareAndExchangeReleaseWidget...OK +StaticFieldWeakCompareAndSetPlainWidget...OK +StaticFieldWeakCompareAndSetWidget...OK +StaticFieldWeakCompareAndSetAcquireWidget...OK +StaticFieldWeakCompareAndSetReleaseWidget...OK +StaticFieldGetAndSetWidget...OK +StaticFieldGetAndSetAcquireWidget...OK +StaticFieldGetAndSetReleaseWidget...OK +StaticFieldGetAndAddWidget...OK +StaticFieldGetAndAddAcquireWidget...OK +StaticFieldGetAndAddReleaseWidget...OK +StaticFieldGetAndBitwiseOrWidget...OK +StaticFieldGetAndBitwiseOrReleaseWidget...OK +StaticFieldGetAndBitwiseOrAcquireWidget...OK +StaticFieldGetAndBitwiseAndWidget...OK +StaticFieldGetAndBitwiseAndReleaseWidget...OK +StaticFieldGetAndBitwiseAndAcquireWidget...OK +StaticFieldGetAndBitwiseXorWidget...OK +StaticFieldGetAndBitwiseXorReleaseWidget...OK +StaticFieldGetAndBitwiseXorAcquireWidget...OK +StaticFinalFieldGetWidget...OK +StaticFinalFieldSetWidget...OK +StaticFinalFieldGetVolatileWidget...OK +StaticFinalFieldSetVolatileWidget...OK +StaticFinalFieldGetAcquireWidget...OK +StaticFinalFieldSetReleaseWidget...OK +StaticFinalFieldGetOpaqueWidget...OK +StaticFinalFieldSetOpaqueWidget...OK +StaticFinalFieldCompareAndSetWidget...OK +StaticFinalFieldCompareAndExchangeWidget...OK +StaticFinalFieldCompareAndExchangeAcquireWidget...OK +StaticFinalFieldCompareAndExchangeReleaseWidget...OK +StaticFinalFieldWeakCompareAndSetPlainWidget...OK +StaticFinalFieldWeakCompareAndSetWidget...OK +StaticFinalFieldWeakCompareAndSetAcquireWidget...OK +StaticFinalFieldWeakCompareAndSetReleaseWidget...OK +StaticFinalFieldGetAndSetWidget...OK +StaticFinalFieldGetAndSetAcquireWidget...OK +StaticFinalFieldGetAndSetReleaseWidget...OK +StaticFinalFieldGetAndAddWidget...OK +StaticFinalFieldGetAndAddAcquireWidget...OK +StaticFinalFieldGetAndAddReleaseWidget...OK +StaticFinalFieldGetAndBitwiseOrWidget...OK +StaticFinalFieldGetAndBitwiseOrReleaseWidget...OK +StaticFinalFieldGetAndBitwiseOrAcquireWidget...OK +StaticFinalFieldGetAndBitwiseAndWidget...OK +StaticFinalFieldGetAndBitwiseAndReleaseWidget...OK +StaticFinalFieldGetAndBitwiseAndAcquireWidget...OK +StaticFinalFieldGetAndBitwiseXorWidget...OK +StaticFinalFieldGetAndBitwiseXorReleaseWidget...OK +StaticFinalFieldGetAndBitwiseXorAcquireWidget...OK +ArrayElementGetWidget...OK +ArrayElementSetWidget...OK +ArrayElementGetVolatileWidget...OK +ArrayElementSetVolatileWidget...OK +ArrayElementGetAcquireWidget...OK +ArrayElementSetReleaseWidget...OK +ArrayElementGetOpaqueWidget...OK +ArrayElementSetOpaqueWidget...OK +ArrayElementCompareAndSetWidget...OK +ArrayElementCompareAndExchangeWidget...OK +ArrayElementCompareAndExchangeAcquireWidget...OK +ArrayElementCompareAndExchangeReleaseWidget...OK +ArrayElementWeakCompareAndSetPlainWidget...OK +ArrayElementWeakCompareAndSetWidget...OK +ArrayElementWeakCompareAndSetAcquireWidget...OK +ArrayElementWeakCompareAndSetReleaseWidget...OK +ArrayElementGetAndSetWidget...OK +ArrayElementGetAndSetAcquireWidget...OK +ArrayElementGetAndSetReleaseWidget...OK +ArrayElementGetAndAddWidget...OK +ArrayElementGetAndAddAcquireWidget...OK +ArrayElementGetAndAddReleaseWidget...OK +ArrayElementGetAndBitwiseOrWidget...OK +ArrayElementGetAndBitwiseOrReleaseWidget...OK +ArrayElementGetAndBitwiseOrAcquireWidget...OK +ArrayElementGetAndBitwiseAndWidget...OK +ArrayElementGetAndBitwiseAndReleaseWidget...OK +ArrayElementGetAndBitwiseAndAcquireWidget...OK +ArrayElementGetAndBitwiseXorWidget...OK +ArrayElementGetAndBitwiseXorReleaseWidget...OK +ArrayElementGetAndBitwiseXorAcquireWidget...OK +BoxingReturnGetBoolean...OK +BoxingSetBoolean...OK +BoxingReturnGetVolatileBoolean...OK +BoxingSetVolatileBoolean...OK +BoxingReturnGetAcquireBoolean...OK +BoxingSetReleaseBoolean...OK +BoxingReturnGetOpaqueBoolean...OK +BoxingSetOpaqueBoolean...OK +BoxingCompareAndSetBoolean...OK +BoxingCompareAndExchangeBoolean...OK +BoxingCompareAndExchangeAcquireBoolean...OK +BoxingCompareAndExchangeReleaseBoolean...OK +BoxingWeakCompareAndSetPlainBoolean...OK +BoxingWeakCompareAndSetBoolean...OK +BoxingWeakCompareAndSetAcquireBoolean...OK +BoxingWeakCompareAndSetReleaseBoolean...OK +BoxingGetAndSetBoolean...OK +BoxingGetAndSetAcquireBoolean...OK +BoxingGetAndSetReleaseBoolean...OK +BoxingGetAndAddBoolean...OK +BoxingGetAndAddAcquireBoolean...OK +BoxingGetAndAddReleaseBoolean...OK +BoxingGetAndBitwiseOrBoolean...OK +BoxingGetAndBitwiseOrReleaseBoolean...OK +BoxingGetAndBitwiseOrAcquireBoolean...OK +BoxingGetAndBitwiseAndBoolean...OK +BoxingGetAndBitwiseAndReleaseBoolean...OK +BoxingGetAndBitwiseAndAcquireBoolean...OK +BoxingGetAndBitwiseXorBoolean...OK +BoxingGetAndBitwiseXorReleaseBoolean...OK +BoxingGetAndBitwiseXorAcquireBoolean...OK +BoxingReturnGetByte...OK +BoxingSetByte...OK +BoxingReturnGetVolatileByte...OK +BoxingSetVolatileByte...OK +BoxingReturnGetAcquireByte...OK +BoxingSetReleaseByte...OK +BoxingReturnGetOpaqueByte...OK +BoxingSetOpaqueByte...OK +BoxingCompareAndSetByte...OK +BoxingCompareAndExchangeByte...OK +BoxingCompareAndExchangeAcquireByte...OK +BoxingCompareAndExchangeReleaseByte...OK +BoxingWeakCompareAndSetPlainByte...OK +BoxingWeakCompareAndSetByte...OK +BoxingWeakCompareAndSetAcquireByte...OK +BoxingWeakCompareAndSetReleaseByte...OK +BoxingGetAndSetByte...OK +BoxingGetAndSetAcquireByte...OK +BoxingGetAndSetReleaseByte...OK +BoxingGetAndAddByte...OK +BoxingGetAndAddAcquireByte...OK +BoxingGetAndAddReleaseByte...OK +BoxingGetAndBitwiseOrByte...OK +BoxingGetAndBitwiseOrReleaseByte...OK +BoxingGetAndBitwiseOrAcquireByte...OK +BoxingGetAndBitwiseAndByte...OK +BoxingGetAndBitwiseAndReleaseByte...OK +BoxingGetAndBitwiseAndAcquireByte...OK +BoxingGetAndBitwiseXorByte...OK +BoxingGetAndBitwiseXorReleaseByte...OK +BoxingGetAndBitwiseXorAcquireByte...OK +BoxingReturnGetShort...OK +BoxingSetShort...OK +BoxingReturnGetVolatileShort...OK +BoxingSetVolatileShort...OK +BoxingReturnGetAcquireShort...OK +BoxingSetReleaseShort...OK +BoxingReturnGetOpaqueShort...OK +BoxingSetOpaqueShort...OK +BoxingCompareAndSetShort...OK +BoxingCompareAndExchangeShort...OK +BoxingCompareAndExchangeAcquireShort...OK +BoxingCompareAndExchangeReleaseShort...OK +BoxingWeakCompareAndSetPlainShort...OK +BoxingWeakCompareAndSetShort...OK +BoxingWeakCompareAndSetAcquireShort...OK +BoxingWeakCompareAndSetReleaseShort...OK +BoxingGetAndSetShort...OK +BoxingGetAndSetAcquireShort...OK +BoxingGetAndSetReleaseShort...OK +BoxingGetAndAddShort...OK +BoxingGetAndAddAcquireShort...OK +BoxingGetAndAddReleaseShort...OK +BoxingGetAndBitwiseOrShort...OK +BoxingGetAndBitwiseOrReleaseShort...OK +BoxingGetAndBitwiseOrAcquireShort...OK +BoxingGetAndBitwiseAndShort...OK +BoxingGetAndBitwiseAndReleaseShort...OK +BoxingGetAndBitwiseAndAcquireShort...OK +BoxingGetAndBitwiseXorShort...OK +BoxingGetAndBitwiseXorReleaseShort...OK +BoxingGetAndBitwiseXorAcquireShort...OK +BoxingReturnGetChar...OK +BoxingSetChar...OK +BoxingReturnGetVolatileChar...OK +BoxingSetVolatileChar...OK +BoxingReturnGetAcquireChar...OK +BoxingSetReleaseChar...OK +BoxingReturnGetOpaqueChar...OK +BoxingSetOpaqueChar...OK +BoxingCompareAndSetChar...OK +BoxingCompareAndExchangeChar...OK +BoxingCompareAndExchangeAcquireChar...OK +BoxingCompareAndExchangeReleaseChar...OK +BoxingWeakCompareAndSetPlainChar...OK +BoxingWeakCompareAndSetChar...OK +BoxingWeakCompareAndSetAcquireChar...OK +BoxingWeakCompareAndSetReleaseChar...OK +BoxingGetAndSetChar...OK +BoxingGetAndSetAcquireChar...OK +BoxingGetAndSetReleaseChar...OK +BoxingGetAndAddChar...OK +BoxingGetAndAddAcquireChar...OK +BoxingGetAndAddReleaseChar...OK +BoxingGetAndBitwiseOrChar...OK +BoxingGetAndBitwiseOrReleaseChar...OK +BoxingGetAndBitwiseOrAcquireChar...OK +BoxingGetAndBitwiseAndChar...OK +BoxingGetAndBitwiseAndReleaseChar...OK +BoxingGetAndBitwiseAndAcquireChar...OK +BoxingGetAndBitwiseXorChar...OK +BoxingGetAndBitwiseXorReleaseChar...OK +BoxingGetAndBitwiseXorAcquireChar...OK +BoxingReturnGetInt...OK +BoxingSetInt...OK +BoxingReturnGetVolatileInt...OK +BoxingSetVolatileInt...OK +BoxingReturnGetAcquireInt...OK +BoxingSetReleaseInt...OK +BoxingReturnGetOpaqueInt...OK +BoxingSetOpaqueInt...OK +BoxingCompareAndSetInt...OK +BoxingCompareAndExchangeInt...OK +BoxingCompareAndExchangeAcquireInt...OK +BoxingCompareAndExchangeReleaseInt...OK +BoxingWeakCompareAndSetPlainInt...OK +BoxingWeakCompareAndSetInt...OK +BoxingWeakCompareAndSetAcquireInt...OK +BoxingWeakCompareAndSetReleaseInt...OK +BoxingGetAndSetInt...OK +BoxingGetAndSetAcquireInt...OK +BoxingGetAndSetReleaseInt...OK +BoxingGetAndAddInt...OK +BoxingGetAndAddAcquireInt...OK +BoxingGetAndAddReleaseInt...OK +BoxingGetAndBitwiseOrInt...OK +BoxingGetAndBitwiseOrReleaseInt...OK +BoxingGetAndBitwiseOrAcquireInt...OK +BoxingGetAndBitwiseAndInt...OK +BoxingGetAndBitwiseAndReleaseInt...OK +BoxingGetAndBitwiseAndAcquireInt...OK +BoxingGetAndBitwiseXorInt...OK +BoxingGetAndBitwiseXorReleaseInt...OK +BoxingGetAndBitwiseXorAcquireInt...OK +BoxingReturnGetLong...OK +BoxingSetLong...OK +BoxingReturnGetVolatileLong...OK +BoxingSetVolatileLong...OK +BoxingReturnGetAcquireLong...OK +BoxingSetReleaseLong...OK +BoxingReturnGetOpaqueLong...OK +BoxingSetOpaqueLong...OK +BoxingCompareAndSetLong...OK +BoxingCompareAndExchangeLong...OK +BoxingCompareAndExchangeAcquireLong...OK +BoxingCompareAndExchangeReleaseLong...OK +BoxingWeakCompareAndSetPlainLong...OK +BoxingWeakCompareAndSetLong...OK +BoxingWeakCompareAndSetAcquireLong...OK +BoxingWeakCompareAndSetReleaseLong...OK +BoxingGetAndSetLong...OK +BoxingGetAndSetAcquireLong...OK +BoxingGetAndSetReleaseLong...OK +BoxingGetAndAddLong...OK +BoxingGetAndAddAcquireLong...OK +BoxingGetAndAddReleaseLong...OK +BoxingGetAndBitwiseOrLong...OK +BoxingGetAndBitwiseOrReleaseLong...OK +BoxingGetAndBitwiseOrAcquireLong...OK +BoxingGetAndBitwiseAndLong...OK +BoxingGetAndBitwiseAndReleaseLong...OK +BoxingGetAndBitwiseAndAcquireLong...OK +BoxingGetAndBitwiseXorLong...OK +BoxingGetAndBitwiseXorReleaseLong...OK +BoxingGetAndBitwiseXorAcquireLong...OK +BoxingReturnGetFloat...OK +BoxingSetFloat...OK +BoxingReturnGetVolatileFloat...OK +BoxingSetVolatileFloat...OK +BoxingReturnGetAcquireFloat...OK +BoxingSetReleaseFloat...OK +BoxingReturnGetOpaqueFloat...OK +BoxingSetOpaqueFloat...OK +BoxingCompareAndSetFloat...OK +BoxingCompareAndExchangeFloat...OK +BoxingCompareAndExchangeAcquireFloat...OK +BoxingCompareAndExchangeReleaseFloat...OK +BoxingWeakCompareAndSetPlainFloat...OK +BoxingWeakCompareAndSetFloat...OK +BoxingWeakCompareAndSetAcquireFloat...OK +BoxingWeakCompareAndSetReleaseFloat...OK +BoxingGetAndSetFloat...OK +BoxingGetAndSetAcquireFloat...OK +BoxingGetAndSetReleaseFloat...OK +BoxingGetAndAddFloat...OK +BoxingGetAndAddAcquireFloat...OK +BoxingGetAndAddReleaseFloat...OK +BoxingGetAndBitwiseOrFloat...OK +BoxingGetAndBitwiseOrReleaseFloat...OK +BoxingGetAndBitwiseOrAcquireFloat...OK +BoxingGetAndBitwiseAndFloat...OK +BoxingGetAndBitwiseAndReleaseFloat...OK +BoxingGetAndBitwiseAndAcquireFloat...OK +BoxingGetAndBitwiseXorFloat...OK +BoxingGetAndBitwiseXorReleaseFloat...OK +BoxingGetAndBitwiseXorAcquireFloat...OK +BoxingReturnGetDouble...OK +BoxingSetDouble...OK +BoxingReturnGetVolatileDouble...OK +BoxingSetVolatileDouble...OK +BoxingReturnGetAcquireDouble...OK +BoxingSetReleaseDouble...OK +BoxingReturnGetOpaqueDouble...OK +BoxingSetOpaqueDouble...OK +BoxingCompareAndSetDouble...OK +BoxingCompareAndExchangeDouble...OK +BoxingCompareAndExchangeAcquireDouble...OK +BoxingCompareAndExchangeReleaseDouble...OK +BoxingWeakCompareAndSetPlainDouble...OK +BoxingWeakCompareAndSetDouble...OK +BoxingWeakCompareAndSetAcquireDouble...OK +BoxingWeakCompareAndSetReleaseDouble...OK +BoxingGetAndSetDouble...OK +BoxingGetAndSetAcquireDouble...OK +BoxingGetAndSetReleaseDouble...OK +BoxingGetAndAddDouble...OK +BoxingGetAndAddAcquireDouble...OK +BoxingGetAndAddReleaseDouble...OK +BoxingGetAndBitwiseOrDouble...OK +BoxingGetAndBitwiseOrReleaseDouble...OK +BoxingGetAndBitwiseOrAcquireDouble...OK +BoxingGetAndBitwiseAndDouble...OK +BoxingGetAndBitwiseAndReleaseDouble...OK +BoxingGetAndBitwiseAndAcquireDouble...OK +BoxingGetAndBitwiseXorDouble...OK +BoxingGetAndBitwiseXorReleaseDouble...OK +BoxingGetAndBitwiseXorAcquireDouble...OK +NullReceiverTest...OK +UnsupportedAccessModeTest...OK +WrongArgumentTypeCausingWrongMethodTypeTest...OK +TooManyArgumentsCausingWrongMethodTypeTest...OK +TooFewArgumentsCausingWrongMethodTypeTest...OK +ReturnTypeCausingWrongMethodTypeTest...OK +UnsupportedAccessModePreemptsWrongMethodTypeExceptionTest...OK +FieldCoordinateTypeTest...OK +ArrayElementOutOfBoundsIndexTest...OK +ArrayElementBadIndexTypeTest...OK +ArrayElementNullArrayTest...OK +ArrayElementWrongArrayTypeTest...OK +ArrayElementMissingIndexTest...OK +ByteArrayViewOutOfBoundsIndexTest...OK +ByteArrayViewUnalignedAccessesIndexTest...OK +ByteArrayViewBadIndexTypeTest...OK +ByteArrayViewMissingIndexTest...OK +ByteArrayViewBadByteArrayTest...OK +ByteBufferViewOutOfBoundsIndexTest...OK +ByteBufferViewUnalignedAccessesIndexTest...OK +ByteBufferViewBadIndexTypeTest...OK +ByteBufferViewMissingIndexTest...OK +ByteBufferViewBadByteBufferTest...OK +VoidReturnTypeTest...OK +BoxedNullBooleanThrowsNPETest...OK +BoxedNullByteThrowsNPETest...OK +BoxedNullCharacterThrowsNPETest...OK +BoxedNullShortThrowsNPETest...OK +BoxedNullIntegerThrowsNPETest...OK +BoxedNullLongThrowsNPETest...OK +BoxedNullFloatThrowsNPETest...OK +BoxedNullDoubleThrowsNPETest...OK +WideningBooleanArgumentTest...OK +WideningByteArgumentTest...OK +WideningCharacterArgumentTest...OK +WideningShortArgumentTest...OK +WideningIntegerArgumentTest...OK +WideningLongArgumentTest...OK +WideningFloatArgumentTest...OK +WideningDoubleArgumentTest...OK +WideningBooleanReturnValueTest...OK +WideningByteReturnValueTest...OK +WideningCharacterReturnValueTest...OK +WideningShortReturnValueTest...OK +WideningIntegerReturnValueTest...OK +WideningLongReturnValueTest...OK +WideningFloatReturnValueTest...OK +WideningDoubleReturnValueTest...OK +SubtypeTest...OK +SupertypeTest...OK +ImplicitBoxingIntegerTest...OK +3182 successes, 0 skips, 0 failures. diff --git a/test/712-varhandle-invocations/info.txt b/test/712-varhandle-invocations/info.txt new file mode 100644 index 0000000000..e2de024d8e --- /dev/null +++ b/test/712-varhandle-invocations/info.txt @@ -0,0 +1 @@ +Generates and runs tests that invoke VarHandle accessor methods. diff --git a/test/712-varhandle-invocations/src/SimpleTests.java b/test/712-varhandle-invocations/src/SimpleTests.java new file mode 100644 index 0000000000..6e62bff4b4 --- /dev/null +++ b/test/712-varhandle-invocations/src/SimpleTests.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class SimpleTests { + public static class TestGuardSkips extends VarHandleUnitTest { + public boolean checkGuard() { + return false; + } + + @Override + protected void doTest() { + throw new IllegalStateException("Not reachable"); + } + + public static void main(String[] args) { + new TestGuardSkips().run(); + } + } + + public static class TestEqualsOK extends VarHandleUnitTest { + @Override + protected void doTest() { + assertEquals(true, true); + } + } + + public static class TestEqualsOK2 extends VarHandleUnitTest { + @Override + protected void doTest() { + assertEquals(true, false); + } + } + + public static class TestExceptionsFail extends VarHandleUnitTest { + @Override + protected void doTest() { + throw new NullPointerException(); + } + } + + public static void main(String[] args) { + new TestGuardSkips().run(); + new TestEqualsOK().run(); + new TestEqualsOK2().run(); + new TestExceptionsFail().run(); + VarHandleUnitTest.DEFAULT_COLLECTOR.printSummary(); + } +} diff --git a/test/712-varhandle-invocations/src/VarHandleAccessorExceptionTests.java b/test/712-varhandle-invocations/src/VarHandleAccessorExceptionTests.java new file mode 100644 index 0000000000..4c9013b14d --- /dev/null +++ b/test/712-varhandle-invocations/src/VarHandleAccessorExceptionTests.java @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2018 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. + */ + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.lang.invoke.WrongMethodTypeException; + +// These tests cover DoVarHandleInvokeCommon in interpreter_common.cc. + +public class VarHandleAccessorExceptionTests { + public static class NullReceiverTest extends VarHandleUnitTest { + private static final VarHandle vh = null; + + @Override + protected void doTest() { + try { + vh.set(3); + failUnreachable(); + } catch (NullPointerException ex) { + } + } + + public static void main(String[] args) { + new NullReceiverTest().run(); + } + } + + public static class UnsupportedAccessModeTest extends VarHandleUnitTest { + private static final boolean b = true; + private static final VarHandle vh; + + static { + try { + Class<?> cls = UnsupportedAccessModeTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "b", boolean.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + // A final field should not support an VarHandle access modes which can update it + boolean isSupported = + vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_AND); + assertFalse(isSupported); + try { + vh.getAndBitwiseAnd(true); + failUnreachable(); + } catch (UnsupportedOperationException ex) { + } + } + + public static void main(String[] args) { + new UnsupportedAccessModeTest().run(); + } + } + + public static class WrongArgumentTypeCausingWrongMethodTypeTest extends VarHandleUnitTest { + private short s; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WrongArgumentTypeCausingWrongMethodTypeTest.class; + vh = MethodHandles.lookup().findVarHandle(cls, "s", short.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + vh.set(this, (short) 0xcafe); + try { + vh.setVolatile(this, System.out); // System.out is a PrintStream, not short! + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + + public static void main(String[] args) { + new WrongArgumentTypeCausingWrongMethodTypeTest().run(); + } + } + + // Too many arguments causing WMTE + public static class TooManyArgumentsCausingWrongMethodTypeTest extends VarHandleUnitTest { + private int i; + private static final VarHandle vh; + + static { + try { + Class<?> cls = TooManyArgumentsCausingWrongMethodTypeTest.class; + vh = MethodHandles.lookup().findVarHandle(cls, "i", int.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + vh.set(this, 0x12345678); + try { + vh.setVolatile(this, 0x5a5a55aa, 0xc3c30f0f); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + + public static void main(String[] args) { + new TooManyArgumentsCausingWrongMethodTypeTest().run(); + } + } + + public static class TooFewArgumentsCausingWrongMethodTypeTest extends VarHandleUnitTest { + private int i; + private static final VarHandle vh; + + static { + try { + Class<?> cls = TooFewArgumentsCausingWrongMethodTypeTest.class; + vh = MethodHandles.lookup().findVarHandle(cls, "i", int.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + i = 33; + vh.compareAndSet(this, 33, 44); + boolean updated = false; + try { + updated = (boolean) vh.compareAndSet(this, 44); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + assertFalse(updated); // Should have failed too few arguments + } + + public static void main(String[] args) { + new TooFewArgumentsCausingWrongMethodTypeTest().run(); + } + } + + public static class ReturnTypeCausingWrongMethodTypeTest extends VarHandleUnitTest { + private int i; + private static final VarHandle vh; + + static { + try { + Class<?> cls = ReturnTypeCausingWrongMethodTypeTest.class; + vh = MethodHandles.lookup().findVarHandle(cls, "i", int.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + i = 33; + vh.getAndSet(this, 44); + Runtime runtime = null; + try { + runtime = (Runtime) vh.getAndSet(this, 44); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + assertEquals(null, runtime); + } + + public static void main(String[] args) { + new ReturnTypeCausingWrongMethodTypeTest().run(); + } + } + + public static class UnsupportedAccessModePreemptsWrongMethodTypeExceptionTest + extends VarHandleUnitTest { + private static final boolean b = true; + private static final VarHandle vh; + + static { + try { + Class<?> cls = UnsupportedAccessModePreemptsWrongMethodTypeExceptionTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "b", boolean.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + // A final field should not support an VarHandle access modes which can update it + boolean supported = vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_BITWISE_AND); + assertFalse(supported); + try { + // The following is both unsupported and a wrong method type... + vh.getAndBitwiseAnd(System.out); + failUnreachable(); + } catch (UnsupportedOperationException ex) { + } + } + + public static void main(String[] args) { + new UnsupportedAccessModePreemptsWrongMethodTypeExceptionTest().run(); + } + } + + public static void main(String[] args) { + NullReceiverTest.main(args); + UnsupportedAccessModeTest.main(args); + WrongArgumentTypeCausingWrongMethodTypeTest.main(args); + TooManyArgumentsCausingWrongMethodTypeTest.main(args); + TooFewArgumentsCausingWrongMethodTypeTest.main(args); + ReturnTypeCausingWrongMethodTypeTest.main(args); + UnsupportedAccessModePreemptsWrongMethodTypeExceptionTest.main(args); + } +} diff --git a/test/712-varhandle-invocations/src/VarHandleBadCoordinateTests.java b/test/712-varhandle-invocations/src/VarHandleBadCoordinateTests.java new file mode 100644 index 0000000000..8f81c94a89 --- /dev/null +++ b/test/712-varhandle-invocations/src/VarHandleBadCoordinateTests.java @@ -0,0 +1,948 @@ +/* + * Copyright (C) 2018 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. + */ + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.lang.invoke.WrongMethodTypeException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class VarHandleBadCoordinateTests { + public static class FieldCoordinateTypeTest extends VarHandleUnitTest { + private static final VarHandle vh; + + public static class A { + public byte field; + } + + public static class B extends A { + private byte other_field; + } + + public static class C {} + + static { + try { + vh = MethodHandles.lookup().findVarHandle(A.class, "field", byte.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + vh.compareAndSet(new A(), (byte) 0, (byte) 3); + vh.compareAndSet(new B(), (byte) 0, (byte) 3); + try { + vh.compareAndSet(new C(), (byte) 0, (byte) 3); + failUnreachable(); + } catch (ClassCastException ex) { + } + try { + vh.compareAndSet(0xbad0bad0, (byte) 0, (byte) 3); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.compareAndSet(0xbad0bad0, (byte) 0, Integer.MAX_VALUE); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.compareAndSet(0xbad0bad0, (byte) 0); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.compareAndSet(new A(), (byte) 0, Integer.MAX_VALUE); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.compareAndSet((A) null, (byte) 0, (byte) 3); + failUnreachable(); + } catch (NullPointerException ex) { + } + } + + public static void main(String[] args) { + new FieldCoordinateTypeTest().run(); + } + } + + public static class ArrayElementOutOfBoundsIndexTest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.arrayElementVarHandle(long[].class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + long[] values = new long[33]; + try { + vh.get(values, -1); + failUnreachable(); + } catch (ArrayIndexOutOfBoundsException ex) { + } + try { + vh.get(values, values.length); + failUnreachable(); + } catch (ArrayIndexOutOfBoundsException ex) { + } + try { + vh.get(values, Integer.MAX_VALUE - 1); + failUnreachable(); + } catch (ArrayIndexOutOfBoundsException ex) { + } + } + + public static void main(String[] args) { + new ArrayElementOutOfBoundsIndexTest().run(); + } + } + + public static class ArrayElementBadIndexTypeTest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.arrayElementVarHandle(long[].class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + long[] values = new long[33]; + vh.set(values, Integer.valueOf(3), Long.MIN_VALUE); + vh.set(values, Byte.valueOf((byte) 0), Long.MIN_VALUE); + try { + vh.set(values, 3.3f, Long.MAX_VALUE); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + + public static void main(String[] args) { + new ArrayElementBadIndexTypeTest().run(); + } + } + + public static class ArrayElementNullArrayTest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.arrayElementVarHandle(long[].class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + long[] values = null; + try { + vh.get(values); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + + public static void main(String[] args) { + new ArrayElementNullArrayTest().run(); + } + } + + public static class ArrayElementWrongArrayTypeTest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.arrayElementVarHandle(long[].class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + try { + vh.get(new char[10], 0); + failUnreachable(); + } catch (ClassCastException ex) { + } + } + + public static void main(String[] args) { + new ArrayElementWrongArrayTypeTest().run(); + } + } + + public static class ArrayElementMissingIndexTest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.arrayElementVarHandle(long[].class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + long[] values = new long[33]; + try { + vh.get(values); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + + public static void main(String[] args) { + new ArrayElementMissingIndexTest().run(); + } + } + + public static class ByteArrayViewOutOfBoundsIndexTest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + byte[] bytes = new byte[16]; + try { + vh.get(bytes, -1); + failUnreachable(); + } catch (IndexOutOfBoundsException ex) { + } + try { + vh.get(bytes, bytes.length); + failUnreachable(); + } catch (IndexOutOfBoundsException ex) { + } + try { + vh.get(bytes, Integer.MAX_VALUE - 1); + failUnreachable(); + } catch (IndexOutOfBoundsException ex) { + } + try { + vh.get(bytes, bytes.length - Integer.SIZE / 8 + 1); + failUnreachable(); + } catch (IndexOutOfBoundsException ex) { + } + vh.get(bytes, bytes.length - Integer.SIZE / 8); + } + + public static void main(String[] args) { + new ByteArrayViewOutOfBoundsIndexTest().run(); + } + } + + public static class ByteArrayViewUnalignedAccessesIndexTest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + byte[] bytes = new byte[33]; + + int alignedIndex = VarHandleUnitTestHelpers.alignedOffset_int(bytes, 0); + for (int i = alignedIndex; i < Integer.SIZE / 8; ++i) { + // No exceptions are expected for GET and SET + // accessors irrespective of the access alignment. + vh.set(bytes, i, 380); + vh.get(bytes, i); + // Other accessors raise an IllegalStateException if + // the access is unaligned. + try { + vh.compareAndExchange(bytes, i, 777, 320); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.compareAndExchangeAcquire(bytes, i, 320, 767); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.compareAndExchangeRelease(bytes, i, 767, 321); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.compareAndSet(bytes, i, 767, 321); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAcquire(bytes, i); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndAdd(bytes, i, 117); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndAddAcquire(bytes, i, 117); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndAddRelease(bytes, i, 117); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseAnd(bytes, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseAndAcquire(bytes, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseAndRelease(bytes, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseOr(bytes, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseOrAcquire(bytes, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseOrRelease(bytes, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseXor(bytes, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseXorAcquire(bytes, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseXorRelease(bytes, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndSet(bytes, i, 117); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndSetAcquire(bytes, i, 117); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndSetRelease(bytes, i, 117); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getOpaque(bytes, i); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getVolatile(bytes, i); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.setOpaque(bytes, i, 777); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.setRelease(bytes, i, 319); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.setVolatile(bytes, i, 787); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.weakCompareAndSet(bytes, i, 787, 340); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.weakCompareAndSetAcquire(bytes, i, 787, 340); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.weakCompareAndSetPlain(bytes, i, 787, 340); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.weakCompareAndSetRelease(bytes, i, 787, 340); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + } + } + + public static void main(String[] args) { + new ByteArrayViewUnalignedAccessesIndexTest().run(); + } + } + + public static class ByteArrayViewBadIndexTypeTest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + byte[] bytes = new byte[16]; + // Boxed index goes through argument conversion so no exception expected. + vh.get(bytes, Integer.valueOf(3)); + vh.get(bytes, Short.valueOf((short) 3)); + + try { + vh.get(bytes, System.out); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + + public static void main(String[] args) { + new ByteArrayViewBadIndexTypeTest().run(); + } + } + + public static class ByteArrayViewMissingIndexTest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + byte[] bytes = new byte[16]; + try { + vh.get(bytes); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + + public static void main(String[] args) { + new ByteArrayViewMissingIndexTest().run(); + } + } + + public static class ByteArrayViewBadByteArrayTest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + byte[] bytes = null; + try { + vh.get(bytes, Integer.valueOf(3)); + failUnreachable(); + } catch (NullPointerException ex) { + } + try { + vh.get(System.err, Integer.valueOf(3)); + failUnreachable(); + } catch (ClassCastException ex) { + } + } + + public static void main(String[] args) { + new ByteArrayViewBadByteArrayTest().run(); + } + } + + public static class ByteBufferViewOutOfBoundsIndexTest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.byteBufferViewVarHandle(float[].class, ByteOrder.LITTLE_ENDIAN); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + ByteBuffer[] buffers = + new ByteBuffer[] { + ByteBuffer.allocateDirect(16), + ByteBuffer.allocate(37), + ByteBuffer.wrap(new byte[27], 3, 27 - 3) + }; + for (ByteBuffer buffer : buffers) { + try { + vh.get(buffer, -1); + failUnreachable(); + } catch (IndexOutOfBoundsException ex) { + } + try { + vh.get(buffer, buffer.limit()); + failUnreachable(); + } catch (IndexOutOfBoundsException ex) { + } + try { + vh.get(buffer, Integer.MAX_VALUE - 1); + failUnreachable(); + } catch (IndexOutOfBoundsException ex) { + } + try { + vh.get(buffer, buffer.limit() - Integer.SIZE / 8 + 1); + failUnreachable(); + } catch (IndexOutOfBoundsException ex) { + } + vh.get(buffer, buffer.limit() - Integer.SIZE / 8); + } + } + + public static void main(String[] args) { + new ByteBufferViewOutOfBoundsIndexTest().run(); + } + } + + public static class ByteBufferViewUnalignedAccessesIndexTest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.byteBufferViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + ByteBuffer[] buffers = + new ByteBuffer[] { + ByteBuffer.allocateDirect(16), + ByteBuffer.allocate(37), + ByteBuffer.wrap(new byte[27], 3, 27 - 3) + }; + + for (ByteBuffer buffer : buffers) { + int alignedIndex = VarHandleUnitTestHelpers.alignedOffset_int(buffer, 0); + for (int i = alignedIndex; i < Integer.SIZE / 8; ++i) { + // No exceptions are expected for GET and SET + // accessors irrespective of the access alignment. + vh.set(buffer, i, 380); + vh.get(buffer, i); + // Other accessors raise an IllegalStateException if + // the access is unaligned. + try { + vh.compareAndExchange(buffer, i, 777, 320); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.compareAndExchangeAcquire(buffer, i, 320, 767); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.compareAndExchangeRelease(buffer, i, 767, 321); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.compareAndSet(buffer, i, 767, 321); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAcquire(buffer, i); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndAdd(buffer, i, 117); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndAddAcquire(buffer, i, 117); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndAddRelease(buffer, i, 117); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseAnd(buffer, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseAndAcquire(buffer, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseAndRelease(buffer, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseOr(buffer, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseOrAcquire(buffer, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseOrRelease(buffer, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseXor(buffer, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseXorAcquire(buffer, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndBitwiseXorRelease(buffer, i, 118); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndSet(buffer, i, 117); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndSetAcquire(buffer, i, 117); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getAndSetRelease(buffer, i, 117); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getOpaque(buffer, i); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.getVolatile(buffer, i); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.setOpaque(buffer, i, 777); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.setRelease(buffer, i, 319); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.setVolatile(buffer, i, 787); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.weakCompareAndSet(buffer, i, 787, 340); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.weakCompareAndSetAcquire(buffer, i, 787, 340); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.weakCompareAndSetPlain(buffer, i, 787, 340); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + try { + vh.weakCompareAndSetRelease(buffer, i, 787, 340); + assertTrue(i == alignedIndex); + } catch (IllegalStateException ex) { + assertFalse(i == alignedIndex); + } + } + } + } + + public static void main(String[] args) { + new ByteBufferViewUnalignedAccessesIndexTest().run(); + } + } + + public static class ByteBufferViewBadIndexTypeTest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.byteBufferViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + ByteBuffer[] buffers = + new ByteBuffer[] { + ByteBuffer.allocateDirect(16), + ByteBuffer.allocate(16), + ByteBuffer.wrap(new byte[32], 4, 32 - 4) + }; + + for (ByteBuffer buffer : buffers) { + // Boxed index goes through argument conversion so no exception expected. + vh.get(buffer, Integer.valueOf(3)); + vh.get(buffer, Short.valueOf((short) 3)); + vh.get(buffer, Byte.valueOf((byte) 7)); + try { + vh.get(buffer, System.out); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + } + + public static void main(String[] args) { + new ByteBufferViewBadIndexTypeTest().run(); + } + } + + public static class ByteBufferViewMissingIndexTest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.byteBufferViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + ByteBuffer[] buffers = + new ByteBuffer[] { + ByteBuffer.allocateDirect(16), + ByteBuffer.allocate(16), + ByteBuffer.wrap(new byte[32], 4, 32 - 4) + }; + for (ByteBuffer buffer : buffers) { + try { + vh.get(buffer); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + } + + public static void main(String[] args) { + new ByteBufferViewMissingIndexTest().run(); + } + } + + public static class ByteBufferViewBadByteBufferTest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.byteBufferViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + if (VarHandleUnitTestHelpers.isRunningOnAndroid()) { + ByteBuffer buffer = null; + // The RI does not like this test + try { + vh.get(buffer, 3); + failUnreachable(); + } catch (NullPointerException ex) { + } + } + try { + vh.get(System.err, 3); + failUnreachable(); + } catch (ClassCastException ex) { + } + } + + public static void main(String[] args) { + new ByteBufferViewBadByteBufferTest().run(); + } + } + + public static void main(String[] args) { + FieldCoordinateTypeTest.main(args); + + ArrayElementOutOfBoundsIndexTest.main(args); + ArrayElementBadIndexTypeTest.main(args); + ArrayElementNullArrayTest.main(args); + ArrayElementWrongArrayTypeTest.main(args); + ArrayElementMissingIndexTest.main(args); + + ByteArrayViewOutOfBoundsIndexTest.main(args); + ByteArrayViewUnalignedAccessesIndexTest.main(args); + ByteArrayViewBadIndexTypeTest.main(args); + ByteArrayViewMissingIndexTest.main(args); + ByteArrayViewBadByteArrayTest.main(args); + + ByteBufferViewOutOfBoundsIndexTest.main(args); + ByteBufferViewUnalignedAccessesIndexTest.main(args); + ByteBufferViewBadIndexTypeTest.main(args); + ByteBufferViewMissingIndexTest.main(args); + ByteBufferViewBadByteBufferTest.main(args); + } +} diff --git a/test/712-varhandle-invocations/src/VarHandleReflectiveTest.java b/test/712-varhandle-invocations/src/VarHandleReflectiveTest.java new file mode 100644 index 0000000000..ae2f332171 --- /dev/null +++ b/test/712-varhandle-invocations/src/VarHandleReflectiveTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018 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. + */ + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class VarHandleReflectiveTest { + public static class ReflectiveAccessorInvocations extends VarHandleUnitTest { + private static final VarHandle vh; + private static int field; + + static { + try { + Class<?> cls = ReflectiveAccessorInvocations.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "field", int.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() throws Exception { + for (VarHandle.AccessMode accessMode : VarHandle.AccessMode.values()) { + Method accessorMethod = + VarHandle.class.getMethod(accessMode.methodName(), Object[].class); + try { + accessorMethod.invoke(vh, new Object[] {new Object[] {}}); + failUnreachable(); + } catch (InvocationTargetException e) { + assertEquals(e.getCause().getClass(), UnsupportedOperationException.class); + } + } + } + + public static void main(String[] args) { + new ReflectiveAccessorInvocations().run(); + } + } + + public static void main(String[] args) { + ReflectiveAccessorInvocations.main(args); + } +} diff --git a/test/712-varhandle-invocations/src/VarHandleTypeConversionTests.java b/test/712-varhandle-invocations/src/VarHandleTypeConversionTests.java new file mode 100644 index 0000000000..c0fbd492b2 --- /dev/null +++ b/test/712-varhandle-invocations/src/VarHandleTypeConversionTests.java @@ -0,0 +1,1343 @@ +/* + * Copyright (C) 2018 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. + */ + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.lang.invoke.WrongMethodTypeException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class VarHandleTypeConversionTests { + public static class VoidReturnTypeTest extends VarHandleUnitTest { + private int i; + private static final VarHandle vh; + + static { + try { + Class<?> cls = VoidReturnTypeTest.class; + vh = MethodHandles.lookup().findVarHandle(cls, "i", int.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + // Void is always okay for a return type. + vh.setVolatile(this, 33); + vh.get(this); + vh.compareAndSet(this, 33, 44); + vh.compareAndSet(this, 27, 16); + vh.weakCompareAndSet(this, 17, 19); + vh.getAndSet(this, 200000); + vh.getAndBitwiseXor(this, 0x5a5a5a5a); + vh.getAndAdd(this, 99); + } + + public static void main(String[] args) { + new VoidReturnTypeTest().run(); + } + } + + // + // Tests that a null reference as a boxed primitive type argument + // throws a NullPointerException. These vary the VarHandle type + // with each primitive for coverage. + // + + public static class BoxedNullBooleanThrowsNPETest extends VarHandleUnitTest { + private static boolean z; + private static final VarHandle vh; + + static { + try { + Class<?> cls = BoxedNullBooleanThrowsNPETest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "z", boolean.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + Boolean newValue = null; + try { + vh.getAndSet(newValue); + failUnreachable(); + } catch (NullPointerException ex) { + } + } + + public static void main(String[] args) { + new BoxedNullBooleanThrowsNPETest().run(); + } + } + + public static class BoxedNullByteThrowsNPETest extends VarHandleUnitTest { + private byte b; + private static final VarHandle vh; + + static { + try { + Class<?> cls = BoxedNullByteThrowsNPETest.class; + vh = MethodHandles.lookup().findVarHandle(cls, "b", byte.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + Byte newValue = null; + try { + vh.getAndSet(this, newValue); + failUnreachable(); + } catch (NullPointerException ex) { + } + } + + public static void main(String[] args) { + new BoxedNullByteThrowsNPETest().run(); + } + } + + public static class BoxedNullCharacterThrowsNPETest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.arrayElementVarHandle(char[].class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + char[] values = new char[3]; + Character newValue = null; + try { + vh.getAndSet(values, 0, newValue); + failUnreachable(); + } catch (NullPointerException ex) { + } + } + + public static void main(String[] args) { + new BoxedNullCharacterThrowsNPETest().run(); + } + } + + public static class BoxedNullShortThrowsNPETest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + Class<?> cls = BoxedNullShortThrowsNPETest.class; + vh = MethodHandles.byteArrayViewVarHandle(short[].class, ByteOrder.LITTLE_ENDIAN); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + byte[] bytes = new byte[2 * Short.SIZE]; + int index = VarHandleUnitTestHelpers.alignedOffset_short(bytes, 0); + Short newValue = null; + try { + vh.set(bytes, index, newValue); + failUnreachable(); + } catch (NullPointerException ex) { + } + } + + public static void main(String[] args) { + new BoxedNullShortThrowsNPETest().run(); + } + } + + public static class BoxedNullIntegerThrowsNPETest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + byte[] bytes = new byte[2 * Integer.SIZE]; + int index = VarHandleUnitTestHelpers.alignedOffset_int(bytes, 0); + Integer newValue = null; + try { + vh.setVolatile(bytes, index, newValue); + failUnreachable(); + } catch (NullPointerException ex) { + } + } + + public static void main(String[] args) { + new BoxedNullIntegerThrowsNPETest().run(); + } + } + + public static class BoxedNullLongThrowsNPETest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + Class<?> cls = BoxedNullLongThrowsNPETest.class; + vh = MethodHandles.byteBufferViewVarHandle(long[].class, ByteOrder.LITTLE_ENDIAN); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + ByteBuffer bb = ByteBuffer.allocateDirect(2 * Long.SIZE); + int index = VarHandleUnitTestHelpers.alignedOffset_long(bb, 0); + Long newValue = null; + try { + vh.getAndAdd(bb, index, newValue); + failUnreachable(); + } catch (NullPointerException ex) { + } + } + + public static void main(String[] args) { + new BoxedNullLongThrowsNPETest().run(); + } + } + + public static class BoxedNullFloatThrowsNPETest extends VarHandleUnitTest { + private static final VarHandle vh; + + static { + try { + Class<?> cls = BoxedNullFloatThrowsNPETest.class; + vh = MethodHandles.byteBufferViewVarHandle(float[].class, ByteOrder.BIG_ENDIAN); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + ByteBuffer bb = ByteBuffer.allocate(2 * Float.SIZE); + int index = VarHandleUnitTestHelpers.alignedOffset_float(bb, 0); + Float newValue = null; + try { + vh.set(bb, index, newValue); + failUnreachable(); + } catch (NullPointerException ex) { + } + } + + public static void main(String[] args) { + new BoxedNullFloatThrowsNPETest().run(); + } + } + + public static class BoxedNullDoubleThrowsNPETest extends VarHandleUnitTest { + private double d; + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.byteBufferViewVarHandle(double[].class, ByteOrder.LITTLE_ENDIAN); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + byte[] bytes = new byte[3 * Double.SIZE]; + int offset = 1; + ByteBuffer bb = ByteBuffer.wrap(bytes, offset, bytes.length - offset); + int index = VarHandleUnitTestHelpers.alignedOffset_double(bb, 0); + Double newValue = null; + try { + vh.set(bb, index, newValue); + failUnreachable(); + } catch (NullPointerException ex) { + } + } + + public static void main(String[] args) { + new BoxedNullDoubleThrowsNPETest().run(); + } + } + + public static class WideningBooleanArgumentTest extends VarHandleUnitTest { + private static boolean v; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WideningBooleanArgumentTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "v", boolean.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + vh.set(true); + try { + vh.set((byte) 3); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set('c'); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((short) 1); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((int) 1); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((long) 1); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((float) 1.0f); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((double) 1.0); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + + public static void main(String[] args) { + new WideningBooleanArgumentTest().run(); + } + } + + public static class WideningByteArgumentTest extends VarHandleUnitTest { + private static byte v; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WideningByteArgumentTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "v", byte.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + try { + vh.set(true); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + vh.set((byte) 3); + try { + vh.set('c'); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((short) 1); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((int) 1); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((long) 1); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((float) 1.0f); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((double) 1.0); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + + public static void main(String[] args) { + new WideningByteArgumentTest().run(); + } + } + + public static class WideningCharacterArgumentTest extends VarHandleUnitTest { + private static char v; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WideningCharacterArgumentTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "v", char.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + try { + vh.set(true); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((byte) 3); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + vh.set('c'); + try { + vh.set((short) 1); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((int) 1); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((long) 1); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((float) 1.0f); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((double) 1.0); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + + public static void main(String[] args) { + new WideningCharacterArgumentTest().run(); + } + } + + public static class WideningShortArgumentTest extends VarHandleUnitTest { + private static short v; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WideningShortArgumentTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "v", short.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + try { + vh.set(true); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + vh.set((byte) 3); + try { + vh.set('c'); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + vh.set((short) 1); + try { + vh.set((int) 1); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((long) 1); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((float) 1.0f); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((double) 1.0); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + + public static void main(String[] args) { + new WideningShortArgumentTest().run(); + } + } + + public static class WideningIntegerArgumentTest extends VarHandleUnitTest { + private static int v; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WideningIntegerArgumentTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "v", int.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + try { + vh.set(true); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + vh.set((byte) 3); + vh.set('c'); + vh.set((char) 0x8fff); + assertEquals(0x8fff, v); + vh.set((short) 1); + vh.set((int) 1); + try { + vh.set((long) 1); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((float) 1.0f); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((double) 1.0); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + + public static void main(String[] args) { + new WideningIntegerArgumentTest().run(); + } + } + + public static class WideningLongArgumentTest extends VarHandleUnitTest { + private static long v; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WideningLongArgumentTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "v", long.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + try { + vh.set(true); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + vh.set((byte) 3); + vh.set('c'); + vh.set((short) 1); + vh.set((int) 1); + vh.set((long) 1); + try { + vh.set((float) 1.0f); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + vh.set((double) 1.0); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + + public static void main(String[] args) { + new WideningLongArgumentTest().run(); + } + } + + public static class WideningFloatArgumentTest extends VarHandleUnitTest { + private static float v; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WideningFloatArgumentTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "v", float.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + try { + vh.set(true); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + vh.set((byte) 3); + vh.set('c'); + vh.set((short) 1); + vh.set((int) 1); + vh.set((long) 1); + vh.set((float) 1.0f); + try { + vh.set((double) 1.0); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + + public static void main(String[] args) { + new WideningFloatArgumentTest().run(); + } + } + + public static class WideningDoubleArgumentTest extends VarHandleUnitTest { + private static double v; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WideningDoubleArgumentTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "v", double.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + try { + vh.set(true); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + vh.set((byte) 3); + vh.set('c'); + vh.set((short) 1); + vh.set((int) 1); + vh.set((long) 1); + vh.set((double) 1.0f); + vh.set((double) 1.0); + } + + public static void main(String[] args) { + new WideningDoubleArgumentTest().run(); + } + } + + public static class WideningBooleanReturnValueTest extends VarHandleUnitTest { + private static boolean v; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WideningBooleanReturnValueTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "v", boolean.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + vh.set(true); + vh.get(); + boolean z = (boolean) vh.get(); + try { + byte b = (byte) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + char c = (char) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + short s = (short) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + int i = (int) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + long j = (long) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + float f = (float) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + double d = (double) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + } + + public static void main(String[] args) { + new WideningBooleanReturnValueTest().run(); + } + } + + public static class WideningByteReturnValueTest extends VarHandleUnitTest { + private static byte v; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WideningByteReturnValueTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "v", byte.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void doTest() { + vh.set((byte) 3); + vh.get(); + try { + boolean z = (boolean) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + + byte b = (byte) vh.get(); + try { + char c = (char) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + short s = (short) vh.get(); + int i = (int) vh.get(); + long j = (long) vh.get(); + float f = (float) vh.get(); + double d = (double) vh.get(); + } + + public static void main(String[] args) { + new WideningByteReturnValueTest().run(); + } + } + + public static class WideningCharacterReturnValueTest extends VarHandleUnitTest { + private static char v; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WideningCharacterReturnValueTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "v", char.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + new WideningCharacterReturnValueTest().run(); + } + + @Override + protected void doTest() { + vh.set('c'); + vh.get(); + try { + boolean z = (boolean) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + byte b = (byte) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + char c = (char) vh.get(); + try { + short s = (short) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + int i = (int) vh.get(); + long j = (long) vh.get(); + float f = (float) vh.get(); + double d = (double) vh.get(); + } + } + + public static class WideningShortReturnValueTest extends VarHandleUnitTest { + private static short v; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WideningShortReturnValueTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "v", short.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + new WideningShortReturnValueTest().run(); + } + + @Override + protected void doTest() { + vh.set((short) 8888); + vh.get(); + try { + boolean z = (boolean) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + byte b = (byte) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + char c = (char) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + short s = (short) vh.get(); + int i = (int) vh.get(); + long j = (long) vh.get(); + float f = (float) vh.get(); + double d = (double) vh.get(); + } + } + + public static class WideningIntegerReturnValueTest extends VarHandleUnitTest { + private static int v; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WideningIntegerReturnValueTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "v", int.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + new WideningIntegerReturnValueTest().run(); + } + + @Override + protected void doTest() { + vh.set(0x1234fedc); + vh.get(); + try { + boolean z = (boolean) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + byte b = (byte) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + char c = (char) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + short s = (short) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + int i = (int) vh.get(); + long j = (long) vh.get(); + float f = (float) vh.get(); + double d = (double) vh.get(); + } + } + + public static class WideningLongReturnValueTest extends VarHandleUnitTest { + private static long v; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WideningLongReturnValueTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "v", long.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + new WideningLongReturnValueTest().run(); + } + + @Override + protected void doTest() { + vh.set(0xfedcba987654321l); + vh.get(); + try { + boolean z = (boolean) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + byte b = (byte) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + char c = (char) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + short s = (short) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + int i = (int) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + long j = (long) vh.get(); + float f = (float) vh.get(); + double d = (double) vh.get(); + } + } + + public static class WideningFloatReturnValueTest extends VarHandleUnitTest { + private static float v; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WideningFloatReturnValueTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "v", float.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + new WideningFloatReturnValueTest().run(); + } + + @Override + protected void doTest() { + vh.set(7.77e20f); + vh.get(); + try { + boolean z = (boolean) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + byte b = (byte) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + char c = (char) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + short s = (short) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + int i = (int) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + long j = (long) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + float f = (float) vh.get(); + double d = (double) vh.get(); + } + } + + public static class WideningDoubleReturnValueTest extends VarHandleUnitTest { + private static double v; + private static final VarHandle vh; + + static { + try { + Class<?> cls = WideningDoubleReturnValueTest.class; + vh = MethodHandles.lookup().findStaticVarHandle(cls, "v", double.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + new WideningDoubleReturnValueTest().run(); + } + + @Override + protected void doTest() { + vh.set(Math.E); + vh.get(); + try { + boolean z = (boolean) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + byte b = (byte) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + char c = (char) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + short s = (short) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + int i = (int) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + long j = (long) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + try { + float f = (float) vh.get(); + failUnreachable(); + } catch (WrongMethodTypeException ex) { + } + double d = (double) vh.get(); + } + } + + public static class SubtypeTest extends VarHandleUnitTest { + private static final Widget INITIAL_VALUE = Widget.ONE; + private static final VarHandle vh; + private Widget w = INITIAL_VALUE; + + static { + try { + vh = MethodHandles.lookup().findVarHandle(SubtypeTest.class, "w", Widget.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + new SubtypeTest().run(); + } + + // A sub-type of the Widget class + public static class WidgetChild extends Widget { + private int weight; + + public WidgetChild(int requistionNumber, int weight) { + super(requistionNumber); + this.weight = weight; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o instanceof WidgetChild == false) { + return false; + } + WidgetChild wc = (WidgetChild) o; + return (requisitionNumber == wc.requisitionNumber && weight == wc.weight); + } + + public static final WidgetChild ONE = new WidgetChild(1, 100); + public static final WidgetChild TWO = new WidgetChild(2, 2000); + } + + @Override + public void doTest() { + assertEquals(INITIAL_VALUE, vh.getVolatile(this)); + vh.setVolatile(this, null); + Widget rw = (Widget) vh.compareAndExchange(this, null, WidgetChild.ONE); + assertEquals(null, rw); + assertEquals(WidgetChild.ONE, this.w); + WidgetChild rwc = + (WidgetChild) + vh.compareAndExchangeRelease(this, WidgetChild.ONE, WidgetChild.TWO); + assertEquals(WidgetChild.TWO, w); + rwc = (WidgetChild) vh.compareAndExchangeAcquire(this, WidgetChild.TWO, Widget.ONE); + assertEquals(Widget.ONE, w); + assertEquals(false, (boolean) vh.compareAndSet(this, null, null)); + assertEquals(true, vh.compareAndSet(this, Widget.ONE, Widget.TWO)); + assertEquals(Widget.TWO, w); + vh.set(this, null); + assertEquals(null, (Widget) vh.get(this)); + vh.setRelease(this, WidgetChild.ONE); + assertEquals(WidgetChild.ONE, (WidgetChild) vh.getAcquire(this)); + assertEquals(WidgetChild.ONE, w); + vh.setOpaque(this, WidgetChild.TWO); + assertEquals(WidgetChild.TWO, vh.getOpaque(this)); + assertEquals(WidgetChild.TWO, w); + vh.setVolatile(this, null); + assertEquals(null, (Widget) vh.getVolatile(this)); + assertEquals(null, w); + assertEquals(null, (WidgetChild) vh.getAndSet(this, WidgetChild.ONE)); + assertEquals(WidgetChild.ONE, w); + assertEquals(WidgetChild.ONE, (WidgetChild) vh.getAndSetRelease(this, WidgetChild.TWO)); + assertEquals(WidgetChild.TWO, (WidgetChild) vh.getAndSetAcquire(this, WidgetChild.ONE)); + try { + WidgetChild result = (WidgetChild) vh.getAndAdd(this, WidgetChild.ONE); + failUnreachable(); + } catch (UnsupportedOperationException e) { + } + try { + WidgetChild result = (WidgetChild) vh.getAndAddAcquire(this, 1); + failUnreachable(); + } catch (UnsupportedOperationException e) { + } + try { + WidgetChild result = (WidgetChild) vh.getAndAddRelease(this, 1); + failUnreachable(); + } catch (UnsupportedOperationException e) { + } + try { + WidgetChild result = (WidgetChild) vh.getAndBitwiseAnd(this, 1); + failUnreachable(); + } catch (UnsupportedOperationException e) { + } + try { + WidgetChild result = (WidgetChild) vh.getAndBitwiseAndAcquire(this, 1); + failUnreachable(); + } catch (UnsupportedOperationException e) { + } + try { + WidgetChild result = (WidgetChild) vh.getAndBitwiseAndRelease(this, 1); + failUnreachable(); + } catch (UnsupportedOperationException e) { + } + try { + WidgetChild result = (WidgetChild) vh.getAndBitwiseOr(this, 1); + failUnreachable(); + } catch (UnsupportedOperationException e) { + } + try { + WidgetChild result = (WidgetChild) vh.getAndBitwiseOrAcquire(this, 1); + failUnreachable(); + } catch (UnsupportedOperationException e) { + } + try { + WidgetChild result = (WidgetChild) vh.getAndBitwiseOrRelease(this, 1); + failUnreachable(); + } catch (UnsupportedOperationException e) { + } + try { + WidgetChild result = (WidgetChild) vh.getAndBitwiseXor(this, 1); + failUnreachable(); + } catch (UnsupportedOperationException e) { + } + try { + WidgetChild result = (WidgetChild) vh.getAndBitwiseXorAcquire(this, 1); + failUnreachable(); + } catch (UnsupportedOperationException e) { + } + try { + WidgetChild result = (WidgetChild) vh.getAndBitwiseXorRelease(this, 1); + failUnreachable(); + } catch (UnsupportedOperationException e) { + } + } + } + + public static class SupertypeTest extends VarHandleUnitTest { + private Widget w = null; + private static final VarHandle vh; + + static { + try { + vh = MethodHandles.lookup().findVarHandle(SupertypeTest.class, "w", Widget.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + new SupertypeTest().run(); + } + + @Override + public void doTest() { + assertEquals(null, (Object) vh.get(this)); + vh.set(this, Widget.ONE); + assertEquals(Widget.ONE, vh.getVolatile(this)); + try { + vh.setVolatile(this, new Object()); + } catch (ClassCastException e) { + } + } + } + + public static class ImplicitBoxingIntegerTest extends VarHandleUnitTest { + private static Integer field; + private static final VarHandle vh; + + static { + try { + vh = + MethodHandles.lookup() + .findStaticVarHandle( + ImplicitBoxingIntegerTest.class, "field", Integer.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + new ImplicitBoxingIntegerTest().run(); + } + + @Override + public void doTest() { + try { + vh.set(true); + failUnreachable(); + } catch (WrongMethodTypeException e) { + } + try { + vh.set((byte) 0); + failUnreachable(); + } catch (WrongMethodTypeException e) { + } + try { + vh.set((short) 1); + failUnreachable(); + } catch (WrongMethodTypeException e) { + } + try { + vh.set('A'); + failUnreachable(); + } catch (WrongMethodTypeException e) { + } + vh.set(2); + try { + vh.setRelease(Long.MAX_VALUE); + } catch (WrongMethodTypeException e) { + } + try { + vh.setRelease(Float.MAX_VALUE); + } catch (WrongMethodTypeException e) { + } + try { + vh.setRelease(Double.MAX_VALUE); + } catch (WrongMethodTypeException e) { + } + vh.set(null); + vh.set(Integer.valueOf(Integer.MAX_VALUE)); + } + } + + public static void main(String[] args) { + VoidReturnTypeTest.main(args); + + BoxedNullBooleanThrowsNPETest.main(args); + BoxedNullByteThrowsNPETest.main(args); + BoxedNullCharacterThrowsNPETest.main(args); + BoxedNullShortThrowsNPETest.main(args); + BoxedNullIntegerThrowsNPETest.main(args); + BoxedNullLongThrowsNPETest.main(args); + BoxedNullFloatThrowsNPETest.main(args); + BoxedNullDoubleThrowsNPETest.main(args); + + WideningBooleanArgumentTest.main(args); + WideningByteArgumentTest.main(args); + WideningCharacterArgumentTest.main(args); + WideningShortArgumentTest.main(args); + WideningIntegerArgumentTest.main(args); + WideningLongArgumentTest.main(args); + WideningFloatArgumentTest.main(args); + WideningDoubleArgumentTest.main(args); + + WideningBooleanReturnValueTest.main(args); + WideningByteReturnValueTest.main(args); + WideningCharacterReturnValueTest.main(args); + WideningShortReturnValueTest.main(args); + WideningIntegerReturnValueTest.main(args); + WideningLongReturnValueTest.main(args); + WideningFloatReturnValueTest.main(args); + WideningDoubleReturnValueTest.main(args); + + SubtypeTest.main(args); + SupertypeTest.main(args); + + ImplicitBoxingIntegerTest.main(args); + } +} diff --git a/test/712-varhandle-invocations/src/VarHandleUnitTest.java b/test/712-varhandle-invocations/src/VarHandleUnitTest.java new file mode 100644 index 0000000000..601d470950 --- /dev/null +++ b/test/712-varhandle-invocations/src/VarHandleUnitTest.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2018 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. + */ + +// Base class for VarHandle unit tests for accessor operations +public abstract class VarHandleUnitTest { + public static VarHandleUnitTestCollector DEFAULT_COLLECTOR = new VarHandleUnitTestCollector(); + + // Error log (lazily initialized on failure). + private StringBuilder lazyErrorLog = null; + + // Tracker of test events (starts, skips, ends) + private final VarHandleUnitTestCollector collector; + + public VarHandleUnitTest(VarHandleUnitTestCollector collector) { + this.collector = collector; + } + + public VarHandleUnitTest() { + this.collector = DEFAULT_COLLECTOR; + } + + // Method that can be overloaded to signify that a test should be + // run or skipped. Returns true if the test should be run and + // false if the test should be skipped. + public boolean checkGuard() { + return true; + } + + // Method that implementations should use to perform a specific test. + protected abstract void doTest() throws Exception; + + public final void assertTrue(boolean value) { + assertEquals(true, value); + } + + public final void assertFalse(boolean value) { + assertEquals(false, value); + } + + public final void assertEquals(boolean expected, boolean actual) { + assertEquals(Boolean.valueOf(expected), Boolean.valueOf(actual)); + } + + public final void assertEquals(byte expected, byte actual) { + assertEquals(Byte.valueOf(expected), Byte.valueOf(actual)); + } + + public final void assertEquals(char expected, char actual) { + assertEquals(Character.valueOf(expected), Character.valueOf(actual)); + } + + public final void assertEquals(short expected, short actual) { + assertEquals(Short.valueOf(expected), Short.valueOf(actual)); + } + + public final void assertEquals(int expected, int actual) { + assertEquals(Integer.valueOf(expected), Integer.valueOf(actual)); + } + + public final void assertEquals(long expected, long actual) { + assertEquals(Long.valueOf(expected), Long.valueOf(actual)); + } + + public final void assertEquals(float expected, float actual) { + assertEquals(Float.valueOf(expected), Float.valueOf(actual)); + } + + public final void assertEquals(double expected, double actual) { + assertEquals(Double.valueOf(expected), Double.valueOf(actual)); + } + + public final void assertEquals(Object expected, Object actual) { + if (expected == null) { + if (actual == null) { + return; + } + } else if (expected.equals(actual)) { + return; + } + failNotEquals("Failed assertion (expected != actual)", expected, actual); + } + + public final void failUnreachable() { + fail("Unreachable code"); + } + + public final void run() { + collector.start(getClass().getSimpleName()); + if (!checkGuard()) { + collector.skip(); + return; + } + + try { + doTest(); + } catch (Exception e) { + fail("Unexpected exception", e); + } finally { + if (lazyErrorLog == null) { + collector.success(); + } else { + collector.fail(lazyErrorLog.toString()); + } + } + } + + private void failNotEquals(String message, Object expected, Object actual) { + errorLog() + .append(message) + .append(": ") + .append(expected) + .append(" != ") + .append(actual) + .append(" in ") + .append(getSourceInfo()) + .append('\n'); + } + + private void fail(String message) { + errorLog().append(message).append(" in ").append(getSourceInfo()).append('\n'); + } + + private void fail(String message, String detail) { + errorLog() + .append(message) + .append(": ") + .append(detail) + .append(" in ") + .append(getSourceInfo()) + .append('\n'); + } + + private void fail(String message, Exception e) { + errorLog() + .append(message) + .append(": ") + .append(e.toString()) + .append(" in ") + .append(getSourceInfo(e)) + .append('\n'); + } + + private String getSourceInfo(Exception e) { + // Unit test has thrown an exception. Stack likely looks like + // runtime frames then unit test frames then + // VarHandleUnitFrames. + StackTraceElement[] stackTraceElements = e.getStackTrace(); + int index = 1; + for (int i = 1; i < stackTraceElements.length; ++i) { + if ("VarHandleUnitTest".equals(stackTraceElements[i].getClassName())) { + return stackTraceElements[i - 1].toString(); + } + } + return "Unknown"; + } + + private String getSourceInfo() { + // Gets source info for a failure such as an assertion. The + // test has called a method on VarHandleUnitTest so the stack + // looks like some frames in VarHandleUnitTest methods and then + // a frame in the test itself. + StackTraceElement[] stackTraceElements = new Exception().getStackTrace(); + for (StackTraceElement stackTraceElement : stackTraceElements) { + if (!"VarHandleUnitTest".equals(stackTraceElement.getClassName())) { + return stackTraceElement.toString(); + } + } + return "Unknown"; + } + + private StringBuilder errorLog() { + if (lazyErrorLog == null) { + lazyErrorLog = new StringBuilder(); + } + return lazyErrorLog; + } +} diff --git a/test/712-varhandle-invocations/src/VarHandleUnitTestCollector.java b/test/712-varhandle-invocations/src/VarHandleUnitTestCollector.java new file mode 100644 index 0000000000..bc64c0c8b1 --- /dev/null +++ b/test/712-varhandle-invocations/src/VarHandleUnitTestCollector.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 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. + */ + +import java.io.PrintStream; + +// Results collector for VarHandle Unit tests +public final class VarHandleUnitTestCollector { + private final PrintStream out = System.out; + + private int numberOfSuccesses; + private int numberOfSkips; + private int numberOfFailures; + + public void start(String testName) { + out.print(testName); + out.print("..."); + } + + public void skip() { + numberOfSkips += 1; + out.println("SKIP"); + } + + public void success() { + numberOfSuccesses += 1; + out.println("OK"); + } + + public void fail(String errorMessage) { + numberOfFailures += 1; + out.println("FAIL"); + out.print(errorMessage); + } + + public void printSummary() { + out.append(Integer.toString(numberOfSuccesses)) + .append(" successes, ") + .append(Integer.toString(numberOfSkips)) + .append(" skips, ") + .append(Integer.toString(numberOfFailures)) + .append(" failures."); + out.println(); + } + + boolean failuresOccurred() { + return numberOfFailures != 0; + } +} diff --git a/test/712-varhandle-invocations/src/VarHandleUnitTestHelpers.java b/test/712-varhandle-invocations/src/VarHandleUnitTestHelpers.java new file mode 100644 index 0000000000..6f72e9962f --- /dev/null +++ b/test/712-varhandle-invocations/src/VarHandleUnitTestHelpers.java @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2018 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. + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.VarHandle; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class VarHandleUnitTestHelpers { + public static boolean isRunningOnAndroid() { + return System.getProperty("java.vm.vendor").contains("Android"); + } + + public static boolean is64Bit() { + // The behaviour of certain accessors depends on the ISA word size. + if (isRunningOnAndroid()) { + try { + Class<?> runtimeClass = Class.forName("dalvik.system.VMRuntime"); + MethodHandle getRuntimeMH = + MethodHandles.lookup() + .findStatic( + runtimeClass, + "getRuntime", + MethodType.methodType(runtimeClass)); + Object runtime = getRuntimeMH.invoke(); + MethodHandle is64BitMH = + MethodHandles.lookup() + .findVirtual( + runtimeClass, + "is64Bit", + MethodType.methodType(boolean.class)); + return (boolean) is64BitMH.invoke(runtime); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } else { + return System.getProperty("sun.arch.data.model").equals("64"); + } + } + + public static boolean getBytesAs_boolean(byte[] array, int index, ByteOrder order) { + return getBytesAs_boolean(ByteBuffer.wrap(array), index, order); + } + + public static byte getBytesAs_byte(byte[] array, int index, ByteOrder order) { + return getBytesAs_byte(ByteBuffer.wrap(array), index, order); + } + + public static char getBytesAs_char(byte[] array, int index, ByteOrder order) { + return getBytesAs_char(ByteBuffer.wrap(array), index, order); + } + + public static short getBytesAs_short(byte[] array, int index, ByteOrder order) { + return getBytesAs_short(ByteBuffer.wrap(array), index, order); + } + + public static int getBytesAs_int(byte[] array, int index, ByteOrder order) { + return getBytesAs_int(ByteBuffer.wrap(array), index, order); + } + + public static long getBytesAs_long(byte[] array, int index, ByteOrder order) { + return getBytesAs_long(ByteBuffer.wrap(array), index, order); + } + + public static float getBytesAs_float(byte[] array, int index, ByteOrder order) { + return getBytesAs_float(ByteBuffer.wrap(array), index, order); + } + + public static double getBytesAs_double(byte[] array, int index, ByteOrder order) { + return getBytesAs_double(ByteBuffer.wrap(array), index, order); + } + + public static boolean getBytesAs_boolean(ByteBuffer buffer, int index, ByteOrder order) { + return buffer.order(order).get(index) != 0; + } + + public static byte getBytesAs_byte(ByteBuffer buffer, int index, ByteOrder order) { + return buffer.order(order).get(index); + } + + public static char getBytesAs_char(ByteBuffer buffer, int index, ByteOrder order) { + return buffer.order(order).getChar(index); + } + + public static short getBytesAs_short(ByteBuffer buffer, int index, ByteOrder order) { + return buffer.order(order).getShort(index); + } + + public static int getBytesAs_int(ByteBuffer buffer, int index, ByteOrder order) { + return buffer.order(order).getInt(index); + } + + public static long getBytesAs_long(ByteBuffer buffer, int index, ByteOrder order) { + return buffer.order(order).getLong(index); + } + + public static float getBytesAs_float(ByteBuffer buffer, int index, ByteOrder order) { + return buffer.order(order).getFloat(index); + } + + public static double getBytesAs_double(ByteBuffer buffer, int index, ByteOrder order) { + return buffer.order(order).getDouble(index); + } + + public static void setBytesAs_boolean(byte[] array, int index, boolean value, ByteOrder order) { + setBytesAs_boolean(ByteBuffer.wrap(array), index, value, order); + } + + public static void setBytesAs_byte(byte[] array, int index, byte value, ByteOrder order) { + setBytesAs_byte(ByteBuffer.wrap(array), index, value, order); + } + + public static void setBytesAs_char(byte[] array, int index, char value, ByteOrder order) { + setBytesAs_char(ByteBuffer.wrap(array), index, value, order); + } + + public static void setBytesAs_short(byte[] array, int index, short value, ByteOrder order) { + setBytesAs_short(ByteBuffer.wrap(array), index, value, order); + } + + public static void setBytesAs_int(byte[] array, int index, int value, ByteOrder order) { + setBytesAs_int(ByteBuffer.wrap(array), index, value, order); + } + + public static void setBytesAs_long(byte[] array, int index, long value, ByteOrder order) { + setBytesAs_long(ByteBuffer.wrap(array), index, value, order); + } + + public static void setBytesAs_float(byte[] array, int index, float value, ByteOrder order) { + setBytesAs_float(ByteBuffer.wrap(array), index, value, order); + } + + public static void setBytesAs_double(byte[] array, int index, double value, ByteOrder order) { + setBytesAs_double(ByteBuffer.wrap(array), index, value, order); + } + + public static void setBytesAs_boolean( + ByteBuffer buffer, int index, boolean value, ByteOrder order) { + buffer.order(order).put(index, value ? (byte) 1 : (byte) 0); + } + + public static void setBytesAs_byte(ByteBuffer buffer, int index, byte value, ByteOrder order) { + buffer.order(order).put(index, value); + } + + public static void setBytesAs_char(ByteBuffer buffer, int index, char value, ByteOrder order) { + buffer.order(order).putChar(index, value); + } + + public static void setBytesAs_short( + ByteBuffer buffer, int index, short value, ByteOrder order) { + buffer.order(order).putShort(index, value); + } + + public static void setBytesAs_int(ByteBuffer buffer, int index, int value, ByteOrder order) { + buffer.order(order).putInt(index, value); + } + + public static void setBytesAs_long(ByteBuffer buffer, int index, long value, ByteOrder order) { + buffer.order(order).putLong(index, value); + } + + public static void setBytesAs_float( + ByteBuffer buffer, int index, float value, ByteOrder order) { + buffer.order(order).putFloat(index, value); + } + + public static void setBytesAs_double( + ByteBuffer buffer, int index, double value, ByteOrder order) { + buffer.order(order).putDouble(index, value); + } + + // Until ART is running on an OpenJDK9 based runtime, there are no + // calls to help with alignment. OpenJDK9 introduces + // ByteBuffer.alignedSlice() and ByteBuffer.alignmentOffset(). RI + // and ART have different data structure alignments which may make + // porting code interesting. + + public static int alignedOffset_char(ByteBuffer buffer, int start) { + return alignedOffset_short(buffer, start); + } + + public static int alignedOffset_short(ByteBuffer buffer, int start) { + for (int i = 0; i < Short.SIZE; ++i) { + try { + vh_probe_short.getVolatile(buffer, start + i); + return start + i; + } catch (IllegalStateException e) { + // Unaligned access. + } + } + return start; + } + + public static int alignedOffset_int(ByteBuffer buffer, int start) { + for (int i = 0; i < Integer.SIZE; ++i) { + try { + vh_probe_int.getVolatile(buffer, start + i); + return start + i; + } catch (IllegalStateException e) { + // Unaligned access. + } catch (Exception e) { + break; + } + } + return start; + } + + public static int alignedOffset_long(ByteBuffer buffer, int start) { + for (int i = 0; i < Long.SIZE; ++i) { + try { + vh_probe_long.getVolatile(buffer, start + i); + return start + i; + } catch (IllegalStateException e) { + // Unaligned access. + } catch (UnsupportedOperationException e) { + // 64-bit operation is not supported irrespective of alignment. + break; + } + } + return start; + } + + public static int alignedOffset_float(ByteBuffer buffer, int start) { + return alignedOffset_int(buffer, start); + } + + public static int alignedOffset_double(ByteBuffer buffer, int start) { + return alignedOffset_long(buffer, start); + } + + public static int alignedOffset_char(byte[] array, int start) { + return alignedOffset_char(ByteBuffer.wrap(array), start); + } + + public static int alignedOffset_short(byte[] array, int start) { + return alignedOffset_short(ByteBuffer.wrap(array), start); + } + + public static int alignedOffset_int(byte[] array, int start) { + return alignedOffset_int(ByteBuffer.wrap(array), start); + } + + public static int alignedOffset_long(byte[] array, int start) { + return alignedOffset_long(ByteBuffer.wrap(array), start); + } + + public static int alignedOffset_float(byte[] array, int start) { + return alignedOffset_float(ByteBuffer.wrap(array), start); + } + + public static int alignedOffset_double(byte[] array, int start) { + return alignedOffset_double(ByteBuffer.wrap(array), start); + } + + static { + ByteOrder order = ByteOrder.LITTLE_ENDIAN; + vh_probe_short = MethodHandles.byteBufferViewVarHandle(short[].class, order); + vh_probe_int = MethodHandles.byteBufferViewVarHandle(int[].class, order); + vh_probe_long = MethodHandles.byteBufferViewVarHandle(long[].class, order); + } + + private static final VarHandle vh_probe_short; + private static final VarHandle vh_probe_int; + private static final VarHandle vh_probe_long; +} diff --git a/test/712-varhandle-invocations/src/Widget.java b/test/712-varhandle-invocations/src/Widget.java new file mode 100644 index 0000000000..0282ff8d64 --- /dev/null +++ b/test/712-varhandle-invocations/src/Widget.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018 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. + */ + +// Widget class for reference type accessor tests. +public class Widget { + protected int requisitionNumber; + + public Widget(int requisitionNumber) { + this.requisitionNumber = requisitionNumber; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Widget)) { + return false; + } + Widget wo = (Widget) o; + return requisitionNumber == wo.requisitionNumber; + } + + public static final Widget ONE = new Widget(1); + public static final Widget TWO = new Widget(2); +} diff --git a/test/712-varhandle-invocations/util-src/generate_java.py b/test/712-varhandle-invocations/util-src/generate_java.py new file mode 100644 index 0000000000..9520b53844 --- /dev/null +++ b/test/712-varhandle-invocations/util-src/generate_java.py @@ -0,0 +1,876 @@ +#!/usr/bin/python3 +# +# Copyright (C) 2018 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. + +""" +Generate java test files for 712-varhandle-invocations +""" + +from enum import Enum +from pathlib import Path +from random import Random +from string import Template + +import io +import re +import sys + +class JavaType(object): + def __init__(self, name, examples, supports_bitwise=False, supports_numeric=False): + self.name=name + self.examples=examples + self.supports_bitwise=supports_bitwise + self.supports_numeric=supports_numeric + + def is_value_type(self): + return False + + def __repr__(self): + return self.name + + def __str__(self): + return self.name + +class ValueType(JavaType): + def __init__(self, name, boxed_type, examples, ordinal=-1, width=-1, supports_bitwise=True, supports_numeric=True): + JavaType.__init__(self, name, examples, supports_bitwise, supports_numeric) + self.ordinal=ordinal + self.width=width + self.boxed_type=boxed_type + + def boxing_method(self): + return self.boxed_type + ".valueOf" + + def unboxing_method(self): + return self.name + "Value" + + def is_value_type(self): + return True + + def __eq__(self, other): + return self.ordinal == other.ordinal + + def __hash__(self): + return self.ordinal + + def __le__(self, other): + return self.ordinal < other.ordinal + + def __repr__(self): + return self.name + + def __str__(self): + return self.name + +BOOLEAN_TYPE = ValueType("boolean", "Boolean", [ "true", "false" ], ordinal = 0, width = 1, supports_numeric=False) +BYTE_TYPE=ValueType("byte", "Byte", [ "(byte) -128", "(byte) -61", "(byte) 7", "(byte) 127", "(byte) 33" ], ordinal=1, width=1) +SHORT_TYPE=ValueType("short", "Short", [ "(short) -32768", "(short) -384", "(short) 32767", "(short) 0xaa55" ], ordinal=2, width=2) +CHAR_TYPE=ValueType("char", "Character", [ r"'A'", r"'#'", r"'$'", r"'Z'", r"'t'", r"'c'" ], ordinal=3, width=2) +INT_TYPE=ValueType("int", "Integer", [ "-0x01234567", "0x7f6e5d4c", "0x12345678", "0x10215220", "42" ], ordinal=4, width=4) +LONG_TYPE=ValueType("long", "Long", [ "-0x0123456789abcdefl", "0x789abcdef0123456l", "0xfedcba9876543210l" ], ordinal=5, width=8) +FLOAT_TYPE=ValueType("float", "Float", [ "-7.77e23f", "1.234e-17f", "3.40e36f", "-8.888e3f", "4.442e11f" ], ordinal=6, width=4, supports_bitwise=False) +DOUBLE_TYPE=ValueType("double", "Double", [ "-1.0e-200", "1.11e200", "3.141", "1.1111", "6.022e23", "6.626e-34" ], ordinal=7, width=4, supports_bitwise=False) + +VALUE_TYPES = { BOOLEAN_TYPE, BYTE_TYPE, SHORT_TYPE, CHAR_TYPE, INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE } + +WIDENING_CONVERSIONS = { + BOOLEAN_TYPE : set(), + BYTE_TYPE : { SHORT_TYPE, INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE }, + SHORT_TYPE : { INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE }, + CHAR_TYPE : { INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE }, + INT_TYPE : { LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE }, + LONG_TYPE : { FLOAT_TYPE, DOUBLE_TYPE }, + FLOAT_TYPE : { DOUBLE_TYPE }, + DOUBLE_TYPE : set() +} + +def types_that_widen_to(var_type): + types_that_widen = { var_type } + for src_type in WIDENING_CONVERSIONS: + if var_type in WIDENING_CONVERSIONS[src_type]: + types_that_widen.add(src_type) + return types_that_widen + +class VarHandleKind(object): + ALL_SUPPORTED_TYPES = VALUE_TYPES + VIEW_SUPPORTED_TYPES = list(filter(lambda x : x.width >= 2, ALL_SUPPORTED_TYPES)) + + def __init__(self, name, imports=[], declarations=[], lookup='', coordinates=[], get_value='', may_throw_read_only=False): + self.name = name + self.imports = imports + self.declarations = declarations + self.lookup = lookup + self.coordinates = coordinates + self.get_value_ = get_value + self.may_throw_read_only = may_throw_read_only + + def get_name(self): + return self.name + + def get_coordinates(self): + return self.coordinates + + def get_field_declarations(self, dictionary): + return list(map(lambda d: Template(d).safe_substitute(dictionary), self.declarations)) + + def get_imports(self): + return self.imports + + def get_lookup(self, dictionary): + return Template(self.lookup).safe_substitute(dictionary) + + def get_supported_types(self): + return VarHandleKind.VIEW_SUPPORTED_TYPES if self.is_view() else VarHandleKind.ALL_SUPPORTED_TYPES + + def is_view(self): + return "View" in self.name + + def get_value(self, dictionary): + return Template(self.get_value_).safe_substitute(dictionary) + +FIELD_VAR_HANDLE = VarHandleKind("Field", + [ + 'java.lang.invoke.MethodHandles', + 'java.lang.invoke.VarHandle' + ], + [ + "${var_type} field = ${initial_value}" + ], + 'MethodHandles.lookup().findVarHandle(${test_class}.class, "field", ${var_type}.class)', + [ + 'this' + ], + 'field', + may_throw_read_only = False) + +FINAL_FIELD_VAR_HANDLE = VarHandleKind("FinalField", + [ + 'java.lang.invoke.MethodHandles', + 'java.lang.invoke.VarHandle' + ], + [ + "${var_type} field = ${initial_value}" + ], + 'MethodHandles.lookup().findVarHandle(${test_class}.class, "field", ${var_type}.class)', + [ + 'this' + ], + 'field', + may_throw_read_only = False) + +STATIC_FIELD_VAR_HANDLE = VarHandleKind("StaticField", + [ + 'java.lang.invoke.MethodHandles', + 'java.lang.invoke.VarHandle' + ], + [ + "static ${var_type} field = ${initial_value}" + ], + 'MethodHandles.lookup().findStaticVarHandle(${test_class}.class, "field", ${var_type}.class)', + [], + 'field', + may_throw_read_only = False) + +STATIC_FINAL_FIELD_VAR_HANDLE = VarHandleKind("StaticFinalField", + [ + 'java.lang.invoke.MethodHandles', + 'java.lang.invoke.VarHandle' + ], + [ + "static ${var_type} field = ${initial_value}" + ], + 'MethodHandles.lookup().findStaticVarHandle(${test_class}.class, "field", ${var_type}.class)', + [], + 'field', + may_throw_read_only = False) + +ARRAY_ELEMENT_VAR_HANDLE = VarHandleKind("ArrayElement", + [ + 'java.lang.invoke.MethodHandles', + 'java.lang.invoke.VarHandle' + ], + [ + "${var_type}[] array = new ${var_type}[11]", + "int index = 3", + "{ array[index] = ${initial_value}; }" + ], + 'MethodHandles.arrayElementVarHandle(${var_type}[].class)', + [ 'array', 'index'], + 'array[index]', + may_throw_read_only = False) + +BYTE_ARRAY_LE_VIEW_VAR_HANDLE = VarHandleKind("ByteArrayViewLE", + [ + 'java.lang.invoke.MethodHandles', + 'java.lang.invoke.VarHandle', + 'java.nio.ByteOrder' + ], + [ + "byte[] array = new byte[27]", + "int index = 8", + "{" + " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(array, index);" + " VarHandleUnitTestHelpers.setBytesAs_${var_type}(array, index, ${initial_value}, ByteOrder.LITTLE_ENDIAN);" + "}" + ], + 'MethodHandles.byteArrayViewVarHandle(${var_type}[].class, ByteOrder.LITTLE_ENDIAN)', + [ + 'array', + 'index' + ], + 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(array, index, ByteOrder.LITTLE_ENDIAN)', + may_throw_read_only = False) + +BYTE_ARRAY_BE_VIEW_VAR_HANDLE = VarHandleKind("ByteArrayViewBE", + [ + 'java.lang.invoke.MethodHandles', + 'java.lang.invoke.VarHandle', + 'java.nio.ByteOrder' + ], + [ + "byte[] array = new byte[27]", + "int index = 8", + "{" + " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(array, index);" + " VarHandleUnitTestHelpers.setBytesAs_${var_type}(array, index, ${initial_value}, ByteOrder.BIG_ENDIAN);" + "}" + ], + 'MethodHandles.byteArrayViewVarHandle(${var_type}[].class, ByteOrder.BIG_ENDIAN)', + [ + 'array', + 'index' + ], + 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(array, index, ByteOrder.BIG_ENDIAN)', + may_throw_read_only = False) + +DIRECT_BYTE_BUFFER_LE_VIEW_VAR_HANDLE = VarHandleKind("DirectByteBufferViewLE", + [ + 'java.lang.invoke.MethodHandles', + 'java.lang.invoke.VarHandle', + 'java.nio.ByteBuffer', + 'java.nio.ByteOrder' + ], + [ + "ByteBuffer bb = ByteBuffer.allocateDirect(31)", + "int index = 8", + "{" + " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);" + " VarHandleUnitTestHelpers.setBytesAs_${var_type}(bb, index, ${initial_value}, ByteOrder.LITTLE_ENDIAN);" + "}" + ], + 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.LITTLE_ENDIAN)', + [ + 'bb', + 'index' + ], + 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.LITTLE_ENDIAN)', + may_throw_read_only = False) + +DIRECT_BYTE_BUFFER_BE_VIEW_VAR_HANDLE = VarHandleKind("DirectByteBufferViewBE", + [ + 'java.lang.invoke.MethodHandles', + 'java.lang.invoke.VarHandle', + 'java.nio.ByteBuffer', + 'java.nio.ByteOrder' + ], + [ + "ByteBuffer bb = ByteBuffer.allocateDirect(31)", + "int index = 8", + "{" + " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);" + " VarHandleUnitTestHelpers.setBytesAs_${var_type}(bb, index, ${initial_value}, ByteOrder.BIG_ENDIAN);" + "}" + ], + 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.BIG_ENDIAN)', + [ + 'bb', + 'index' + ], + 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.BIG_ENDIAN)', + may_throw_read_only = False) + +HEAP_BYTE_BUFFER_LE_VIEW_VAR_HANDLE = VarHandleKind("HeapByteBufferViewLE", + [ + 'java.lang.invoke.MethodHandles', + 'java.lang.invoke.VarHandle', + 'java.nio.ByteBuffer', + 'java.nio.ByteOrder' + ], + [ + "byte[] array = new byte[36]", + "int offset = 8", + "ByteBuffer bb = ByteBuffer.wrap(array, offset, array.length - offset)", + "int index = 8", + "{" + " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);" + " VarHandleUnitTestHelpers.setBytesAs_${var_type}(bb, index, ${initial_value}, ByteOrder.LITTLE_ENDIAN);" + "}" + ], + 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.LITTLE_ENDIAN)', + [ + 'bb', + 'index' + ], + 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.LITTLE_ENDIAN)', + may_throw_read_only = False) + +HEAP_BYTE_BUFFER_BE_VIEW_VAR_HANDLE = VarHandleKind("HeapByteBufferViewBE", + [ + 'java.lang.invoke.MethodHandles', + 'java.lang.invoke.VarHandle', + 'java.nio.ByteBuffer', + 'java.nio.ByteOrder' + ], + [ + "byte[] array = new byte[47]", + "int offset = 8", + "ByteBuffer bb = ByteBuffer.wrap(array, offset, array.length - offset)", + "int index = 8", + "{" + " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);" + " VarHandleUnitTestHelpers.setBytesAs_${var_type}(bb, index, ${initial_value}, ByteOrder.BIG_ENDIAN);" + "}" + ], + 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.BIG_ENDIAN)', + [ + 'bb', + 'index' + ], + 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.BIG_ENDIAN)', + may_throw_read_only = False) + +HEAP_BYTE_BUFFER_RO_LE_VIEW_VAR_HANDLE = VarHandleKind("HeapByteBufferReadOnlyViewLE", + [ + 'java.lang.invoke.MethodHandles', + 'java.lang.invoke.VarHandle', + 'java.nio.ByteBuffer', + 'java.nio.ByteOrder', + 'java.nio.ReadOnlyBufferException' + ], + [ + "byte[] array = new byte[43]", + "int index = 8", + "ByteBuffer bb", + "{" + " bb = ByteBuffer.wrap(array).asReadOnlyBuffer();" + " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, index);" + " VarHandleUnitTestHelpers.setBytesAs_${var_type}(array, index, ${initial_value}, ByteOrder.LITTLE_ENDIAN);" + " bb = bb.asReadOnlyBuffer();" + + "}" + ], + 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.LITTLE_ENDIAN)', + [ + 'bb', + 'index' + ], + 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.LITTLE_ENDIAN)', + may_throw_read_only = True) + +HEAP_BYTE_BUFFER_RO_BE_VIEW_VAR_HANDLE = VarHandleKind("HeapByteBufferReadOnlyViewBE", + [ + 'java.lang.invoke.MethodHandles', + 'java.lang.invoke.VarHandle', + 'java.nio.ByteBuffer', + 'java.nio.ByteOrder', + 'java.nio.ReadOnlyBufferException' + ], + [ + "byte[] array = new byte[29]", + "int index", + "ByteBuffer bb", + "{" + " bb = ByteBuffer.wrap(array);" + " index = VarHandleUnitTestHelpers.alignedOffset_${var_type}(bb, 8);" + " VarHandleUnitTestHelpers.setBytesAs_${var_type}(array, index, ${initial_value}, ByteOrder.BIG_ENDIAN);" + " bb = bb.asReadOnlyBuffer();" + "}" + ], + 'MethodHandles.byteBufferViewVarHandle(${var_type}[].class, ByteOrder.BIG_ENDIAN)', + [ + 'bb', + 'index' + ], + 'VarHandleUnitTestHelpers.getBytesAs_${var_type}(bb, index, ByteOrder.BIG_ENDIAN)', + may_throw_read_only = True) + +ALL_FIELD_VAR_HANDLE_KINDS = [ + FIELD_VAR_HANDLE, + FINAL_FIELD_VAR_HANDLE, + STATIC_FIELD_VAR_HANDLE, + STATIC_FINAL_FIELD_VAR_HANDLE +] + +ALL_BYTE_VIEW_VAR_HANDLE_KINDS = [ + BYTE_ARRAY_LE_VIEW_VAR_HANDLE, + BYTE_ARRAY_BE_VIEW_VAR_HANDLE, + DIRECT_BYTE_BUFFER_LE_VIEW_VAR_HANDLE, + DIRECT_BYTE_BUFFER_BE_VIEW_VAR_HANDLE, + HEAP_BYTE_BUFFER_LE_VIEW_VAR_HANDLE, + HEAP_BYTE_BUFFER_BE_VIEW_VAR_HANDLE, + HEAP_BYTE_BUFFER_RO_LE_VIEW_VAR_HANDLE, + HEAP_BYTE_BUFFER_RO_BE_VIEW_VAR_HANDLE +] + +ALL_VAR_HANDLE_KINDS = ALL_FIELD_VAR_HANDLE_KINDS + [ ARRAY_ELEMENT_VAR_HANDLE ] + ALL_BYTE_VIEW_VAR_HANDLE_KINDS + +class AccessModeForm(Enum): + GET = 0 + SET = 1 + STRONG_COMPARE_AND_SET = 2 + WEAK_COMPARE_AND_SET = 3 + COMPARE_AND_EXCHANGE = 4 + GET_AND_SET = 5 + GET_AND_UPDATE_BITWISE = 6 + GET_AND_UPDATE_NUMERIC = 7 + +class VarHandleAccessor: + def __init__(self, method_name): + self.method_name = method_name + self.access_mode = self.get_access_mode(method_name) + self.access_mode_form = self.get_access_mode_form(method_name) + + def get_return_type(self, var_type): + if self.access_mode_form == AccessModeForm.SET: + return None + elif (self.access_mode_form == AccessModeForm.STRONG_COMPARE_AND_SET or + self.access_mode_form == AccessModeForm.WEAK_COMPARE_AND_SET): + return BOOLEAN_TYPE + else: + return var_type + + def get_number_of_var_type_arguments(self): + if self.access_mode_form == AccessModeForm.GET: + return 0 + elif (self.access_mode_form == AccessModeForm.SET or + self.access_mode_form == AccessModeForm.GET_AND_SET or + self.access_mode_form == AccessModeForm.GET_AND_UPDATE_BITWISE or + self.access_mode_form == AccessModeForm.GET_AND_UPDATE_NUMERIC): + return 1 + elif (self.access_mode_form == AccessModeForm.STRONG_COMPARE_AND_SET or + self.access_mode_form == AccessModeForm.WEAK_COMPARE_AND_SET or + self.access_mode_form == AccessModeForm.COMPARE_AND_EXCHANGE): + return 2 + else: + raise ValueError(self.access_mode_form) + + def is_read_only(self): + return self.access_mode_form == AccessModeForm.GET + + def get_java_bitwise_operator(self): + if "BitwiseAnd" in self.method_name: + return "&" + elif "BitwiseOr" in self.method_name: + return "|" + elif "BitwiseXor" in self.method_name: + return "^" + raise ValueError(self.method_name) + + def get_java_numeric_operator(self): + if "Add" in self.method_name: + return "+" + raise ValueError(self.method_name) + + @staticmethod + def get_access_mode(accessor_method): + """Converts an access method name to AccessMode value. For example, getAndSet becomes GET_AND_SET""" + return re.sub('([A-Z])', r'_\1', accessor_method).upper() + + @staticmethod + def get_access_mode_form(accessor_method): + prefix_mode_list = [ + ('getAndAdd', AccessModeForm.GET_AND_UPDATE_NUMERIC), + ('getAndBitwise', AccessModeForm.GET_AND_UPDATE_BITWISE), + ('getAndSet', AccessModeForm.GET_AND_SET), + ('get', AccessModeForm.GET), + ('set', AccessModeForm.SET), + ('compareAndSet', AccessModeForm.STRONG_COMPARE_AND_SET), + ('weakCompareAndSet', AccessModeForm.WEAK_COMPARE_AND_SET), + ('compareAndExchange', AccessModeForm.COMPARE_AND_EXCHANGE)] + for prefix, mode in prefix_mode_list: + if accessor_method.startswith(prefix): + return mode + raise ValueError(accessor_method) + +VAR_HANDLE_ACCESSORS = [ + VarHandleAccessor('get'), + VarHandleAccessor('set'), + VarHandleAccessor('getVolatile'), + VarHandleAccessor('setVolatile'), + VarHandleAccessor('getAcquire'), + VarHandleAccessor('setRelease'), + VarHandleAccessor('getOpaque'), + VarHandleAccessor('setOpaque'), + VarHandleAccessor('compareAndSet'), + VarHandleAccessor('compareAndExchange'), + VarHandleAccessor('compareAndExchangeAcquire'), + VarHandleAccessor('compareAndExchangeRelease'), + VarHandleAccessor('weakCompareAndSetPlain'), + VarHandleAccessor('weakCompareAndSet'), + VarHandleAccessor('weakCompareAndSetAcquire'), + VarHandleAccessor('weakCompareAndSetRelease'), + VarHandleAccessor('getAndSet'), + VarHandleAccessor('getAndSetAcquire'), + VarHandleAccessor('getAndSetRelease'), + VarHandleAccessor('getAndAdd'), + VarHandleAccessor('getAndAddAcquire'), + VarHandleAccessor('getAndAddRelease'), + VarHandleAccessor('getAndBitwiseOr'), + VarHandleAccessor('getAndBitwiseOrRelease'), + VarHandleAccessor('getAndBitwiseOrAcquire'), + VarHandleAccessor('getAndBitwiseAnd'), + VarHandleAccessor('getAndBitwiseAndRelease'), + VarHandleAccessor('getAndBitwiseAndAcquire'), + VarHandleAccessor('getAndBitwiseXor'), + VarHandleAccessor('getAndBitwiseXorRelease'), + VarHandleAccessor('getAndBitwiseXorAcquire') +] + +# Pseudo-RNG used for arbitrary decisions +RANDOM = Random(0) + +BANNER = '// This file is generated by util-src/generate_java.py do not directly modify!' + +# List of generated test classes +GENERATED_TEST_CLASSES = [] + +def java_file_for_class(class_name): + return class_name + ".java" + +def capitalize_first(word): + return word[0].upper() + word[1:] + +def indent_code(code): + """Applies rudimentary indentation to code""" + return code + +def build_template_dictionary(test_class, var_handle_kind, accessor, var_type): + initial_value = RANDOM.choice(var_type.examples) + updated_value = RANDOM.choice(list(filter(lambda v : v != initial_value, var_type.examples))) + coordinates = ", ".join(var_handle_kind.get_coordinates()) + if accessor.get_number_of_var_type_arguments() != 0 and coordinates != "": + coordinates += ", " + dictionary = { + 'accessor_method' : accessor.method_name, + 'access_mode' : accessor.access_mode, + 'banner' : BANNER, + 'coordinates' : coordinates, + 'initial_value' : initial_value, + 'test_class' : test_class, + 'updated_value' : updated_value, + 'var_type' : var_type, + } + dictionary['imports'] = ";\n".join(list(map(lambda x: "import " + x, var_handle_kind.get_imports()))) + dictionary['lookup'] = var_handle_kind.get_lookup(dictionary) + dictionary['field_declarations'] = ";\n".join(var_handle_kind.get_field_declarations(dictionary)) + dictionary['read_value'] = var_handle_kind.get_value(dictionary) + return dictionary + +def emit_accessor_test(var_handle_kind, accessor, var_type, output_path): + test_class = var_handle_kind.get_name() + capitalize_first(accessor.method_name) + capitalize_first(var_type.name) + GENERATED_TEST_CLASSES.append(test_class) + src_file_path = output_path / java_file_for_class(test_class) + expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type) + # Compute test operation + if accessor.access_mode_form == AccessModeForm.GET: + test_template = Template(""" + ${var_type} value = (${var_type}) vh.${accessor_method}(${coordinates}); + assertEquals(${initial_value}, value);""") + elif accessor.access_mode_form == AccessModeForm.SET: + test_template = Template(""" + vh.${accessor_method}(${coordinates}${updated_value}); + assertEquals(${updated_value}, ${read_value});""") + elif accessor.access_mode_form == AccessModeForm.STRONG_COMPARE_AND_SET: + test_template = Template(""" + assertEquals(${initial_value}, ${read_value}); + // Test an update that should succeed. + boolean applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value}); + assertEquals(${updated_value}, ${read_value}); + assertTrue(applied); + // Test an update that should fail. + applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${initial_value}); + assertFalse(applied); + assertEquals(${updated_value}, ${read_value});""") + elif accessor.access_mode_form == AccessModeForm.WEAK_COMPARE_AND_SET: + test_template = Template(""" + assertEquals(${initial_value}, ${read_value}); + // Test an update that should succeed. + int attempts = 10000; + boolean applied; + do { + applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value}); + } while (applied == false && attempts-- > 0); + assertEquals(${updated_value}, ${read_value}); + assertTrue(attempts > 0); + // Test an update that should fail. + applied = (boolean) vh.${accessor_method}(${coordinates}${initial_value}, ${initial_value}); + assertFalse(applied); + assertEquals(${updated_value}, ${read_value});""") + elif accessor.access_mode_form == AccessModeForm.COMPARE_AND_EXCHANGE: + test_template = Template(""" + // This update should succeed. + ${var_type} witness_value = (${var_type}) vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value}); + assertEquals(${initial_value}, witness_value); + assertEquals(${updated_value}, ${read_value}); + // This update should fail. + witness_value = (${var_type}) vh.${accessor_method}(${coordinates}${initial_value}, ${initial_value}); + assertEquals(${updated_value}, witness_value); + assertEquals(${updated_value}, ${read_value});""") + elif accessor.access_mode_form == AccessModeForm.GET_AND_SET: + test_template = Template(""" + ${var_type} old_value = (${var_type}) vh.${accessor_method}(${coordinates}${updated_value}); + assertEquals(${initial_value}, old_value); + assertEquals(${updated_value}, ${read_value});""") + elif accessor.access_mode_form == AccessModeForm.GET_AND_UPDATE_BITWISE: + if var_type.supports_bitwise == True: + expansions['binop'] = accessor.get_java_bitwise_operator() + test_template = Template(""" + ${var_type} old_value = (${var_type}) vh.${accessor_method}(${coordinates}${updated_value}); + assertEquals(${initial_value}, old_value); + assertEquals(${initial_value} ${binop} ${updated_value}, ${read_value});""") + else: + test_template = Template(""" + vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value}); + failUnreachable();""") + elif accessor.access_mode_form == AccessModeForm.GET_AND_UPDATE_NUMERIC: + if var_type.supports_numeric == True: + expansions['binop'] = accessor.get_java_numeric_operator() + test_template = Template(""" + ${var_type} old_value = (${var_type}) vh.${accessor_method}(${coordinates}${updated_value}); + assertEquals(${initial_value}, old_value); + ${var_type} expected_value = (${var_type}) (${initial_value} ${binop} ${updated_value}); + assertEquals(expected_value, ${read_value});""") + else: + test_template = Template(""" + vh.${accessor_method}(${coordinates}${initial_value}, ${updated_value}); + failUnreachable();""") + else: + raise ValueError(accessor.access_mode_form) + + if var_handle_kind.may_throw_read_only and not accessor.is_read_only(): + # ByteBufferViews can be read-only and dynamically raise ReadOnlyBufferException. + expansions['try_statement'] = "try {" + expansions['catch_statement'] = "failUnreachable();\n} catch (ReadOnlyBufferException ex) {}" + else: + expansions['try_statement'] = "" + expansions['catch_statement'] = "" + + expansions['test_body'] = test_template.safe_substitute(expansions) + + s = Template("""${banner} + +${imports}; + +class ${test_class} extends VarHandleUnitTest { + ${field_declarations}; + static final VarHandle vh; + static { + try { + vh = ${lookup}; + } catch (Exception e) { + throw new RuntimeException("Unexpected initialization exception", e); + } + } + + @Override + public void doTest() throws Exception { + if (!vh.isAccessModeSupported(VarHandle.AccessMode.${access_mode})) { + try { + ${test_body} + failUnreachable(); + } catch (UnsupportedOperationException ex) {} + } else { + ${try_statement} + ${test_body} + ${catch_statement} + } + } + + public static void main(String[] args) { + new ${test_class}().run(); + } +} +""").safe_substitute(expansions) + with src_file_path.open("w") as src_file: + print(s, file=src_file) + +def emit_value_type_accessor_tests(output_path): + for var_handle_kind in ALL_VAR_HANDLE_KINDS: + for accessor in VAR_HANDLE_ACCESSORS: + for var_type in var_handle_kind.get_supported_types(): + emit_accessor_test(var_handle_kind, accessor, var_type, output_path) + +def emit_reference_accessor_tests(output_path): + ref_type = JavaType("Widget", [ "Widget.ONE", "Widget.TWO", "null" ]) + for var_handle_kind in ALL_VAR_HANDLE_KINDS: + if var_handle_kind.is_view(): + # Views as reference type arrays are not supported. They + # fail instantiation. This is tested in 710-varhandle-creation. + continue + for accessor in VAR_HANDLE_ACCESSORS: + emit_accessor_test(var_handle_kind, accessor, ref_type, output_path) + +def emit_boxing_value_type_accessor_test(accessor, var_type, output_path): + test_class = "Boxing" + capitalize_first(accessor.method_name) + capitalize_first(var_type.name) + GENERATED_TEST_CLASSES.append(test_class) + src_file_path = output_path / java_file_for_class(test_class) + var_handle_kind = FIELD_VAR_HANDLE + expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type) + template = Template(""" +${banner} + +${imports}; +import java.lang.invoke.WrongMethodTypeException; + +public class ${test_class} extends VarHandleUnitTest { + ${field_declarations}; + private static final VarHandle vh; + static { + try { + vh = ${lookup}; + } catch (Exception e) { + throw new RuntimeException("Unexpected initialization exception", e); + } + } + + @Override + public void doTest() throws Exception { + ${body} + } + + public static void main(String[] args) { + new ${test_class}().run(); + } +} +""") + with io.StringIO() as body_text: + compatible_types = types_that_widen_to(var_type) + for value_type in VALUE_TYPES: + print("try {", file=body_text) + return_type = accessor.get_return_type(var_type) + if return_type: + print("{0} result = ({0}) ".format(return_type), end="", file=body_text) + print("vh.{0}(this".format(accessor.method_name), end="", file=body_text) + num_args = accessor.get_number_of_var_type_arguments() + for i in range(0, num_args): + print(", {0}({1})".format(value_type.boxing_method(), value_type.examples[i]), end="", file=body_text) + print(");", file=body_text) + if value_type in compatible_types: + print(" assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode), + file=body_text) + else: + print("failUnreachable();", file=body_text) + print("} catch (WrongMethodTypeException e) {", file=body_text) + print("} catch (UnsupportedOperationException e) {", file=body_text) + print(" assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode), + file=body_text) + print("}", file=body_text) + expansions['body'] = body_text.getvalue(); + with src_file_path.open("w") as src_file: + print(template.safe_substitute(expansions), file=src_file) + +def emit_boxing_return_value_type_test(accessor, var_type, output_path): + test_class = "BoxingReturn" + capitalize_first(accessor.method_name) + capitalize_first(var_type.name) + GENERATED_TEST_CLASSES.append(test_class) + src_file_path = output_path / java_file_for_class(test_class) + var_handle_kind = FIELD_VAR_HANDLE + expansions = build_template_dictionary(test_class, var_handle_kind, accessor, var_type) + template = Template(""" +${banner} + +${imports}; +import java.lang.invoke.WrongMethodTypeException; + +public class ${test_class} extends VarHandleUnitTest { + ${field_declarations}; + private static final VarHandle vh; + static { + try { + vh = ${lookup}; + } catch (Exception e) { + throw new RuntimeException("Unexpected initialization exception", e); + } + } + + @Override + public void doTest() throws Exception { + ${body} + } + + public static void main(String[] args) { + new ${test_class}().run(); + } +} +""") + with io.StringIO() as body_text: + return_type = accessor.get_return_type(var_type) + compatible_types = { return_type } + for value_type in VALUE_TYPES: + print("try {", file=body_text) + print("{0} result = ({0}) ".format(value_type.boxed_type), end="", file=body_text) + print("vh.{0}(this".format(accessor.method_name), end="", file=body_text) + num_args = accessor.get_number_of_var_type_arguments() + for i in range(0, num_args): + print(", {0})".format(var_type.examples[i]), end="", file=body_text) + print(");", file=body_text) + if value_type in compatible_types: + print(" assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode), + file=body_text) + else: + print("failUnreachable();", file=body_text) + print("} catch (WrongMethodTypeException e) {", file=body_text) + print("} catch (UnsupportedOperationException e) {", file=body_text) + print(" assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode), + file=body_text) + print("}", file=body_text) + expansions['body'] = body_text.getvalue(); + with src_file_path.open("w") as src_file: + print(template.safe_substitute(expansions), file=src_file) + +def emit_boxing_value_type_accessor_tests(output_path): + for var_type in VALUE_TYPES: + for accessor in VAR_HANDLE_ACCESSORS: + if accessor.get_number_of_var_type_arguments() > 0: + emit_boxing_value_type_accessor_test(accessor, var_type, output_path) + else: + emit_boxing_return_value_type_test(accessor, var_type, output_path) + +def emit_main(output_path, manual_test_classes): + main_file_path = output_path / "Main.java" + all_test_classes = GENERATED_TEST_CLASSES + manual_test_classes + with main_file_path.open("w") as main_file: + print("// " + BANNER, file=main_file) + print(""" +public class Main { + public static void main(String[] args) { +""", file=main_file) + for cls in all_test_classes: + print(" " + cls + ".main(args);", file=main_file) + print(" VarHandleUnitTest.DEFAULT_COLLECTOR.printSummary();", file=main_file) + print(" System.exit(VarHandleUnitTest.DEFAULT_COLLECTOR.failuresOccurred() ? 1 : 0);", file=main_file) + print(" }\n}", file=main_file) + +def main(argv): + final_java_dir = Path(argv[1]) + if not final_java_dir.exists() or not final_java_dir.is_dir(): + print("{} is not a valid java dir".format(final_java_dir), file=sys.stderr) + sys.exit(1) + emit_value_type_accessor_tests(final_java_dir) + emit_reference_accessor_tests(final_java_dir) + emit_boxing_value_type_accessor_tests(final_java_dir) + emit_main(final_java_dir, argv[2:]) + +if __name__ == '__main__': + main(sys.argv) diff --git a/test/714-invoke-custom-lambda-metafactory/expected.txt b/test/714-invoke-custom-lambda-metafactory/expected.txt index cbe98404c5..54b6c24798 100644 --- a/test/714-invoke-custom-lambda-metafactory/expected.txt +++ b/test/714-invoke-custom-lambda-metafactory/expected.txt @@ -2,3 +2,4 @@ Exception in thread "main" java.lang.BootstrapMethodError: Exception from call s at Main.main(Main.java:25) Caused by: java.lang.NullPointerException: Bootstrap method returned null ... 1 more +exit status: 1 diff --git a/test/714-invoke-custom-lambda-metafactory/run b/test/714-invoke-custom-lambda-metafactory/run new file mode 100755 index 0000000000..7a0d0d05ab --- /dev/null +++ b/test/714-invoke-custom-lambda-metafactory/run @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Copyright 2017 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. + +# Squash the exit status and put it in expected +./default-run "$@" +echo "exit status:" $? diff --git a/test/800-smali/smali/b_22045582.smali b/test/800-smali/smali/b_22045582.smali index 3cb661a7cb..09ea784b5b 100644 --- a/test/800-smali/smali/b_22045582.smali +++ b/test/800-smali/smali/b_22045582.smali @@ -5,7 +5,7 @@ .super Ljava/lang/Object; -.method public static run()La/b/c/d/e/nonexistant; +.method public static run()La/b/c/d/e/nonexistent; .registers 4 # v1 is undefined, and the return type cannot be resolved. The Undefined should take # precedence here. diff --git a/test/988-TooDeepClassInstanceOf/expected.txt b/test/805-TooDeepClassInstanceOf/expected.txt index b0aad4deb5..b0aad4deb5 100644 --- a/test/988-TooDeepClassInstanceOf/expected.txt +++ b/test/805-TooDeepClassInstanceOf/expected.txt diff --git a/test/988-TooDeepClassInstanceOf/info.txt b/test/805-TooDeepClassInstanceOf/info.txt index 390b00d122..390b00d122 100644 --- a/test/988-TooDeepClassInstanceOf/info.txt +++ b/test/805-TooDeepClassInstanceOf/info.txt diff --git a/test/988-TooDeepClassInstanceOf/src/Main.java b/test/805-TooDeepClassInstanceOf/src/Main.java index 93a41e565b..93a41e565b 100644 --- a/test/988-TooDeepClassInstanceOf/src/Main.java +++ b/test/805-TooDeepClassInstanceOf/src/Main.java diff --git a/test/988-TooWideClassInstanceOf/expected.txt b/test/806-TooWideClassInstanceOf/expected.txt index b0aad4deb5..b0aad4deb5 100644 --- a/test/988-TooWideClassInstanceOf/expected.txt +++ b/test/806-TooWideClassInstanceOf/expected.txt diff --git a/test/988-TooWideClassInstanceOf/info.txt b/test/806-TooWideClassInstanceOf/info.txt index 30546fe076..30546fe076 100644 --- a/test/988-TooWideClassInstanceOf/info.txt +++ b/test/806-TooWideClassInstanceOf/info.txt diff --git a/test/988-TooWideClassInstanceOf/src/Main.java b/test/806-TooWideClassInstanceOf/src/Main.java index 332569c104..332569c104 100644 --- a/test/988-TooWideClassInstanceOf/src/Main.java +++ b/test/806-TooWideClassInstanceOf/src/Main.java diff --git a/test/911-get-stack-trace/expected_d8.diff b/test/911-get-stack-trace/expected_d8.diff index 3ce9bedf95..c12015a832 100644 --- a/test/911-get-stack-trace/expected_d8.diff +++ b/test/911-get-stack-trace/expected_d8.diff @@ -161,7 +161,7 @@ 363c363 < doTest ()V 122 59 --- -> doTest ()V 119 59 +> doTest ()V 120 59 376c376 < baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 --- @@ -325,15 +325,15 @@ 598c598 < doTest ()V 127 61 --- -> doTest ()V 124 61 +> doTest ()V 125 61 630c630 < doTest ()V 112 54 --- -> doTest ()V 109 54 +> doTest ()V 110 54 677c677 < doTest ()V 117 56 --- -> doTest ()V 114 56 +> doTest ()V 115 56 687c687 < baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 --- diff --git a/test/952-invoke-custom-lookup/build b/test/952-invoke-custom-lookup/build new file mode 100644 index 0000000000..f3fe95c135 --- /dev/null +++ b/test/952-invoke-custom-lookup/build @@ -0,0 +1,27 @@ +#!/bin/bash +# +# Copyright 2018 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. + +# make us exit on a failure +set -e + +# This test uses previously prepared dex and jar files. They need to +# be re-packaged to match the files that the run-test-jar script +# expects. +if [[ $@ != *"--jvm"* ]]; then + zip ${TEST_NAME}.jar classes.dex +else + unzip -d classes classes.jar +fi diff --git a/test/952-invoke-custom-lookup/classes.dex b/test/952-invoke-custom-lookup/classes.dex Binary files differnew file mode 100644 index 0000000000..670d93dedf --- /dev/null +++ b/test/952-invoke-custom-lookup/classes.dex diff --git a/test/952-invoke-custom-lookup/classes.jar b/test/952-invoke-custom-lookup/classes.jar Binary files differnew file mode 100644 index 0000000000..aa6a1f65fa --- /dev/null +++ b/test/952-invoke-custom-lookup/classes.jar diff --git a/test/952-invoke-custom-lookup/expected.txt b/test/952-invoke-custom-lookup/expected.txt new file mode 100644 index 0000000000..0da2b866d2 --- /dev/null +++ b/test/952-invoke-custom-lookup/expected.txt @@ -0,0 +1,10 @@ +NAME: 1 +CALLER: Main +CALLER CLASS: class Main +THIS CLASS: class com.android.tools.r8.maindexlist.desugar.BootstrapHolder +invokedynamic target on Main +NAME: 2 +CALLER: Main +CALLER CLASS: class Main +THIS CLASS: class com.android.tools.r8.maindexlist.desugar.BootstrapHolder +invokedynamic target on BootstrapHolder diff --git a/test/952-invoke-custom-lookup/info.txt b/test/952-invoke-custom-lookup/info.txt new file mode 100644 index 0000000000..3bfe87dfd3 --- /dev/null +++ b/test/952-invoke-custom-lookup/info.txt @@ -0,0 +1 @@ +A temporary test for the lookup class used for invoke-custom (see b/73056094). diff --git a/test/965-default-verify/src/Iface.java b/test/965-default-verify/src/Iface.java index 180fba2833..698230a666 100644 --- a/test/965-default-verify/src/Iface.java +++ b/test/965-default-verify/src/Iface.java @@ -18,6 +18,6 @@ public interface Iface { return "Hello"; } public default void verificationSoftFail() { - Statics.nonexistantFunction(); + Statics.nonexistentFunction(); } } diff --git a/test/965-default-verify/src/Statics.java b/test/965-default-verify/src/Statics.java index 2e17ba4174..23a4a01863 100644 --- a/test/965-default-verify/src/Statics.java +++ b/test/965-default-verify/src/Statics.java @@ -15,8 +15,7 @@ */ class Statics { - public static void nonexistantFunction() { + public static void nonexistentFunction() { System.out.println("I don't exist"); } } - diff --git a/test/965-default-verify/src2/Statics.java b/test/965-default-verify/src2/Statics.java index 7899ca9c5e..73c5ec6188 100644 --- a/test/965-default-verify/src2/Statics.java +++ b/test/965-default-verify/src2/Statics.java @@ -14,7 +14,7 @@ * limitations under the License. */ class Statics { - // public static void nonexistantFunction() { + // public static void nonexistentFunction() { // System.out.println("I don't exist"); // } } diff --git a/test/983-source-transform-verify/source_transform.cc b/test/983-source-transform-verify/source_transform.cc index dfefce207b..26c5668681 100644 --- a/test/983-source-transform-verify/source_transform.cc +++ b/test/983-source-transform-verify/source_transform.cc @@ -19,25 +19,19 @@ #include <cstdio> #include <cstring> #include <iostream> +#include <sstream> #include <vector> #include "android-base/stringprintf.h" #include "jni.h" #include "jvmti.h" +#include "scoped_local_ref.h" -#include "base/macros.h" -#include "bytecode_utils.h" #include "dex/code_item_accessors-inl.h" -#include "dex/art_dex_file_loader.h" +#include "dex/dex_file_loader.h" #include "dex/dex_file.h" #include "dex/dex_file_loader.h" #include "dex/dex_instruction.h" -#include "jit/jit.h" -#include "native_stack_dump.h" -#include "runtime.h" -#include "scoped_thread_state_change-inl.h" -#include "thread-current-inl.h" -#include "thread_list.h" // Test infrastructure #include "jvmti_helper.h" @@ -48,9 +42,19 @@ namespace Test983SourceTransformVerify { constexpr bool kSkipInitialLoad = true; +static void Println(JNIEnv* env, std::ostringstream msg_stream) { + std::string msg = msg_stream.str(); + ScopedLocalRef<jclass> test_klass(env, env->FindClass("art/Test983")); + jmethodID println_method = env->GetStaticMethodID(test_klass.get(), + "doPrintln", + "(Ljava/lang/String;)V"); + ScopedLocalRef<jstring> data(env, env->NewStringUTF(msg.c_str())); + env->CallStaticVoidMethod(test_klass.get(), println_method, data.get()); +} + // The hook we are using. void JNICALL CheckDexFileHook(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED, - JNIEnv* jni_env ATTRIBUTE_UNUSED, + JNIEnv* env, jclass class_being_redefined, jobject loader ATTRIBUTE_UNUSED, const char* name, @@ -60,10 +64,11 @@ void JNICALL CheckDexFileHook(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED, jint* new_class_data_len ATTRIBUTE_UNUSED, unsigned char** new_class_data ATTRIBUTE_UNUSED) { if (kSkipInitialLoad && class_being_redefined == nullptr) { - // Something got loaded concurrently. Just ignore it for now. + // Something got loaded concurrently. Just ignore it for now. To make sure the test is + // repeatable we only care about things that come from RetransformClasses. return; } - std::cout << "Dex file hook for " << name << std::endl; + Println(env, std::ostringstream() << "Dex file hook for " << name); if (IsJVM()) { return; } @@ -75,7 +80,7 @@ void JNICALL CheckDexFileHook(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED, CHECK_LE(static_cast<jint>(header_file_size), class_data_len); class_data_len = static_cast<jint>(header_file_size); - const ArtDexFileLoader dex_file_loader; + const DexFileLoader dex_file_loader; std::string error; std::unique_ptr<const DexFile> dex(dex_file_loader.Open(class_data, class_data_len, @@ -86,7 +91,8 @@ void JNICALL CheckDexFileHook(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED, /*verify_checksum*/ true, &error)); if (dex.get() == nullptr) { - std::cout << "Failed to verify dex file for " << name << " because " << error << std::endl; + Println(env, std::ostringstream() << "Failed to verify dex file for " + << name << " because " << error); return; } for (uint32_t i = 0; i < dex->NumClassDefs(); i++) { @@ -105,9 +111,10 @@ void JNICALL CheckDexFileHook(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED, int forbiden_flags = (Instruction::kVerifyError | Instruction::kVerifyRuntimeOnly); if (inst.Opcode() == Instruction::RETURN_VOID_NO_BARRIER || (inst.GetVerifyExtraFlags() & forbiden_flags) != 0) { - std::cout << "Unexpected instruction found in " << dex->PrettyMethod(it.GetMemberIndex()) - << " [Dex PC: 0x" << std::hex << pair.DexPc() << std::dec << "] : " - << inst.DumpString(dex.get()) << std::endl; + Println(env, std::ostringstream() << "Unexpected instruction found in " + << dex->PrettyMethod(it.GetMemberIndex()) + << " [Dex PC: 0x" << std::hex << pair.DexPc() + << std::dec << "] : " << inst.DumpString(dex.get())); continue; } } @@ -116,22 +123,11 @@ void JNICALL CheckDexFileHook(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED, } // Get all capabilities except those related to retransformation. -jint OnLoad(JavaVM* vm, - char* options ATTRIBUTE_UNUSED, - void* reserved ATTRIBUTE_UNUSED) { - if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) { - printf("Unable to get jvmti env!\n"); - return 1; - } - SetStandardCapabilities(jvmti_env); +extern "C" JNIEXPORT void JNICALL Java_art_Test983_setupLoadHook(JNIEnv* env, jclass) { jvmtiEventCallbacks cb; memset(&cb, 0, sizeof(cb)); cb.ClassFileLoadHook = CheckDexFileHook; - if (jvmti_env->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) { - printf("Unable to set class file load hook cb!\n"); - return 1; - } - return 0; + JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb))); } } // namespace Test983SourceTransformVerify diff --git a/test/983-source-transform-verify/src/art/Test983.java b/test/983-source-transform-verify/src/art/Test983.java index faae96aef6..7dc47ab06a 100644 --- a/test/983-source-transform-verify/src/art/Test983.java +++ b/test/983-source-transform-verify/src/art/Test983.java @@ -27,7 +27,15 @@ public class Test983 { doTest(); } + private native static void setupLoadHook(); + + /* called from JNI */ + public static void doPrintln(String str) { + System.out.println(str); + } + public static void doTest() { + setupLoadHook(); Redefinition.enableCommonRetransformation(true); Redefinition.doCommonClassRetransformation(Transform.class); Redefinition.doCommonClassRetransformation(Object.class); diff --git a/test/993-breakpoints/src/art/Breakpoint.java b/test/993-breakpoints/src/art/Breakpoint.java index 2a370ebd40..bbb89f707f 100644 --- a/test/993-breakpoints/src/art/Breakpoint.java +++ b/test/993-breakpoints/src/art/Breakpoint.java @@ -117,7 +117,7 @@ public class Breakpoint { Thread thr); public static native void stopBreakpointWatch(Thread thr); - public static final class LineNumber { + public static final class LineNumber implements Comparable<LineNumber> { public final long location; public final int line; diff --git a/test/Android.bp b/test/Android.bp index 72e8eee95a..25556adf65 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -62,7 +62,7 @@ art_cc_defaults { "libvixld-arm", "libvixld-arm64", "libart-gtest", - "libdexfile", + "libdexfiled", "libbase", "libicuuc", @@ -114,7 +114,7 @@ art_cc_defaults { shared_libs: [ "libartd", "libartd-compiler", - "libdexfile", + "libdexfiled", ], static_libs: [ "libgtest", @@ -151,7 +151,7 @@ art_cc_library { shared_libs: [ "libartd", "libartd-compiler", - "libdexfile", + "libdexfiled", "libbase", "libbacktrace", ], @@ -238,6 +238,7 @@ art_cc_defaults { "931-agent-thread/agent_thread.cc", "933-misc-events/misc_events.cc", "945-obsolete-native/obsolete_native.cc", + "983-source-transform-verify/source_transform.cc", "984-obsolete-invoke/obsolete_invoke.cc", "986-native-method-bind/native_bind.cc", "987-agent-bind/agent_bind.cc", @@ -267,12 +268,8 @@ art_cc_defaults { "1942-suspend-raw-monitor-exit/native_suspend_monitor.cc", "1943-suspend-raw-monitor-wait/native_suspend_monitor.cc", ], - shared_libs: [ - "libdexfile", - "libbase", - ], header_libs: [ - "libnativehelper_header_only", + "jni_headers", "libopenjdkjvmti_headers", ], include_dirs: ["art/test/ti-agent"], @@ -292,15 +289,21 @@ art_cc_defaults { "909-attach-agent/attach.cc", "912-classes/classes_art.cc", "936-search-onload/search_onload.cc", - "983-source-transform-verify/source_transform.cc", "1940-ddms-ext/ddm_ext.cc", + "1944-sudden-exit/sudden_exit.cc", + ], + shared_libs: [ + "libbase", ], } art_cc_test_library { name: "libtiagent", defaults: ["libtiagent-defaults"], - shared_libs: ["libart"], + shared_libs: [ + "libart", + "libdexfile", + ], } art_cc_test_library { @@ -309,7 +312,36 @@ art_cc_test_library { "art_debug_defaults", "libtiagent-defaults", ], - shared_libs: ["libartd"], + shared_libs: [ + "libartd", + "libdexfiled", + ], +} + +art_cc_test_library { + name: "libctstiagent", + defaults: ["libtiagent-base-defaults"], + whole_static_libs: [ + "libdexfile", + "libz", + "libziparchive", + ], + static_libs: [ + "libbase", + "libcutils", + "libutils", + ], + shared_libs: [ + "liblog", + ], + header_libs: [ + // This is needed to resolve the base/ header file in libdexfile. Unfortunately there are + // many problems with how we export headers that are making doing this the 'right' way + // difficult. + // TODO: move those headers to art/ rather than under runtime. + "libart_runtime_headers", + ], + export_include_dirs: ["ti-agent"], } art_cc_defaults { @@ -340,12 +372,6 @@ art_cc_test_library { shared_libs: ["libartd"], } -art_cc_test_library { - name: "libctstiagent", - defaults: ["libtiagent-base-defaults"], - export_include_dirs: ["ti-agent"], -} - cc_defaults { name: "libarttest-defaults", defaults: [ @@ -399,7 +425,6 @@ cc_defaults { "708-jit-cache-churn/jit.cc", ], shared_libs: [ - "libdexfile", "libbacktrace", "libbase", "libnativehelper", @@ -409,7 +434,10 @@ cc_defaults { art_cc_test_library { name: "libarttest", defaults: ["libarttest-defaults"], - shared_libs: ["libart"], + shared_libs: [ + "libart", + "libdexfile", + ], } art_cc_test_library { @@ -418,7 +446,10 @@ art_cc_test_library { "art_debug_defaults", "libarttest-defaults", ], - shared_libs: ["libartd"], + shared_libs: [ + "libartd", + "libdexfiled", + ], } art_cc_test_library { diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index 2df0cc6fae..464449c752 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -32,11 +32,6 @@ TEST_ART_RUN_TEST_DEPENDENCIES += \ $(HOST_OUT_EXECUTABLES)/d8-compat-dx endif -# Convert's a rule name to the form used in variables, e.g. no-relocate to NO_RELOCATE -define name-to-var -$(shell echo $(1) | tr '[:lower:]' '[:upper:]' | tr '-' '_') -endef # name-to-var - # We need dex2oat and dalvikvm on the target as well as the core images (all images as we sync # only once). TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_EXECUTABLES) $(TARGET_CORE_IMG_OUTS) @@ -124,13 +119,13 @@ define core-image-dependencies endif endif ifeq ($(2),no-image) - $(1)_prereq_rules += $$($(call name-to-var,$(1))_CORE_IMAGE_$$(image_suffix)_$(4)) + $(1)_prereq_rules += $$($(call to-upper,$(1))_CORE_IMAGE_$$(image_suffix)_$(4)) else ifeq ($(2),picimage) - $(1)_prereq_rules += $$($(call name-to-var,$(1))_CORE_IMAGE_$$(image_suffix)_$(4)) + $(1)_prereq_rules += $$($(call to-upper,$(1))_CORE_IMAGE_$$(image_suffix)_$(4)) else ifeq ($(2),multipicimage) - $(1)_prereq_rules += $$($(call name-to-var,$(1))_CORE_IMAGE_$$(image_suffix)_multi_$(4)) + $(1)_prereq_rules += $$($(call to-upper,$(1))_CORE_IMAGE_$$(image_suffix)_multi_$(4)) endif endif endif @@ -174,7 +169,6 @@ test-art-run-test : test-art-host-run-test test-art-target-run-test host_prereq_rules := target_prereq_rules := core-image-dependencies := -name-to-var := define-test-art-host-or-target-run-test-group := TARGET_TYPES := COMPILER_TYPES := diff --git a/test/etc/default-build b/test/etc/default-build index 4dc2393c54..6040f7d910 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -124,18 +124,20 @@ JACK_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-D jack.java.source.version=1.8 - declare -A SMALI_EXPERIMENTAL_ARGS SMALI_EXPERIMENTAL_ARGS["default-methods"]="--api 24" SMALI_EXPERIMENTAL_ARGS["method-handles"]="--api 26" +SMALI_EXPERIMENTAL_ARGS["var-handles"]="--api 26" SMALI_EXPERIMENTAL_ARGS["agents"]="--api 26" declare -A JAVAC_EXPERIMENTAL_ARGS JAVAC_EXPERIMENTAL_ARGS["default-methods"]="-source 1.8 -target 1.8" JAVAC_EXPERIMENTAL_ARGS["lambdas"]="-source 1.8 -target 1.8" JAVAC_EXPERIMENTAL_ARGS["method-handles"]="-source 1.8 -target 1.8" -# We need to leave javac at default 1.7 so that dx will continue to work +JAVAC_EXPERIMENTAL_ARGS["var-handles"]="-source 1.8 -target 1.8" JAVAC_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-source 1.8 -target 1.8" JAVAC_EXPERIMENTAL_ARGS["agents"]="-source 1.8 -target 1.8" declare -A DX_EXPERIMENTAL_ARGS DX_EXPERIMENTAL_ARGS["method-handles"]="--min-sdk-version=26" +DX_EXPERIMENTAL_ARGS["var-handles"]="--min-sdk-version=26" while true; do if [ "x$1" = "x--dx-option" ]; then @@ -441,7 +443,7 @@ else if [ "${HAS_SRC2}" = "true" ]; then mkdir -p classes - ${JAVAC} ${JAVAC_ARGS} -d classes `find src2 -name '*.java'` + ${JAVAC} ${JAVAC_ARGS} -classpath classes -d classes `find src2 -name '*.java'` fi if [[ "${HAS_SRC}" == "true" || "${HAS_SRC2}" == "true" || "${HAS_SRC_ART}" == "true" ]]; then diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar index 02438701b8..b8427f491b 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -570,7 +570,7 @@ if [ "$HAVE_IMAGE" = "n" ]; then if [ "${RELOCATE}" = "y" ] ; then DALVIKVM_BOOT_OPT="-Ximage:${BOOT_IMAGE}" else - DALVIKVM_BOOT_OPT="-Ximage:/system/non-existant/core.art" + DALVIKVM_BOOT_OPT="-Ximage:/system/non-existent/core.art" fi else DALVIKVM_BOOT_OPT="-Ximage:${BOOT_IMAGE}" @@ -667,7 +667,8 @@ fi if [ "$HOST" = "y" ]; then max_filename_size=$(getconf NAME_MAX $DEX_LOCATION) else - # There is no getconf on device, fallback to standard value. See NAME_MAX in kernel <linux/limits.h> + # There is no getconf on device, fallback to standard value. + # See NAME_MAX in kernel <linux/limits.h> max_filename_size=255 fi # Compute VDEX_NAME. @@ -849,7 +850,7 @@ if [ "$HOST" = "n" ]; then fi # System libraries needed by libarttestd.so - PUBLIC_LIBS=libart.so:libartd.so:libc++.so:libbacktrace.so:libdexfile.so:libbase.so:libnativehelper.so + PUBLIC_LIBS=libart.so:libartd.so:libc++.so:libbacktrace.so:libdexfile.so:libdexfiled.so:libbase.so:libnativehelper.so # Create a script with the command. The command can get longer than the longest # allowed adb command and there is no way to get the exit status from a adb shell @@ -886,11 +887,14 @@ if [ "$HOST" = "n" ]; then adb push $cmdfile $DEX_LOCATION/cmdline.sh > /dev/null 2>&1 fi + exit_status=0 if [ "$DRY_RUN" != "y" ]; then adb shell sh $DEX_LOCATION/cmdline.sh + exit_status=$? fi rm -f $cmdfile + exit $exit_status else # Host run. export ANDROID_PRINTF_LOG=brief @@ -996,10 +1000,12 @@ else trap 'kill -INT -$pid' INT $cmdline "$@" 2>&1 & pid=$! wait $pid + exit_value=$? # Add extra detail if time out is enabled. - if [ ${PIPESTATUS[0]} = 124 ] && [ "$TIME_OUT" = "timeout" ]; then + if [ $exit_value = 124 ] && [ "$TIME_OUT" = "timeout" ]; then echo -e "\e[91mTEST TIMED OUT!\e[0m" >&2 fi + exit $exit_value else # With a thread dump that uses gdb if a timeout. trap 'kill -INT -$pid' INT @@ -1022,6 +1028,7 @@ else # The test timed out. echo -e "\e[91mTEST TIMED OUT!\e[0m" >&2 fi + exit $test_exit_status fi fi fi diff --git a/test/knownfailures.json b/test/knownfailures.json index 2b28409a1f..b483b93e19 100644 --- a/test/knownfailures.json +++ b/test/knownfailures.json @@ -1,12 +1,5 @@ [ { - "tests": [ "1939-proxy-frames", "1914-get-local-instance" ], - "description": ["Test 1939 & 1914 seems to consistently fail in gcstress on 64 bit with", - "a proxy this object having no associated class!"], - "variant": "gcstress", - "bug": "http://b/67679263" - }, - { "tests": "1934-jvmti-signal-thread", "description": ["Disables 1934-jvmti-signal-thread in tracing configurations"], "variant": "trace | stream", @@ -660,8 +653,25 @@ "description": ["Test is designed to only check --compiler-filter=speed"] }, { + "test_patterns": [".*"], + "description": ["Tests are timing out for weeks now, disable to fix."], + "variant": "cdex-fast & redefine-stress" + }, + { "tests": "674-HelloWorld-Dm", "variant": "target", "description": ["Requires zip, which isn't available on device"] + }, + { + "tests": "712-varhandle-invocations", + "variant": "speed-profile & debug & gcstress & target", + "bug": "b/73275005", + "description": ["Time out"] + }, + { + "tests": ["130-hprof"], + "env_vars": {"SANITIZE_HOST": "address"}, + "bug": "b/73060923", + "description": ["ASAN issue"] } ] diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc index 9a7352e479..bfd165db10 100644 --- a/test/ti-agent/common_load.cc +++ b/test/ti-agent/common_load.cc @@ -28,7 +28,6 @@ #include "901-hello-ti-agent/basics.h" #include "909-attach-agent/attach.h" #include "936-search-onload/search_onload.h" -#include "983-source-transform-verify/source_transform.h" #include "1919-vminit-thread-start-timing/vminit.h" namespace art { @@ -83,7 +82,6 @@ static AgentLib agents[] = { { "939-hello-transformation-bcp", common_redefine::OnLoad, nullptr }, { "941-recursive-obsolete-jit", common_redefine::OnLoad, nullptr }, { "943-private-recursive-jit", common_redefine::OnLoad, nullptr }, - { "983-source-transform-verify", Test983SourceTransformVerify::OnLoad, nullptr }, { "1919-vminit-thread-start-timing", Test1919VMInitThreadStart::OnLoad, nullptr }, }; diff --git a/tools/cpp-define-generator/Android.bp b/tools/cpp-define-generator/Android.bp index 57c9c095f8..f3342d39f6 100644 --- a/tools/cpp-define-generator/Android.bp +++ b/tools/cpp-define-generator/Android.bp @@ -28,7 +28,10 @@ cc_binary { // Do not use art_cc_binary because HOST_PREFER_32_BIT is incompatib "art_debug_defaults", "art_defaults", ], - include_dirs: ["art/runtime"], + include_dirs: [ + "art/libdexfile", + "art/runtime", + ], srcs: ["main.cc"], shared_libs: [ "libbase", diff --git a/tools/external_oj_libjdwp_art_failures.txt b/tools/external_oj_libjdwp_art_failures.txt index 828c0aac0f..6c2206fe46 100644 --- a/tools/external_oj_libjdwp_art_failures.txt +++ b/tools/external_oj_libjdwp_art_failures.txt @@ -53,25 +53,6 @@ "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.CapabilitiesNewTest#testCapabilitiesNew001" ] }, { - description: "Test is flaky", - result: EXEC_FAILED, - bug: 69121056, - name: "org.apache.harmony.jpda.tests.jdwp.ObjectReference.IsCollectedTest#testIsCollected001" -}, -{ - description: "Test is flaky", - result: EXEC_FAILED, - bug: 70958370, - names: [ "org.apache.harmony.jpda.tests.jdwp.ObjectReference.EnableCollectionTest#testEnableCollection001", - "org.apache.harmony.jpda.tests.jdwp.MultiSession.EnableCollectionTest#testEnableCollection001" ] -}, -{ - description: "Test crashes", - result: EXEC_FAILED, - bug: 69591477, - name: "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.ExitTest#testExit001" -}, -{ description: "Test times out on fugu-debug", result: EXEC_FAILED, bug: 70459916, diff --git a/tools/hiddenapi/Android.bp b/tools/hiddenapi/Android.bp index f9824f1fa3..af87d31e53 100644 --- a/tools/hiddenapi/Android.bp +++ b/tools/hiddenapi/Android.bp @@ -30,7 +30,6 @@ cc_defaults { }, shared_libs: [ - "libdexfile", "libbase", ], } @@ -40,6 +39,7 @@ art_cc_binary { defaults: ["hiddenapi-defaults"], shared_libs: [ "libart", + "libdexfile", ], } @@ -51,6 +51,7 @@ art_cc_binary { ], shared_libs: [ "libartd", + "libdexfiled", ], } diff --git a/tools/prebuilt_libjdwp_art_failures.txt b/tools/prebuilt_libjdwp_art_failures.txt index a9d268de0a..2664560455 100644 --- a/tools/prebuilt_libjdwp_art_failures.txt +++ b/tools/prebuilt_libjdwp_art_failures.txt @@ -102,28 +102,9 @@ "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.CapabilitiesNewTest#testCapabilitiesNew001" ] }, { - description: "Test is flaky", - result: EXEC_FAILED, - bug: 69121056, - name: "org.apache.harmony.jpda.tests.jdwp.ObjectReference.IsCollectedTest#testIsCollected001" -}, -{ description: "Test for ddms extensions that are not implemented for prebuilt-libjdwp", result: EXEC_FAILED, bug: 69169846, name: "org.apache.harmony.jpda.tests.jdwp.DDM.DDMTest#testChunk001" }, -{ - description: "Test is flakey", - result: EXEC_FAILED, - bug: 70958370, - names: [ "org.apache.harmony.jpda.tests.jdwp.ObjectReference.EnableCollectionTest#testEnableCollection001", - "org.apache.harmony.jpda.tests.jdwp.MultiSession.EnableCollectionTest#testEnableCollection001" ] -}, -{ - description: "Test crashes", - result: EXEC_FAILED, - bug: 69591477, - name: "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.ExitTest#testExit001" -} ] diff --git a/tools/public.libraries.buildbot.txt b/tools/public.libraries.buildbot.txt index 734fd1e50b..de636a813a 100644 --- a/tools/public.libraries.buildbot.txt +++ b/tools/public.libraries.buildbot.txt @@ -1,6 +1,7 @@ libart.so libartd.so libdexfile.so +libdexfiled.so libbacktrace.so libc.so libc++.so diff --git a/tools/titrace/Android.bp b/tools/titrace/Android.bp index 097622e756..21f266c087 100644 --- a/tools/titrace/Android.bp +++ b/tools/titrace/Android.bp @@ -40,9 +40,8 @@ cc_defaults { }, header_libs: [ "libopenjdkjvmti_headers", - "libart_runtime_headers", // for dex_instruction_list.h only - // "libbase_headers", ], + include_dirs: ["art/libdexfile"], // for dex_instruction_list.h only multilib: { lib32: { suffix: "32", |