Merge "Refactor ClassLinker::FindPrimitiveClass()."
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index a9acf90..48b50ea 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2319,9 +2319,10 @@
if (offset >= kReferenceLoadMinFarOffset) {
locations->AddTemp(FixedTempLocation());
}
- } else {
+ } else if (!instruction->GetArray()->IsIntermediateAddress()) {
// We need a non-scratch temporary for the array data pointer in
- // CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier().
+ // CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier() for the case with no
+ // intermediate address.
locations->AddTemp(Location::RequiresRegister());
}
}
@@ -2351,11 +2352,12 @@
MacroAssembler* masm = GetVIXLAssembler();
UseScratchRegisterScope temps(masm);
- // The read barrier instrumentation of object ArrayGet instructions
+ // The non-Baker read barrier instrumentation of object ArrayGet instructions
// does not support the HIntermediateAddress instruction.
DCHECK(!((type == DataType::Type::kReference) &&
instruction->GetArray()->IsIntermediateAddress() &&
- kEmitCompilerReadBarrier));
+ kEmitCompilerReadBarrier &&
+ !kUseBakerReadBarrier));
if (type == DataType::Type::kReference && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
// Object ArrayGet with Baker's read barrier case.
@@ -2363,6 +2365,7 @@
// CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier call.
DCHECK(!instruction->CanDoImplicitNullCheckOn(instruction->InputAt(0)));
if (index.IsConstant()) {
+ DCHECK(!instruction->GetArray()->IsIntermediateAddress());
// Array load with a constant index can be treated as a field load.
offset += Int64FromLocation(index) << DataType::SizeShift(type);
Location maybe_temp =
@@ -2375,9 +2378,8 @@
/* needs_null_check */ false,
/* use_load_acquire */ false);
} else {
- Register temp = WRegisterFrom(locations->GetTemp(0));
codegen_->GenerateArrayLoadWithBakerReadBarrier(
- out, obj.W(), offset, index, temp, /* needs_null_check */ false);
+ instruction, out, obj.W(), offset, index, /* needs_null_check */ false);
}
} else {
// General case.
@@ -2426,8 +2428,8 @@
// input instruction has done it already. See the comment in
// `TryExtractArrayAccessAddress()`.
if (kIsDebugBuild) {
- HIntermediateAddress* tmp = instruction->GetArray()->AsIntermediateAddress();
- DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), offset);
+ HIntermediateAddress* interm_addr = instruction->GetArray()->AsIntermediateAddress();
+ DCHECK_EQ(interm_addr->GetOffset()->AsIntConstant()->GetValueAsUint64(), offset);
}
temp = obj;
} else {
@@ -2539,8 +2541,8 @@
// input instruction has done it already. See the comment in
// `TryExtractArrayAccessAddress()`.
if (kIsDebugBuild) {
- HIntermediateAddress* tmp = instruction->GetArray()->AsIntermediateAddress();
- DCHECK(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64() == offset);
+ HIntermediateAddress* interm_addr = instruction->GetArray()->AsIntermediateAddress();
+ DCHECK(interm_addr->GetOffset()->AsIntConstant()->GetValueAsUint64() == offset);
}
temp = array;
} else {
@@ -5957,11 +5959,11 @@
instruction, ref, obj, src, needs_null_check, use_load_acquire);
}
-void CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier(Location ref,
+void CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier(HArrayGet* instruction,
+ Location ref,
Register obj,
uint32_t data_offset,
Location index,
- Register temp,
bool needs_null_check) {
DCHECK(kEmitCompilerReadBarrier);
DCHECK(kUseBakerReadBarrier);
@@ -6000,9 +6002,24 @@
DCHECK(temps.IsAvailable(ip0));
DCHECK(temps.IsAvailable(ip1));
temps.Exclude(ip0, ip1);
+
+ Register temp;
+ if (instruction->GetArray()->IsIntermediateAddress()) {
+ // We do not need to compute the intermediate address from the array: the
+ // input instruction has done it already. See the comment in
+ // `TryExtractArrayAccessAddress()`.
+ if (kIsDebugBuild) {
+ HIntermediateAddress* interm_addr = instruction->GetArray()->AsIntermediateAddress();
+ DCHECK_EQ(interm_addr->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
+ }
+ temp = obj;
+ } else {
+ temp = WRegisterFrom(instruction->GetLocations()->GetTemp(0));
+ __ Add(temp.X(), obj.X(), Operand(data_offset));
+ }
+
uint32_t custom_data = EncodeBakerReadBarrierArrayData(temp.GetCode());
- __ Add(temp.X(), obj.X(), Operand(data_offset));
{
ExactAssemblyScope guard(GetVIXLAssembler(),
(kPoisonHeapReferences ? 4u : 3u) * vixl::aarch64::kInstructionSize);
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 1ba58b1..ada5742 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -694,11 +694,11 @@
bool use_load_acquire);
// Fast path implementation of ReadBarrier::Barrier for a heap
// reference array load when Baker's read barriers are used.
- void GenerateArrayLoadWithBakerReadBarrier(Location ref,
+ void GenerateArrayLoadWithBakerReadBarrier(HArrayGet* instruction,
+ Location ref,
vixl::aarch64::Register obj,
uint32_t data_offset,
Location index,
- vixl::aarch64::Register temp,
bool needs_null_check);
// Emit code checking the status of the Marking Register, and
diff --git a/compiler/optimizing/instruction_simplifier_arm.cc b/compiler/optimizing/instruction_simplifier_arm.cc
index 24fbb6c..f968c19 100644
--- a/compiler/optimizing/instruction_simplifier_arm.cc
+++ b/compiler/optimizing/instruction_simplifier_arm.cc
@@ -202,6 +202,11 @@
return;
}
+ // TODO: Support intermediate address for object arrays on arm.
+ if (type == DataType::Type::kReference) {
+ return;
+ }
+
if (type == DataType::Type::kInt64
|| type == DataType::Type::kFloat32
|| type == DataType::Type::kFloat64) {
diff --git a/compiler/optimizing/instruction_simplifier_shared.cc b/compiler/optimizing/instruction_simplifier_shared.cc
index ccdcb35..0f30f66 100644
--- a/compiler/optimizing/instruction_simplifier_shared.cc
+++ b/compiler/optimizing/instruction_simplifier_shared.cc
@@ -245,11 +245,11 @@
return false;
}
if (kEmitCompilerReadBarrier &&
+ !kUseBakerReadBarrier &&
access->IsArrayGet() &&
access->GetType() == DataType::Type::kReference) {
- // For object arrays, the read barrier instrumentation requires
+ // For object arrays, the non-Baker read barrier instrumentation requires
// the original array pointer.
- // TODO: This can be relaxed for Baker CC.
return false;
}
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 7684dc7..6d04b0e 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -2916,6 +2916,40 @@
void IntrinsicCodeGeneratorARM64::VisitReachabilityFence(HInvoke* invoke ATTRIBUTE_UNUSED) { }
+void IntrinsicLocationsBuilderARM64::VisitCRC32Update(HInvoke* invoke) {
+ if (!codegen_->GetInstructionSetFeatures().HasCRC()) {
+ return;
+ }
+
+ LocationSummary* locations = new (allocator_) LocationSummary(invoke,
+ LocationSummary::kNoCall,
+ kIntrinsified);
+
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister());
+}
+
+// Lower the invoke of CRC32.update(int crc, int b).
+void IntrinsicCodeGeneratorARM64::VisitCRC32Update(HInvoke* invoke) {
+ DCHECK(codegen_->GetInstructionSetFeatures().HasCRC());
+
+ MacroAssembler* masm = GetVIXLAssembler();
+
+ Register crc = InputRegisterAt(invoke, 0);
+ Register val = InputRegisterAt(invoke, 1);
+ Register out = OutputRegister(invoke);
+
+ // The general algorithm of the CRC32 calculation is:
+ // crc = ~crc
+ // result = crc32_for_byte(crc, b)
+ // crc = ~result
+ // It is directly lowered to three instructions.
+ __ Mvn(out, crc);
+ __ Crc32b(out, out, val);
+ __ Mvn(out, out);
+}
+
UNIMPLEMENTED_INTRINSIC(ARM64, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(ARM64, StringStringIndexOf);
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc
index 38e4c89..0c463a2 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -3059,6 +3059,7 @@
UNIMPLEMENTED_INTRINSIC(ARMVIXL, UnsafeCASLong) // High register pressure.
UNIMPLEMENTED_INTRINSIC(ARMVIXL, SystemArrayCopyChar)
UNIMPLEMENTED_INTRINSIC(ARMVIXL, ReferenceGetReferent)
+UNIMPLEMENTED_INTRINSIC(ARMVIXL, CRC32Update)
UNIMPLEMENTED_INTRINSIC(ARMVIXL, StringStringIndexOf);
UNIMPLEMENTED_INTRINSIC(ARMVIXL, StringStringIndexOfAfter);
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 6f7f5e4..21fb7d7 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -2696,6 +2696,8 @@
UNIMPLEMENTED_INTRINSIC(MIPS, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(MIPS, SystemArrayCopy)
+UNIMPLEMENTED_INTRINSIC(MIPS, CRC32Update)
+
UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOf);
UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOfAfter);
UNIMPLEMENTED_INTRINSIC(MIPS, StringBufferAppend);
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index 2eb2529..4b86f5d 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -2346,6 +2346,7 @@
UNIMPLEMENTED_INTRINSIC(MIPS64, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(MIPS64, SystemArrayCopy)
+UNIMPLEMENTED_INTRINSIC(MIPS64, CRC32Update)
UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOf);
UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOfAfter);
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index 3504d7a..6dd4681 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -2967,6 +2967,7 @@
UNIMPLEMENTED_INTRINSIC(X86, LongHighestOneBit)
UNIMPLEMENTED_INTRINSIC(X86, IntegerLowestOneBit)
UNIMPLEMENTED_INTRINSIC(X86, LongLowestOneBit)
+UNIMPLEMENTED_INTRINSIC(X86, CRC32Update)
UNIMPLEMENTED_INTRINSIC(X86, StringStringIndexOf);
UNIMPLEMENTED_INTRINSIC(X86, StringStringIndexOfAfter);
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 96f6eaa..7db26dc 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -2732,6 +2732,7 @@
UNIMPLEMENTED_INTRINSIC(X86_64, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(X86_64, FloatIsInfinite)
UNIMPLEMENTED_INTRINSIC(X86_64, DoubleIsInfinite)
+UNIMPLEMENTED_INTRINSIC(X86_64, CRC32Update)
UNIMPLEMENTED_INTRINSIC(X86_64, StringStringIndexOf);
UNIMPLEMENTED_INTRINSIC(X86_64, StringStringIndexOfAfter);
diff --git a/compiler/utils/assembler_thumb_test.cc b/compiler/utils/assembler_thumb_test.cc
index 053e202..3d26296 100644
--- a/compiler/utils/assembler_thumb_test.cc
+++ b/compiler/utils/assembler_thumb_test.cc
@@ -125,7 +125,7 @@
// Assemble the .S
snprintf(cmd, sizeof(cmd), "%sas %s -o %s.o", toolsdir.c_str(), filename, filename);
int cmd_result = system(cmd);
- ASSERT_EQ(cmd_result, 0) << strerror(errno);
+ ASSERT_EQ(cmd_result, 0) << cmd << strerror(errno);
// Disassemble.
snprintf(cmd, sizeof(cmd), "%sobjdump -D -M force-thumb --section=.text %s.o | grep '^ *[0-9a-f][0-9a-f]*:'",
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index d22b301..baeebd9 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -23,6 +23,7 @@
#include <unistd.h>
#include <android-base/logging.h>
+#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include "common_runtime_test.h"
@@ -90,6 +91,10 @@
args.push_back("--runtime-arg");
args.push_back("-Xnorelocate");
+ // Unless otherwise stated, use a small amount of threads, so that potential aborts are
+ // shorter. This can be overridden with extra_args.
+ args.push_back("-j4");
+
args.insert(args.end(), extra_args.begin(), extra_args.end());
int status = Dex2Oat(args, error_msg);
@@ -99,33 +104,33 @@
return status;
}
- void GenerateOdexForTest(
+ ::testing::AssertionResult GenerateOdexForTest(
const std::string& dex_location,
const std::string& odex_location,
CompilerFilter::Filter filter,
const std::vector<std::string>& extra_args = {},
bool expect_success = true,
- bool use_fd = false) {
- GenerateOdexForTest(dex_location,
- odex_location,
- filter,
- extra_args,
- expect_success,
- use_fd,
- [](const OatFile&) {});
+ bool use_fd = false) WARN_UNUSED {
+ return GenerateOdexForTest(dex_location,
+ odex_location,
+ filter,
+ extra_args,
+ expect_success,
+ use_fd,
+ [](const OatFile&) {});
}
bool test_accepts_odex_file_on_failure = false;
template <typename T>
- void GenerateOdexForTest(
+ ::testing::AssertionResult GenerateOdexForTest(
const std::string& dex_location,
const std::string& odex_location,
CompilerFilter::Filter filter,
const std::vector<std::string>& extra_args,
bool expect_success,
bool use_fd,
- T check_oat) {
+ T check_oat) WARN_UNUSED {
std::string error_msg;
int status = GenerateOdexForTestWithStatus({dex_location},
odex_location,
@@ -135,7 +140,10 @@
use_fd);
bool success = (WIFEXITED(status) && WEXITSTATUS(status) == 0);
if (expect_success) {
- ASSERT_TRUE(success) << error_msg << std::endl << output_;
+ if (!success) {
+ return ::testing::AssertionFailure()
+ << "Failed to compile odex: " << error_msg << std::endl << output_;
+ }
// Verify the odex file was generated as expected.
std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
@@ -146,12 +154,16 @@
dex_location.c_str(),
/*reservation=*/ nullptr,
&error_msg));
- ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
+ if (odex_file == nullptr) {
+ return ::testing::AssertionFailure() << "Could not open odex file: " << error_msg;
+ }
CheckFilter(filter, odex_file->GetCompilerFilter());
check_oat(*(odex_file.get()));
} else {
- ASSERT_FALSE(success) << output_;
+ if (success) {
+ return ::testing::AssertionFailure() << "Succeeded to compile odex: " << output_;
+ }
error_msg_ = error_msg;
@@ -165,9 +177,12 @@
dex_location.c_str(),
/*reservation=*/ nullptr,
&error_msg));
- ASSERT_TRUE(odex_file.get() == nullptr);
+ if (odex_file != nullptr) {
+ return ::testing::AssertionFailure() << "Could open odex file: " << error_msg;
+ }
}
}
+ return ::testing::AssertionSuccess();
}
// Check the input compiler filter against the generated oat file's filter. May be overridden
@@ -265,7 +280,7 @@
std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
copy.push_back("--swap-file=" + swap_location);
}
- GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy);
+ ASSERT_TRUE(GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy));
CheckValidity();
ASSERT_TRUE(success_);
@@ -490,7 +505,7 @@
std::vector<std::string> new_args(extra_args);
new_args.push_back("--app-image-file=" + app_image_file);
- GenerateOdexForTest(dex_location, odex_location, filter, new_args);
+ ASSERT_TRUE(GenerateOdexForTest(dex_location, odex_location, filter, new_args));
CheckValidity();
ASSERT_TRUE(success_);
@@ -681,12 +696,12 @@
copy.push_back("--app-image-file=" + app_image_file_name);
}
}
- GenerateOdexForTest(dex_location,
- odex_location,
- CompilerFilter::kSpeedProfile,
- copy,
- expect_success,
- use_fd);
+ ASSERT_TRUE(GenerateOdexForTest(dex_location,
+ odex_location,
+ CompilerFilter::kSpeedProfile,
+ copy,
+ expect_success,
+ use_fd));
if (app_image_file != nullptr) {
ASSERT_EQ(app_image_file->FlushCloseOrErase(), 0) << "Could not flush and close art file";
}
@@ -877,24 +892,24 @@
{
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 },
- /*expect_success=*/ true,
- /*use_fd=*/ true);
+ ASSERT_TRUE(GenerateOdexForTest(dex_location,
+ odex_location,
+ CompilerFilter::kQuicken,
+ { input_vdex, output_vdex },
+ /* 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_file1->Fd());
- GenerateOdexForTest(dex_location,
- odex_location,
- CompilerFilter::kVerify,
- { input_vdex, output_vdex, kDisableCompactDex },
- /*expect_success=*/ true,
- /*use_fd=*/ true);
+ ASSERT_TRUE(GenerateOdexForTest(dex_location,
+ odex_location,
+ CompilerFilter::kVerify,
+ { input_vdex, output_vdex, kDisableCompactDex },
+ /* expect_success= */ true,
+ /* use_fd= */ true));
}
ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
CheckResult(dex_location, odex_location);
@@ -918,12 +933,12 @@
{
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);
+ ASSERT_TRUE(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);
}
@@ -931,12 +946,12 @@
{
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_TRUE(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";
@@ -992,11 +1007,11 @@
std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
copy.push_back("--swap-file=" + swap_location);
copy.push_back("-j512"); // Excessive idle threads just slow down dex2oat.
- GenerateOdexForTest(dex_location,
- odex_location,
- CompilerFilter::kSpeed,
- copy,
- expect_success);
+ ASSERT_TRUE(GenerateOdexForTest(dex_location,
+ odex_location,
+ CompilerFilter::kSpeed,
+ copy,
+ expect_success));
}
std::string GetTestDexFileName() {
@@ -1072,13 +1087,13 @@
ASSERT_STREQ(expected_classpath_key, classpath);
};
- GenerateOdexForTest(dex_location,
- odex_location,
- CompilerFilter::kQuicken,
- extra_args,
- expected_success,
- /*use_fd*/ false,
- check_oat);
+ ASSERT_TRUE(GenerateOdexForTest(dex_location,
+ odex_location,
+ CompilerFilter::kQuicken,
+ extra_args,
+ expected_success,
+ /*use_fd*/ false,
+ check_oat));
}
std::string GetUsedDexLocation() {
@@ -1135,11 +1150,11 @@
Copy(GetDexSrc1(), stripped_classpath);
- GenerateOdexForTest(stripped_classpath,
- odex_for_classpath,
- CompilerFilter::kQuicken,
- {},
- true);
+ ASSERT_TRUE(GenerateOdexForTest(stripped_classpath,
+ odex_for_classpath,
+ CompilerFilter::kQuicken,
+ {},
+ true));
// Strip the dex file
Copy(GetStrippedDexSrc1(), stripped_classpath);
@@ -1216,7 +1231,7 @@
CompilerFilter::Filter::kQuicken,
&error_msg,
{"--force-determinism", "--avoid-storing-invocation"});
- EXPECT_EQ(res, 0);
+ ASSERT_EQ(res, 0);
Copy(base_oat_name, unload_oat_name);
Copy(base_vdex_name, unload_vdex_name);
std::unique_ptr<File> unload_oat(OS::OpenFileForReading(unload_oat_name.c_str()));
@@ -1233,7 +1248,7 @@
CompilerFilter::Filter::kQuicken,
&error_msg,
{"--force-determinism", "--avoid-storing-invocation", "--app-image-file=" + app_image_name});
- EXPECT_EQ(res2, 0);
+ ASSERT_EQ(res2, 0);
Copy(base_oat_name, no_unload_oat_name);
Copy(base_vdex_name, no_unload_vdex_name);
std::unique_ptr<File> no_unload_oat(OS::OpenFileForReading(no_unload_oat_name.c_str()));
@@ -1535,26 +1550,26 @@
std::string out_dir = GetScratchDir();
const std::string base_oat_name = out_dir + "/base.oat";
size_t no_dedupe_size = 0;
- GenerateOdexForTest(dex->GetLocation(),
- base_oat_name,
- CompilerFilter::Filter::kSpeed,
- { "--deduplicate-code=false" },
- true, // expect_success
- false, // use_fd
- [&no_dedupe_size](const OatFile& o) {
- no_dedupe_size = o.Size();
- });
+ ASSERT_TRUE(GenerateOdexForTest(dex->GetLocation(),
+ base_oat_name,
+ CompilerFilter::Filter::kSpeed,
+ { "--deduplicate-code=false" },
+ true, // expect_success
+ false, // use_fd
+ [&no_dedupe_size](const OatFile& o) {
+ no_dedupe_size = o.Size();
+ }));
size_t dedupe_size = 0;
- GenerateOdexForTest(dex->GetLocation(),
- base_oat_name,
- CompilerFilter::Filter::kSpeed,
- { "--deduplicate-code=true" },
- true, // expect_success
- false, // use_fd
- [&dedupe_size](const OatFile& o) {
- dedupe_size = o.Size();
- });
+ ASSERT_TRUE(GenerateOdexForTest(dex->GetLocation(),
+ base_oat_name,
+ CompilerFilter::Filter::kSpeed,
+ { "--deduplicate-code=true" },
+ true, // expect_success
+ false, // use_fd
+ [&dedupe_size](const OatFile& o) {
+ dedupe_size = o.Size();
+ }));
EXPECT_LT(dedupe_size, no_dedupe_size);
}
@@ -1563,15 +1578,15 @@
std::unique_ptr<const DexFile> dex(OpenTestDexFile("MainUncompressed"));
std::string out_dir = GetScratchDir();
const std::string base_oat_name = out_dir + "/base.oat";
- GenerateOdexForTest(dex->GetLocation(),
- base_oat_name,
- CompilerFilter::Filter::kQuicken,
- { },
- true, // expect_success
- false, // use_fd
- [](const OatFile& o) {
- CHECK(!o.ContainsDexCode());
- });
+ ASSERT_TRUE(GenerateOdexForTest(dex->GetLocation(),
+ base_oat_name,
+ CompilerFilter::Filter::kQuicken,
+ { },
+ true, // expect_success
+ false, // use_fd
+ [](const OatFile& o) {
+ CHECK(!o.ContainsDexCode());
+ }));
}
TEST_F(Dex2oatTest, EmptyUncompressedDexTest) {
@@ -1667,15 +1682,15 @@
std::string out_dir = GetScratchDir();
const std::string oat_filename = out_dir + "/base.oat";
// The dex won't pass the method verifier, only use the verify filter.
- GenerateOdexForTest(temp_dex.GetFilename(),
- oat_filename,
- CompilerFilter::Filter::kVerify,
- { },
- true, // expect_success
- false, // use_fd
- [](const OatFile& o) {
- CHECK(o.ContainsDexCode());
- });
+ ASSERT_TRUE(GenerateOdexForTest(temp_dex.GetFilename(),
+ oat_filename,
+ CompilerFilter::Filter::kVerify,
+ { },
+ true, // expect_success
+ false, // use_fd
+ [](const OatFile& o) {
+ CHECK(o.ContainsDexCode());
+ }));
// Open our generated oat file.
std::string error_msg;
std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
@@ -1718,11 +1733,11 @@
}
const std::string& dex_location = apk_file.GetFilename();
const std::string odex_location = GetOdexDir() + "/output.odex";
- GenerateOdexForTest(dex_location,
- odex_location,
- CompilerFilter::kQuicken,
- { "--compact-dex-level=fast" },
- true);
+ ASSERT_TRUE(GenerateOdexForTest(dex_location,
+ odex_location,
+ CompilerFilter::kQuicken,
+ { "--compact-dex-level=fast" },
+ true));
}
TEST_F(Dex2oatTest, StderrLoggerOutput) {
@@ -1732,11 +1747,11 @@
// Test file doesn't matter.
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location,
- odex_location,
- CompilerFilter::kQuicken,
- { "--runtime-arg", "-Xuse-stderr-logger" },
- true);
+ ASSERT_TRUE(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"));
@@ -1749,11 +1764,11 @@
// Test file doesn't matter.
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location,
- odex_location,
- CompilerFilter::kVerify,
- { "--compilation-reason=install" },
- true);
+ ASSERT_TRUE(GenerateOdexForTest(dex_location,
+ odex_location,
+ CompilerFilter::kVerify,
+ { "--compilation-reason=install" },
+ true));
std::string error_msg;
std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
odex_location.c_str(),
@@ -1774,11 +1789,11 @@
// Test file doesn't matter.
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location,
- odex_location,
- CompilerFilter::kVerify,
- {},
- true);
+ ASSERT_TRUE(GenerateOdexForTest(dex_location,
+ odex_location,
+ CompilerFilter::kVerify,
+ {},
+ true));
std::string error_msg;
std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
odex_location.c_str(),
@@ -1799,14 +1814,13 @@
const std::string dex_location = dex->GetLocation();
const std::string odex_location = out_dir + "/base.oat";
const std::string vdex_location = out_dir + "/base.vdex";
- GenerateOdexForTest(dex_location,
- odex_location,
- CompilerFilter::Filter::kVerify,
- { "--copy-dex-files=false" },
- true, // expect_success
- false, // use_fd
- [](const OatFile&) {
- });
+ ASSERT_TRUE(GenerateOdexForTest(dex_location,
+ odex_location,
+ CompilerFilter::Filter::kVerify,
+ { "--copy-dex-files=false" },
+ true, // expect_success
+ false, // use_fd
+ [](const OatFile&) {}));
{
// Check the vdex doesn't have dex.
std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location.c_str(),
@@ -1856,19 +1870,21 @@
}
auto generate_and_check = [&](CompilerFilter::Filter filter) {
- GenerateOdexForTest(dex_location,
- odex_location,
- filter,
- { "--dump-timings",
- "--dm-file=" + dm_file.GetFilename(),
- // Pass -Xuse-stderr-logger have dex2oat output in output_ on target.
- "--runtime-arg",
- "-Xuse-stderr-logger" },
- true, // expect_success
- false, // use_fd
- [](const OatFile& o) {
- CHECK(o.ContainsDexCode());
- });
+ output_.clear();
+ ASSERT_TRUE(GenerateOdexForTest(dex_location,
+ odex_location,
+ filter,
+ { "--dump-timings",
+ "--dm-file=" + dm_file.GetFilename(),
+ // Pass -Xuse-stderr-logger have dex2oat output in output_ on
+ // target.
+ "--runtime-arg",
+ "-Xuse-stderr-logger" },
+ true, // expect_success
+ false, // use_fd
+ [](const OatFile& o) {
+ CHECK(o.ContainsDexCode());
+ }));
// Check the output for "Fast verify", this is printed from --dump-timings.
std::istringstream iss(output_);
std::string line;
@@ -1916,14 +1932,14 @@
{
std::string input_vdex = "--input-vdex-fd=-1";
std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_output->Fd());
- GenerateOdexForTest(dex_location,
- odex_location,
- CompilerFilter::kQuicken,
- // Disable cdex since we want to compare against the original dex file
- // after unquickening.
- { input_vdex, output_vdex, kDisableCompactDex },
- /*expect_success=*/ true,
- /*use_fd=*/ true);
+ ASSERT_TRUE(GenerateOdexForTest(dex_location,
+ odex_location,
+ CompilerFilter::kQuicken,
+ // Disable cdex since we want to compare against the original
+ // dex file after unquickening.
+ { input_vdex, output_vdex, kDisableCompactDex },
+ /* expect_success= */ true,
+ /* use_fd= */ true));
}
// Unquicken by running the verify compiler filter on the vdex file and verify it matches.
std::string odex_location2 = GetOdexDir() + "/unquickened.odex";
@@ -1932,13 +1948,14 @@
{
std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_output->Fd());
std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_unquickened->Fd());
- GenerateOdexForTest(dex_location,
- odex_location2,
- CompilerFilter::kVerify,
- // Disable cdex to avoid needing to write out the shared section.
- { input_vdex, output_vdex, kDisableCompactDex },
- /*expect_success=*/ true,
- /*use_fd=*/ true);
+ ASSERT_TRUE(GenerateOdexForTest(dex_location,
+ odex_location2,
+ CompilerFilter::kVerify,
+ // Disable cdex to avoid needing to write out the shared
+ // section.
+ { input_vdex, output_vdex, kDisableCompactDex },
+ /* expect_success= */ true,
+ /* use_fd= */ true));
}
ASSERT_EQ(vdex_unquickened->Flush(), 0) << "Could not flush and close vdex file";
ASSERT_TRUE(success_);
@@ -2046,13 +2063,13 @@
ScratchFile app_image_file;
const std::string out_dir = GetScratchDir();
const std::string odex_location = out_dir + "/base.odex";
- GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
- odex_location,
- CompilerFilter::Filter::kSpeedProfile,
- { "--app-image-fd=" + std::to_string(app_image_file.GetFd()) },
- true, // expect_success
- false, // use_fd
- [](const OatFile&) {});
+ ASSERT_TRUE(GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
+ odex_location,
+ CompilerFilter::Filter::kSpeedProfile,
+ { "--app-image-fd=" + std::to_string(app_image_file.GetFd()) },
+ true, // expect_success
+ false, // use_fd
+ [](const OatFile&) {}));
// Open our generated oat file.
std::string error_msg;
std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
@@ -2105,15 +2122,15 @@
const std::string out_dir = GetScratchDir();
const std::string odex_location = out_dir + "/base.odex";
const std::string app_image_location = out_dir + "/base.art";
- GenerateOdexForTest(GetTestDexFileName("StringLiterals"),
- odex_location,
- CompilerFilter::Filter::kSpeedProfile,
- { "--app-image-file=" + app_image_location,
- "--resolve-startup-const-strings=true",
- "--profile-file=" + profile_file.GetFilename()},
- /*expect_success=*/ true,
- /*use_fd=*/ false,
- [](const OatFile&) {});
+ ASSERT_TRUE(GenerateOdexForTest(GetTestDexFileName("StringLiterals"),
+ odex_location,
+ CompilerFilter::Filter::kSpeedProfile,
+ { "--app-image-file=" + app_image_location,
+ "--resolve-startup-const-strings=true",
+ "--profile-file=" + profile_file.GetFilename()},
+ /* expect_success= */ true,
+ /* use_fd= */ false,
+ [](const OatFile&) {}));
// Open our generated oat file.
std::string error_msg;
std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
@@ -2220,27 +2237,27 @@
}
expected_stored_context += + "]";
// The class path should not be valid and should fail being stored.
- GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
- odex_location,
- CompilerFilter::Filter::kQuicken,
- { "--class-loader-context=" + stored_context },
- true, // expect_success
- false, // use_fd
- [&](const OatFile& oat_file) {
+ EXPECT_TRUE(GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
+ odex_location,
+ CompilerFilter::Filter::kQuicken,
+ { "--class-loader-context=" + stored_context },
+ true, // expect_success
+ false, // use_fd
+ [&](const OatFile& oat_file) {
EXPECT_NE(oat_file.GetClassLoaderContext(), stored_context) << output_;
EXPECT_NE(oat_file.GetClassLoaderContext(), valid_context) << output_;
- });
+ }));
// The stored context should match what we expect even though it's invalid.
- GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
- odex_location,
- CompilerFilter::Filter::kQuicken,
- { "--class-loader-context=" + valid_context,
- "--stored-class-loader-context=" + stored_context },
- true, // expect_success
- false, // use_fd
- [&](const OatFile& oat_file) {
+ EXPECT_TRUE(GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
+ odex_location,
+ CompilerFilter::Filter::kQuicken,
+ { "--class-loader-context=" + valid_context,
+ "--stored-class-loader-context=" + stored_context },
+ true, // expect_success
+ false, // use_fd
+ [&](const OatFile& oat_file) {
EXPECT_EQ(oat_file.GetClassLoaderContext(), expected_stored_context) << output_;
- });
+ }));
}
} // namespace art
diff --git a/disassembler/Android.bp b/disassembler/Android.bp
index 241b191..a7c1802 100644
--- a/disassembler/Android.bp
+++ b/disassembler/Android.bp
@@ -20,11 +20,39 @@
host_supported: true,
srcs: [
"disassembler.cc",
- "disassembler_arm.cc",
- "disassembler_arm64.cc",
"disassembler_mips.cc",
"disassembler_x86.cc",
],
+ codegen: {
+ arm: {
+ srcs: ["disassembler_arm.cc"]
+ },
+ arm64: {
+ srcs: ["disassembler_arm64.cc"]
+ },
+ // TODO: We should also conditionally include the MIPS32/MIPS64 and the
+ // x86/x86-64 disassembler definitions (b/119090273). However, using the
+ // following syntax here:
+ //
+ // mips: {
+ // srcs: ["disassembler_mips.cc"]
+ // },
+ // mips64: {
+ // srcs: ["disassembler_mips.cc"]
+ // },
+ // x86: {
+ // srcs: ["disassembler_x86.cc"]
+ // },
+ // x86_64: {
+ // srcs: ["disassembler_x86.cc"]
+ // },
+ //
+ // does not work, as it generates a file rejected by ninja with this
+ // error message (e.g. on host, where we include all the back ends by
+ // default):
+ //
+ // FAILED: ninja: out/soong/build.ninja:320768: multiple rules generate out/soong/.intermediates/art/disassembler/libart-disassembler/linux_glibc_x86_64_static/obj/art/disassembler/disassembler_mips.o [-w dupbuild=err]
+ },
include_dirs: ["art/runtime"],
shared_libs: [
diff --git a/disassembler/disassembler.cc b/disassembler/disassembler.cc
index 262e815..aee690e 100644
--- a/disassembler/disassembler.cc
+++ b/disassembler/disassembler.cc
@@ -21,10 +21,21 @@
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "disassembler_arm.h"
-#include "disassembler_arm64.h"
-#include "disassembler_mips.h"
-#include "disassembler_x86.h"
+#ifdef ART_ENABLE_CODEGEN_arm
+# include "disassembler_arm.h"
+#endif
+
+#ifdef ART_ENABLE_CODEGEN_arm64
+# include "disassembler_arm64.h"
+#endif
+
+#if defined(ART_ENABLE_CODEGEN_mips) || defined(ART_ENABLE_CODEGEN_mips64)
+# include "disassembler_mips.h"
+#endif
+
+#if defined(ART_ENABLE_CODEGEN_x86) || defined(ART_ENABLE_CODEGEN_x86_64)
+# include "disassembler_x86.h"
+#endif
using android::base::StringPrintf;
@@ -36,21 +47,35 @@
}
Disassembler* Disassembler::Create(InstructionSet instruction_set, DisassemblerOptions* options) {
- if (instruction_set == InstructionSet::kArm || instruction_set == InstructionSet::kThumb2) {
- return new arm::DisassemblerArm(options);
- } else if (instruction_set == InstructionSet::kArm64) {
- return new arm64::DisassemblerArm64(options);
- } else if (instruction_set == InstructionSet::kMips) {
- return new mips::DisassemblerMips(options, /* is_o32_abi= */ true);
- } else if (instruction_set == InstructionSet::kMips64) {
- return new mips::DisassemblerMips(options, /* is_o32_abi= */ false);
- } else if (instruction_set == InstructionSet::kX86) {
- return new x86::DisassemblerX86(options, false);
- } else if (instruction_set == InstructionSet::kX86_64) {
- return new x86::DisassemblerX86(options, true);
- } else {
- UNIMPLEMENTED(FATAL) << static_cast<uint32_t>(instruction_set);
- return nullptr;
+ switch (instruction_set) {
+#ifdef ART_ENABLE_CODEGEN_arm
+ case InstructionSet::kArm:
+ case InstructionSet::kThumb2:
+ return new arm::DisassemblerArm(options);
+#endif
+#ifdef ART_ENABLE_CODEGEN_arm64
+ case InstructionSet::kArm64:
+ return new arm64::DisassemblerArm64(options);
+#endif
+#ifdef ART_ENABLE_CODEGEN_mips
+ case InstructionSet::kMips:
+ return new mips::DisassemblerMips(options, /* is_o32_abi= */ true);
+#endif
+#ifdef ART_ENABLE_CODEGEN_mips64
+ case InstructionSet::kMips64:
+ return new mips::DisassemblerMips(options, /* is_o32_abi= */ false);
+#endif
+#ifdef ART_ENABLE_CODEGEN_x86
+ case InstructionSet::kX86:
+ return new x86::DisassemblerX86(options, /* supports_rex= */ false);
+#endif
+#ifdef ART_ENABLE_CODEGEN_x86_64
+ case InstructionSet::kX86_64:
+ return new x86::DisassemblerX86(options, /* supports_rex= */ true);
+#endif
+ default:
+ UNIMPLEMENTED(FATAL) << static_cast<uint32_t>(instruction_set);
+ return nullptr;
}
}
diff --git a/libartbase/base/file_utils_test.cc b/libartbase/base/file_utils_test.cc
index f7c9c5e..c917307 100644
--- a/libartbase/base/file_utils_test.cc
+++ b/libartbase/base/file_utils_test.cc
@@ -83,11 +83,15 @@
ASSERT_EQ(0, unsetenv("ANDROID_ROOT"));
std::string android_root3 = GetAndroidRootSafe(&error_msg);
// This should be the same as the other root (modulo realpath), otherwise the test setup is
- // broken.
- UniqueCPtr<char> real_root(realpath(android_root.c_str(), nullptr));
+ // broken. On non-bionic. On bionic we can be running with a different libart that lives outside
+ // of ANDROID_ROOT
UniqueCPtr<char> real_root3(realpath(android_root3.c_str(), nullptr));
+#if !defined(__BIONIC__ ) || defined(__ANDROID__)
+ UniqueCPtr<char> real_root(realpath(android_root.c_str(), nullptr));
EXPECT_STREQ(real_root.get(), real_root3.get());
-
+#else
+ EXPECT_STRNE(real_root3.get(), "");
+#endif
// Reset ANDROID_ROOT, as other things may depend on it.
ASSERT_EQ(0, setenv("ANDROID_ROOT", android_root_env.c_str(), /* overwrite */ 1));
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index e9c17ee..d8da912 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -402,6 +402,7 @@
case Intrinsics::kUnsafeLoadFence:
case Intrinsics::kUnsafeStoreFence:
case Intrinsics::kUnsafeFullFence:
+ case Intrinsics::kCRC32Update:
// These intrinsics are on the light greylist and will fail a DCHECK in
// SetIntrinsic() if their flags change on the respective dex methods.
// Note that the DCHECK currently won't fail if the dex methods are
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 7ccfff1..d1d5bc4 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2034,11 +2034,15 @@
}
if (app_image) {
AppImageLoadingHelper::Update(this, space, class_loader, dex_caches, &temp_set);
- // Update class loader and resolved strings. If added_class_table is false, the resolved
- // strings were forwarded UpdateAppImageClassLoadersAndDexCaches.
- UpdateClassLoaderVisitor visitor(space, class_loader.Get());
- for (const ClassTable::TableSlot& root : temp_set) {
- visitor(root.Read());
+
+ {
+ ScopedTrace trace("AppImage:UpdateClassLoaders");
+ // Update class loader and resolved strings. If added_class_table is false, the resolved
+ // strings were forwarded UpdateAppImageClassLoadersAndDexCaches.
+ UpdateClassLoaderVisitor visitor(space, class_loader.Get());
+ for (const ClassTable::TableSlot& root : temp_set) {
+ visitor(root.Read());
+ }
}
if (kBitstringSubtypeCheckEnabled) {
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index e0bbf43..26a8d13 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -1658,7 +1658,9 @@
<< " type=" << to_ref->PrettyTypeOf()
<< " young_gen=" << std::boolalpha << young_gen_ << std::noboolalpha
<< " space=" << heap_->DumpSpaceNameFromAddress(to_ref)
- << " region_type=" << rtype;
+ << " region_type=" << rtype
+ // TODO: Temporary; remove this when this is no longer needed (b/116087961).
+ << " runtime->sentinel=" << Runtime::Current()->GetSentinel().Read<kWithoutReadBarrier>();
}
bool add_to_live_bytes = false;
// Invariant: There should be no object from a newly-allocated
@@ -1702,7 +1704,9 @@
<< " type=" << to_ref->PrettyTypeOf()
<< " young_gen=" << std::boolalpha << young_gen_ << std::noboolalpha
<< " space=" << heap_->DumpSpaceNameFromAddress(to_ref)
- << " region_type=" << rtype;
+ << " region_type=" << rtype
+ // TODO: Temporary; remove this when this is no longer needed (b/116087961).
+ << " runtime->sentinel=" << Runtime::Current()->GetSentinel().Read<kWithoutReadBarrier>();
}
#ifdef USE_BAKER_OR_BROOKS_READ_BARRIER
mirror::Object* referent = nullptr;
diff --git a/runtime/image.cc b/runtime/image.cc
index 376742a..59ac283 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', '6', '6', '\0' }; // Add metadata section.
+const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '7', '\0' }; // Added CRC32 intrinsic
ImageHeader::ImageHeader(uint32_t image_begin,
uint32_t image_size,
diff --git a/runtime/interpreter/interpreter_intrinsics.cc b/runtime/interpreter/interpreter_intrinsics.cc
index 17b3cd4..24a026a 100644
--- a/runtime/interpreter/interpreter_intrinsics.cc
+++ b/runtime/interpreter/interpreter_intrinsics.cc
@@ -558,6 +558,7 @@
UNIMPLEMENTED_CASE(ReferenceGetReferent /* ()Ljava/lang/Object; */)
UNIMPLEMENTED_CASE(IntegerValueOf /* (I)Ljava/lang/Integer; */)
UNIMPLEMENTED_CASE(ThreadInterrupted /* ()Z */)
+ UNIMPLEMENTED_CASE(CRC32Update /* (II)I */)
INTRINSIC_CASE(VarHandleFullFence)
INTRINSIC_CASE(VarHandleAcquireFence)
INTRINSIC_CASE(VarHandleReleaseFence)
diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h
index 48e1728..71b2336 100644
--- a/runtime/interpreter/interpreter_switch_impl-inl.h
+++ b/runtime/interpreter/interpreter_switch_impl-inl.h
@@ -23,6 +23,7 @@
#include "base/memory_tool.h"
#include "base/quasi_atomic.h"
#include "dex/dex_file_types.h"
+#include "dex/dex_instruction_list.h"
#include "experimental_flags.h"
#include "interpreter_common.h"
#include "jit/jit.h"
@@ -36,6 +37,7 @@
namespace art {
namespace interpreter {
+// TODO: Replace macros with member functions.
#define CHECK_FORCE_RETURN() \
{ \
if (UNLIKELY(shadow_frame.GetForcePopFrame())) { \
@@ -46,12 +48,13 @@
SendMethodExitEvents(self, \
instrumentation, \
shadow_frame, \
- shadow_frame.GetThisObject(accessor.InsSize()), \
+ shadow_frame.GetThisObject(Accessor().InsSize()), \
shadow_frame.GetMethod(), \
- inst->GetDexPc(insns), \
+ inst->GetDexPc(Insns()), \
JValue()); \
} \
ctx->result = JValue(); /* Handled in caller. */ \
+ exit_interpreter_loop = true; \
return; \
} \
} \
@@ -65,18 +68,19 @@
if (!MoveToExceptionHandler(self, shadow_frame, instr)) { \
/* Structured locking is to be enforced for abnormal termination, too. */ \
DoMonitorCheckOnExit<do_assignability_check>(self, &shadow_frame); \
- if (interpret_one_instruction) { \
+ if (ctx->interpret_one_instruction) { \
/* Signal mterp to return to caller */ \
shadow_frame.SetDexPC(dex::kDexNoIndex); \
} \
ctx->result = JValue(); /* Handled in caller. */ \
+ exit_interpreter_loop = true; \
return; \
} else { \
CHECK_FORCE_RETURN(); \
int32_t displacement = \
static_cast<int32_t>(shadow_frame.GetDexPC()) - static_cast<int32_t>(dex_pc); \
inst = inst->RelativeAt(displacement); \
- break; /* Stop executing this opcode and continue in the exception handler. */ \
+ return; /* Stop executing this opcode and continue in the exception handler. */ \
} \
} \
do {} while (false)
@@ -138,13 +142,12 @@
CHECK_FORCE_RETURN(); \
if (UNLIKELY(instrumentation->HasDexPcListeners())) { \
if (UNLIKELY(!DoDexPcMoveEvent(self, \
- accessor, \
+ Accessor(), \
shadow_frame, \
dex_pc, \
instrumentation, \
save_ref))) { \
HANDLE_PENDING_EXCEPTION(); \
- break; \
} \
CHECK_FORCE_RETURN(); \
} \
@@ -164,11 +167,12 @@
dex_pc, \
offset, \
&result)) { \
- if (interpret_one_instruction) { \
+ if (ctx->interpret_one_instruction) { \
/* OSR has completed execution of the method. Signal mterp to return to caller */ \
shadow_frame.SetDexPC(dex::kDexNoIndex); \
} \
ctx->result = result; \
+ exit_interpreter_loop = true; \
return; \
} \
} \
@@ -176,6 +180,7 @@
#define HOTNESS_UPDATE() \
{ \
+ jit::Jit* jit = Runtime::Current()->GetJit(); \
if (jit != nullptr) { \
jit->AddSamples(self, shadow_frame.GetMethod(), 1, /*with_backedges=*/ true); \
} \
@@ -193,7 +198,7 @@
if (IsBackwardBranch(offset)) { \
HOTNESS_UPDATE(); \
/* Record new dex pc early to have consistent suspend point at loop header. */ \
- shadow_frame.SetDexPC(inst->GetDexPc(insns)); \
+ shadow_frame.SetDexPC(inst->GetDexPc(Insns())); \
self->AllowThreadSuspension(); \
} \
} \
@@ -268,6 +273,2460 @@
}
}
+// Short-lived helper class which executes single DEX bytecode. It is inlined by compiler.
+//
+// The function names must match the names from dex_instruction_list.h and have no arguments.
+//
+// Any relevant execution information is stored in the fields - it should be kept to minimum.
+//
+template<bool do_access_check, bool transaction_active>
+class InstructionHandler {
+ public:
+ ALWAYS_INLINE void NOP() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void MOVE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_12x(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void MOVE_FROM16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_22x(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_22x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void MOVE_16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_32x(),
+ shadow_frame.GetVReg(inst->VRegB_32x()));
+ inst = inst->Next_3xx();
+ }
+
+ ALWAYS_INLINE void MOVE_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data),
+ shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void MOVE_WIDE_FROM16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_22x(inst_data),
+ shadow_frame.GetVRegLong(inst->VRegB_22x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void MOVE_WIDE_16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_32x(),
+ shadow_frame.GetVRegLong(inst->VRegB_32x()));
+ inst = inst->Next_3xx();
+ }
+
+ ALWAYS_INLINE void MOVE_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegReference(inst->VRegA_12x(inst_data),
+ shadow_frame.GetVRegReference(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void MOVE_OBJECT_FROM16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegReference(inst->VRegA_22x(inst_data),
+ shadow_frame.GetVRegReference(inst->VRegB_22x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void MOVE_OBJECT_16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegReference(inst->VRegA_32x(),
+ shadow_frame.GetVRegReference(inst->VRegB_32x()));
+ inst = inst->Next_3xx();
+ }
+
+ ALWAYS_INLINE void MOVE_RESULT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_11x(inst_data), ResultRegister()->GetI());
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void MOVE_RESULT_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_11x(inst_data), ResultRegister()->GetJ());
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void MOVE_RESULT_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE_SAVE(ResultRegister());
+ shadow_frame.SetVRegReference(inst->VRegA_11x(inst_data), ResultRegister()->GetL());
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void MOVE_EXCEPTION() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Throwable> exception = self->GetException();
+ DCHECK(exception != nullptr) << "No pending exception on MOVE_EXCEPTION instruction";
+ shadow_frame.SetVRegReference(inst->VRegA_11x(inst_data), exception);
+ self->ClearException();
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void RETURN_VOID_NO_BARRIER() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ JValue result;
+ self->AllowThreadSuspension();
+ HANDLE_MONITOR_CHECKS();
+ if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
+ !SendMethodExitEvents(self,
+ instrumentation,
+ shadow_frame,
+ shadow_frame.GetThisObject(Accessor().InsSize()),
+ shadow_frame.GetMethod(),
+ inst->GetDexPc(Insns()),
+ result))) {
+ HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
+ }
+ if (ctx->interpret_one_instruction) {
+ /* Signal mterp to return to caller */
+ shadow_frame.SetDexPC(dex::kDexNoIndex);
+ }
+ ctx->result = result;
+ exit_interpreter_loop = true;
+ }
+
+ ALWAYS_INLINE void RETURN_VOID() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ QuasiAtomic::ThreadFenceForConstructor();
+ JValue result;
+ self->AllowThreadSuspension();
+ HANDLE_MONITOR_CHECKS();
+ if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
+ !SendMethodExitEvents(self,
+ instrumentation,
+ shadow_frame,
+ shadow_frame.GetThisObject(Accessor().InsSize()),
+ shadow_frame.GetMethod(),
+ inst->GetDexPc(Insns()),
+ result))) {
+ HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
+ }
+ if (ctx->interpret_one_instruction) {
+ /* Signal mterp to return to caller */
+ shadow_frame.SetDexPC(dex::kDexNoIndex);
+ }
+ ctx->result = result;
+ exit_interpreter_loop = true;
+ }
+
+ ALWAYS_INLINE void RETURN() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ JValue result;
+ result.SetJ(0);
+ result.SetI(shadow_frame.GetVReg(inst->VRegA_11x(inst_data)));
+ self->AllowThreadSuspension();
+ HANDLE_MONITOR_CHECKS();
+ if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
+ !SendMethodExitEvents(self,
+ instrumentation,
+ shadow_frame,
+ shadow_frame.GetThisObject(Accessor().InsSize()),
+ shadow_frame.GetMethod(),
+ inst->GetDexPc(Insns()),
+ result))) {
+ HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
+ }
+ if (ctx->interpret_one_instruction) {
+ /* Signal mterp to return to caller */
+ shadow_frame.SetDexPC(dex::kDexNoIndex);
+ }
+ ctx->result = result;
+ exit_interpreter_loop = true;
+ }
+
+ ALWAYS_INLINE void RETURN_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ JValue result;
+ result.SetJ(shadow_frame.GetVRegLong(inst->VRegA_11x(inst_data)));
+ self->AllowThreadSuspension();
+ HANDLE_MONITOR_CHECKS();
+ if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
+ !SendMethodExitEvents(self,
+ instrumentation,
+ shadow_frame,
+ shadow_frame.GetThisObject(Accessor().InsSize()),
+ shadow_frame.GetMethod(),
+ inst->GetDexPc(Insns()),
+ result))) {
+ HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
+ }
+ if (ctx->interpret_one_instruction) {
+ /* Signal mterp to return to caller */
+ shadow_frame.SetDexPC(dex::kDexNoIndex);
+ }
+ ctx->result = result;
+ exit_interpreter_loop = true;
+ }
+
+ ALWAYS_INLINE void RETURN_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ JValue result;
+ self->AllowThreadSuspension();
+ HANDLE_MONITOR_CHECKS();
+ const size_t ref_idx = inst->VRegA_11x(inst_data);
+ ObjPtr<mirror::Object> obj_result = shadow_frame.GetVRegReference(ref_idx);
+ if (do_assignability_check && obj_result != nullptr) {
+ ObjPtr<mirror::Class> return_type = shadow_frame.GetMethod()->ResolveReturnType();
+ // Re-load since it might have moved.
+ obj_result = shadow_frame.GetVRegReference(ref_idx);
+ if (return_type == nullptr) {
+ // Return the pending exception.
+ HANDLE_PENDING_EXCEPTION();
+ }
+ if (!obj_result->VerifierInstanceOf(return_type)) {
+ // This should never happen.
+ std::string temp1, temp2;
+ self->ThrowNewExceptionF("Ljava/lang/InternalError;",
+ "Returning '%s' that is not instance of return type '%s'",
+ obj_result->GetClass()->GetDescriptor(&temp1),
+ return_type->GetDescriptor(&temp2));
+ HANDLE_PENDING_EXCEPTION();
+ }
+ }
+ result.SetL(obj_result);
+ if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
+ !SendMethodExitEvents(self,
+ instrumentation,
+ shadow_frame,
+ shadow_frame.GetThisObject(Accessor().InsSize()),
+ shadow_frame.GetMethod(),
+ inst->GetDexPc(Insns()),
+ result))) {
+ HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
+ }
+ // Re-load since it might have moved during the MethodExitEvent.
+ result.SetL(shadow_frame.GetVRegReference(ref_idx));
+ if (ctx->interpret_one_instruction) {
+ /* Signal mterp to return to caller */
+ shadow_frame.SetDexPC(dex::kDexNoIndex);
+ }
+ ctx->result = result;
+ exit_interpreter_loop = true;
+ }
+
+ ALWAYS_INLINE void CONST_4() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t dst = inst->VRegA_11n(inst_data);
+ int4_t val = inst->VRegB_11n(inst_data);
+ shadow_frame.SetVReg(dst, val);
+ if (val == 0) {
+ shadow_frame.SetVRegReference(dst, nullptr);
+ }
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void CONST_16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint8_t dst = inst->VRegA_21s(inst_data);
+ int16_t val = inst->VRegB_21s();
+ shadow_frame.SetVReg(dst, val);
+ if (val == 0) {
+ shadow_frame.SetVRegReference(dst, nullptr);
+ }
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void CONST() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint8_t dst = inst->VRegA_31i(inst_data);
+ int32_t val = inst->VRegB_31i();
+ shadow_frame.SetVReg(dst, val);
+ if (val == 0) {
+ shadow_frame.SetVRegReference(dst, nullptr);
+ }
+ inst = inst->Next_3xx();
+ }
+
+ ALWAYS_INLINE void CONST_HIGH16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint8_t dst = inst->VRegA_21h(inst_data);
+ int32_t val = static_cast<int32_t>(inst->VRegB_21h() << 16);
+ shadow_frame.SetVReg(dst, val);
+ if (val == 0) {
+ shadow_frame.SetVRegReference(dst, nullptr);
+ }
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void CONST_WIDE_16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_21s(inst_data), inst->VRegB_21s());
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void CONST_WIDE_32() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_31i(inst_data), inst->VRegB_31i());
+ inst = inst->Next_3xx();
+ }
+
+ ALWAYS_INLINE void CONST_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_51l(inst_data), inst->VRegB_51l());
+ inst = inst->Next_51l();
+ }
+
+ ALWAYS_INLINE void CONST_WIDE_HIGH16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_21h(inst_data),
+ static_cast<uint64_t>(inst->VRegB_21h()) << 48);
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void CONST_STRING() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::String> s = ResolveString(self,
+ shadow_frame,
+ dex::StringIndex(inst->VRegB_21c()));
+ if (UNLIKELY(s == nullptr)) {
+ HANDLE_PENDING_EXCEPTION();
+ } else {
+ shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), s);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void CONST_STRING_JUMBO() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::String> s = ResolveString(self,
+ shadow_frame,
+ dex::StringIndex(inst->VRegB_31c()));
+ if (UNLIKELY(s == nullptr)) {
+ HANDLE_PENDING_EXCEPTION();
+ } else {
+ shadow_frame.SetVRegReference(inst->VRegA_31c(inst_data), s);
+ inst = inst->Next_3xx();
+ }
+ }
+
+ ALWAYS_INLINE void CONST_CLASS() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
+ shadow_frame.GetMethod(),
+ self,
+ false,
+ do_access_check);
+ if (UNLIKELY(c == nullptr)) {
+ HANDLE_PENDING_EXCEPTION();
+ } else {
+ shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), c);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void CONST_METHOD_HANDLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ClassLinker* cl = Runtime::Current()->GetClassLinker();
+ ObjPtr<mirror::MethodHandle> mh = cl->ResolveMethodHandle(self,
+ inst->VRegB_21c(),
+ shadow_frame.GetMethod());
+ if (UNLIKELY(mh == nullptr)) {
+ HANDLE_PENDING_EXCEPTION();
+ } else {
+ shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), mh);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void CONST_METHOD_TYPE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ClassLinker* cl = Runtime::Current()->GetClassLinker();
+ ObjPtr<mirror::MethodType> mt = cl->ResolveMethodType(self,
+ dex::ProtoIndex(inst->VRegB_21c()),
+ shadow_frame.GetMethod());
+ if (UNLIKELY(mt == nullptr)) {
+ HANDLE_PENDING_EXCEPTION();
+ } else {
+ shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), mt);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void MONITOR_ENTER() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ HANDLE_ASYNC_EXCEPTION();
+ ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
+ if (UNLIKELY(obj == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ } else {
+ DoMonitorEnter<do_assignability_check>(self, &shadow_frame, obj);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx);
+ }
+ }
+
+ ALWAYS_INLINE void MONITOR_EXIT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ HANDLE_ASYNC_EXCEPTION();
+ ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
+ if (UNLIKELY(obj == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ } else {
+ DoMonitorExit<do_assignability_check>(self, &shadow_frame, obj);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx);
+ }
+ }
+
+ ALWAYS_INLINE void CHECK_CAST() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
+ shadow_frame.GetMethod(),
+ self,
+ false,
+ do_access_check);
+ if (UNLIKELY(c == nullptr)) {
+ HANDLE_PENDING_EXCEPTION();
+ } else {
+ ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegA_21c(inst_data));
+ if (UNLIKELY(obj != nullptr && !obj->InstanceOf(c))) {
+ ThrowClassCastException(c, obj->GetClass());
+ HANDLE_PENDING_EXCEPTION();
+ } else {
+ inst = inst->Next_2xx();
+ }
+ }
+ }
+
+ ALWAYS_INLINE void INSTANCE_OF() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegC_22c()),
+ shadow_frame.GetMethod(),
+ self,
+ false,
+ do_access_check);
+ if (UNLIKELY(c == nullptr)) {
+ HANDLE_PENDING_EXCEPTION();
+ } else {
+ ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
+ shadow_frame.SetVReg(inst->VRegA_22c(inst_data),
+ (obj != nullptr && obj->InstanceOf(c)) ? 1 : 0);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void ARRAY_LENGTH() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Object> array = shadow_frame.GetVRegReference(inst->VRegB_12x(inst_data));
+ if (UNLIKELY(array == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ } else {
+ shadow_frame.SetVReg(inst->VRegA_12x(inst_data), array->AsArray()->GetLength());
+ inst = inst->Next_1xx();
+ }
+ }
+
+ ALWAYS_INLINE void NEW_INSTANCE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Object> obj = nullptr;
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
+ shadow_frame.GetMethod(),
+ self,
+ false,
+ do_access_check);
+ if (LIKELY(c != nullptr)) {
+ if (UNLIKELY(c->IsStringClass())) {
+ gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
+ obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
+ } else {
+ obj = AllocObjectFromCode<true>(
+ c.Ptr(),
+ self,
+ Runtime::Current()->GetHeap()->GetCurrentAllocator());
+ }
+ }
+ if (UNLIKELY(obj == nullptr)) {
+ HANDLE_PENDING_EXCEPTION();
+ } else {
+ obj->GetClass()->AssertInitializedOrInitializingInThread(self);
+ // Don't allow finalizable objects to be allocated during a transaction since these can't
+ // be finalized without a started runtime.
+ if (transaction_active && obj->GetClass()->IsFinalizable()) {
+ AbortTransactionF(self, "Allocating finalizable object in transaction: %s",
+ obj->PrettyTypeOf().c_str());
+ HANDLE_PENDING_EXCEPTION();
+ }
+ shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), obj);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void NEW_ARRAY() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ int32_t length = shadow_frame.GetVReg(inst->VRegB_22c(inst_data));
+ ObjPtr<mirror::Object> obj = AllocArrayFromCode<do_access_check, true>(
+ dex::TypeIndex(inst->VRegC_22c()),
+ length,
+ shadow_frame.GetMethod(),
+ self,
+ Runtime::Current()->GetHeap()->GetCurrentAllocator());
+ if (UNLIKELY(obj == nullptr)) {
+ HANDLE_PENDING_EXCEPTION();
+ } else {
+ shadow_frame.SetVRegReference(inst->VRegA_22c(inst_data), obj);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void FILLED_NEW_ARRAY() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success =
+ DoFilledNewArray<false, do_access_check, transaction_active>(inst, shadow_frame, self,
+ ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+ }
+
+ ALWAYS_INLINE void FILLED_NEW_ARRAY_RANGE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success =
+ DoFilledNewArray<true, do_access_check, transaction_active>(inst, shadow_frame,
+ self, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+ }
+
+ ALWAYS_INLINE void FILL_ARRAY_DATA() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ const uint16_t* payload_addr = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
+ const Instruction::ArrayDataPayload* payload =
+ reinterpret_cast<const Instruction::ArrayDataPayload*>(payload_addr);
+ ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegA_31t(inst_data));
+ bool success = FillArrayData(obj, payload);
+ if (!success) {
+ HANDLE_PENDING_EXCEPTION();
+ }
+ if (transaction_active) {
+ RecordArrayElementsInTransaction(obj->AsArray(), payload->element_count);
+ }
+ inst = inst->Next_3xx();
+ }
+
+ ALWAYS_INLINE void THROW() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ HANDLE_ASYNC_EXCEPTION();
+ ObjPtr<mirror::Object> exception =
+ shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
+ if (UNLIKELY(exception == nullptr)) {
+ ThrowNullPointerException("throw with null exception");
+ } else if (do_assignability_check && !exception->GetClass()->IsThrowableClass()) {
+ // This should never happen.
+ std::string temp;
+ self->ThrowNewExceptionF("Ljava/lang/InternalError;",
+ "Throwing '%s' that is not instance of Throwable",
+ exception->GetClass()->GetDescriptor(&temp));
+ } else {
+ self->SetException(exception->AsThrowable());
+ }
+ HANDLE_PENDING_EXCEPTION();
+ }
+
+ ALWAYS_INLINE void GOTO() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ HANDLE_ASYNC_EXCEPTION();
+ int8_t offset = inst->VRegA_10t(inst_data);
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ }
+
+ ALWAYS_INLINE void GOTO_16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ HANDLE_ASYNC_EXCEPTION();
+ int16_t offset = inst->VRegA_20t();
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ }
+
+ ALWAYS_INLINE void GOTO_32() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ HANDLE_ASYNC_EXCEPTION();
+ int32_t offset = inst->VRegA_30t();
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ }
+
+ ALWAYS_INLINE void PACKED_SWITCH() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ int32_t offset = DoPackedSwitch(inst, shadow_frame, inst_data);
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ }
+
+ ALWAYS_INLINE void SPARSE_SWITCH() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ int32_t offset = DoSparseSwitch(inst, shadow_frame, inst_data);
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ }
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wfloat-equal"
+
+
+ ALWAYS_INLINE void CMPL_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ float val1 = shadow_frame.GetVRegFloat(inst->VRegB_23x());
+ float val2 = shadow_frame.GetVRegFloat(inst->VRegC_23x());
+ int32_t result;
+ if (val1 > val2) {
+ result = 1;
+ } else if (val1 == val2) {
+ result = 0;
+ } else {
+ result = -1;
+ }
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void CMPG_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ float val1 = shadow_frame.GetVRegFloat(inst->VRegB_23x());
+ float val2 = shadow_frame.GetVRegFloat(inst->VRegC_23x());
+ int32_t result;
+ if (val1 < val2) {
+ result = -1;
+ } else if (val1 == val2) {
+ result = 0;
+ } else {
+ result = 1;
+ }
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void CMPL_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ double val1 = shadow_frame.GetVRegDouble(inst->VRegB_23x());
+ double val2 = shadow_frame.GetVRegDouble(inst->VRegC_23x());
+ int32_t result;
+ if (val1 > val2) {
+ result = 1;
+ } else if (val1 == val2) {
+ result = 0;
+ } else {
+ result = -1;
+ }
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
+ inst = inst->Next_2xx();
+ }
+
+
+ ALWAYS_INLINE void CMPG_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ double val1 = shadow_frame.GetVRegDouble(inst->VRegB_23x());
+ double val2 = shadow_frame.GetVRegDouble(inst->VRegC_23x());
+ int32_t result;
+ if (val1 < val2) {
+ result = -1;
+ } else if (val1 == val2) {
+ result = 0;
+ } else {
+ result = 1;
+ }
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
+ inst = inst->Next_2xx();
+ }
+
+#pragma clang diagnostic pop
+
+
+ ALWAYS_INLINE void CMP_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ int64_t val1 = shadow_frame.GetVRegLong(inst->VRegB_23x());
+ int64_t val2 = shadow_frame.GetVRegLong(inst->VRegC_23x());
+ int32_t result;
+ if (val1 > val2) {
+ result = 1;
+ } else if (val1 == val2) {
+ result = 0;
+ } else {
+ result = -1;
+ }
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void IF_EQ() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) ==
+ shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
+ int16_t offset = inst->VRegC_22t();
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ } else {
+ BRANCH_INSTRUMENTATION(2);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void IF_NE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) !=
+ shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
+ int16_t offset = inst->VRegC_22t();
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ } else {
+ BRANCH_INSTRUMENTATION(2);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void IF_LT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) <
+ shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
+ int16_t offset = inst->VRegC_22t();
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ } else {
+ BRANCH_INSTRUMENTATION(2);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void IF_GE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) >=
+ shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
+ int16_t offset = inst->VRegC_22t();
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ } else {
+ BRANCH_INSTRUMENTATION(2);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void IF_GT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) >
+ shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
+ int16_t offset = inst->VRegC_22t();
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ } else {
+ BRANCH_INSTRUMENTATION(2);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void IF_LE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) <=
+ shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
+ int16_t offset = inst->VRegC_22t();
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ } else {
+ BRANCH_INSTRUMENTATION(2);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void IF_EQZ() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) == 0) {
+ int16_t offset = inst->VRegB_21t();
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ } else {
+ BRANCH_INSTRUMENTATION(2);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void IF_NEZ() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) != 0) {
+ int16_t offset = inst->VRegB_21t();
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ } else {
+ BRANCH_INSTRUMENTATION(2);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void IF_LTZ() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) < 0) {
+ int16_t offset = inst->VRegB_21t();
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ } else {
+ BRANCH_INSTRUMENTATION(2);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void IF_GEZ() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) >= 0) {
+ int16_t offset = inst->VRegB_21t();
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ } else {
+ BRANCH_INSTRUMENTATION(2);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void IF_GTZ() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) > 0) {
+ int16_t offset = inst->VRegB_21t();
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ } else {
+ BRANCH_INSTRUMENTATION(2);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void IF_LEZ() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) <= 0) {
+ int16_t offset = inst->VRegB_21t();
+ BRANCH_INSTRUMENTATION(offset);
+ inst = inst->RelativeAt(offset);
+ HANDLE_BACKWARD_BRANCH(offset);
+ } else {
+ BRANCH_INSTRUMENTATION(2);
+ inst = inst->Next_2xx();
+ }
+ }
+
+ ALWAYS_INLINE void AGET_BOOLEAN() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+ if (UNLIKELY(a == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ }
+ int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+ ObjPtr<mirror::BooleanArray> array = a->AsBooleanArray();
+ if (array->CheckIsValidIndex(index)) {
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
+ inst = inst->Next_2xx();
+ } else {
+ HANDLE_PENDING_EXCEPTION();
+ }
+ }
+
+ ALWAYS_INLINE void AGET_BYTE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+ if (UNLIKELY(a == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ }
+ int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+ ObjPtr<mirror::ByteArray> array = a->AsByteArray();
+ if (array->CheckIsValidIndex(index)) {
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
+ inst = inst->Next_2xx();
+ } else {
+ HANDLE_PENDING_EXCEPTION();
+ }
+ }
+
+ ALWAYS_INLINE void AGET_CHAR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+ if (UNLIKELY(a == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ }
+ int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+ ObjPtr<mirror::CharArray> array = a->AsCharArray();
+ if (array->CheckIsValidIndex(index)) {
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
+ inst = inst->Next_2xx();
+ } else {
+ HANDLE_PENDING_EXCEPTION();
+ }
+ }
+
+ ALWAYS_INLINE void AGET_SHORT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+ if (UNLIKELY(a == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ }
+ int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+ ObjPtr<mirror::ShortArray> array = a->AsShortArray();
+ if (array->CheckIsValidIndex(index)) {
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
+ inst = inst->Next_2xx();
+ } else {
+ HANDLE_PENDING_EXCEPTION();
+ }
+ }
+
+ ALWAYS_INLINE void AGET() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+ if (UNLIKELY(a == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ }
+ int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+ DCHECK(a->IsIntArray() || a->IsFloatArray()) << a->PrettyTypeOf();
+ ObjPtr<mirror::IntArray> array = ObjPtr<mirror::IntArray>::DownCast(a);
+ if (array->CheckIsValidIndex(index)) {
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
+ inst = inst->Next_2xx();
+ } else {
+ HANDLE_PENDING_EXCEPTION();
+ }
+ }
+
+ ALWAYS_INLINE void AGET_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+ if (UNLIKELY(a == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ }
+ int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+ DCHECK(a->IsLongArray() || a->IsDoubleArray()) << a->PrettyTypeOf();
+ ObjPtr<mirror::LongArray> array = ObjPtr<mirror::LongArray>::DownCast(a);
+ if (array->CheckIsValidIndex(index)) {
+ shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
+ inst = inst->Next_2xx();
+ } else {
+ HANDLE_PENDING_EXCEPTION();
+ }
+ }
+
+ ALWAYS_INLINE void AGET_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+ if (UNLIKELY(a == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ }
+ int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+ ObjPtr<mirror::ObjectArray<mirror::Object>> array = a->AsObjectArray<mirror::Object>();
+ if (array->CheckIsValidIndex(index)) {
+ shadow_frame.SetVRegReference(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
+ inst = inst->Next_2xx();
+ } else {
+ HANDLE_PENDING_EXCEPTION();
+ }
+ }
+
+ ALWAYS_INLINE void APUT_BOOLEAN() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+ if (UNLIKELY(a == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ }
+ uint8_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
+ int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+ ObjPtr<mirror::BooleanArray> array = a->AsBooleanArray();
+ if (array->CheckIsValidIndex(index)) {
+ array->SetWithoutChecks<transaction_active>(index, val);
+ inst = inst->Next_2xx();
+ } else {
+ HANDLE_PENDING_EXCEPTION();
+ }
+ }
+
+ ALWAYS_INLINE void APUT_BYTE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+ if (UNLIKELY(a == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ }
+ int8_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
+ int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+ ObjPtr<mirror::ByteArray> array = a->AsByteArray();
+ if (array->CheckIsValidIndex(index)) {
+ array->SetWithoutChecks<transaction_active>(index, val);
+ inst = inst->Next_2xx();
+ } else {
+ HANDLE_PENDING_EXCEPTION();
+ }
+ }
+
+ ALWAYS_INLINE void APUT_CHAR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+ if (UNLIKELY(a == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ }
+ uint16_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
+ int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+ ObjPtr<mirror::CharArray> array = a->AsCharArray();
+ if (array->CheckIsValidIndex(index)) {
+ array->SetWithoutChecks<transaction_active>(index, val);
+ inst = inst->Next_2xx();
+ } else {
+ HANDLE_PENDING_EXCEPTION();
+ }
+ }
+
+ ALWAYS_INLINE void APUT_SHORT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+ if (UNLIKELY(a == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ }
+ int16_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
+ int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+ ObjPtr<mirror::ShortArray> array = a->AsShortArray();
+ if (array->CheckIsValidIndex(index)) {
+ array->SetWithoutChecks<transaction_active>(index, val);
+ inst = inst->Next_2xx();
+ } else {
+ HANDLE_PENDING_EXCEPTION();
+ }
+ }
+
+ ALWAYS_INLINE void APUT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+ if (UNLIKELY(a == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ }
+ int32_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
+ int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+ DCHECK(a->IsIntArray() || a->IsFloatArray()) << a->PrettyTypeOf();
+ ObjPtr<mirror::IntArray> array = ObjPtr<mirror::IntArray>::DownCast(a);
+ if (array->CheckIsValidIndex(index)) {
+ array->SetWithoutChecks<transaction_active>(index, val);
+ inst = inst->Next_2xx();
+ } else {
+ HANDLE_PENDING_EXCEPTION();
+ }
+ }
+
+ ALWAYS_INLINE void APUT_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+ if (UNLIKELY(a == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ }
+ int64_t val = shadow_frame.GetVRegLong(inst->VRegA_23x(inst_data));
+ int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+ DCHECK(a->IsLongArray() || a->IsDoubleArray()) << a->PrettyTypeOf();
+ ObjPtr<mirror::LongArray> array = ObjPtr<mirror::LongArray>::DownCast(a);
+ if (array->CheckIsValidIndex(index)) {
+ array->SetWithoutChecks<transaction_active>(index, val);
+ inst = inst->Next_2xx();
+ } else {
+ HANDLE_PENDING_EXCEPTION();
+ }
+ }
+
+ ALWAYS_INLINE void APUT_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+ if (UNLIKELY(a == nullptr)) {
+ ThrowNullPointerExceptionFromInterpreter();
+ HANDLE_PENDING_EXCEPTION();
+ }
+ int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+ ObjPtr<mirror::Object> val = shadow_frame.GetVRegReference(inst->VRegA_23x(inst_data));
+ ObjPtr<mirror::ObjectArray<mirror::Object>> array = a->AsObjectArray<mirror::Object>();
+ if (array->CheckIsValidIndex(index) && array->CheckAssignable(val)) {
+ array->SetWithoutChecks<transaction_active>(index, val);
+ inst = inst->Next_2xx();
+ } else {
+ HANDLE_PENDING_EXCEPTION();
+ }
+ }
+
+ ALWAYS_INLINE void IGET_BOOLEAN() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimBoolean, do_access_check>(
+ self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IGET_BYTE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimByte, do_access_check>(
+ self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IGET_CHAR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimChar, do_access_check>(
+ self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IGET_SHORT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimShort, do_access_check>(
+ self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IGET() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimInt, do_access_check>(
+ self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IGET_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimLong, do_access_check>(
+ self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IGET_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldGet<InstanceObjectRead, Primitive::kPrimNot, do_access_check>(
+ self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IGET_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIGetQuick<Primitive::kPrimInt>(shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IGET_WIDE_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIGetQuick<Primitive::kPrimLong>(shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IGET_OBJECT_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIGetQuick<Primitive::kPrimNot>(shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IGET_BOOLEAN_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIGetQuick<Primitive::kPrimBoolean>(shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IGET_BYTE_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIGetQuick<Primitive::kPrimByte>(shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IGET_CHAR_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIGetQuick<Primitive::kPrimChar>(shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IGET_SHORT_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIGetQuick<Primitive::kPrimShort>(shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void SGET_BOOLEAN() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void SGET_BYTE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void SGET_CHAR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void SGET_SHORT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void SGET() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void SGET_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void SGET_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldGet<StaticObjectRead, Primitive::kPrimNot, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IPUT_BOOLEAN() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IPUT_BYTE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IPUT_CHAR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IPUT_SHORT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IPUT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IPUT_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IPUT_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IPUT_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIPutQuick<Primitive::kPrimInt, transaction_active>(
+ shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IPUT_BOOLEAN_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIPutQuick<Primitive::kPrimBoolean, transaction_active>(
+ shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IPUT_BYTE_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIPutQuick<Primitive::kPrimByte, transaction_active>(
+ shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IPUT_CHAR_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIPutQuick<Primitive::kPrimChar, transaction_active>(
+ shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IPUT_SHORT_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIPutQuick<Primitive::kPrimShort, transaction_active>(
+ shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IPUT_WIDE_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIPutQuick<Primitive::kPrimLong, transaction_active>(
+ shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void IPUT_OBJECT_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIPutQuick<Primitive::kPrimNot, transaction_active>(
+ shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void SPUT_BOOLEAN() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void SPUT_BYTE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void SPUT_CHAR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void SPUT_SHORT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void SPUT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void SPUT_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void SPUT_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check,
+ transaction_active>(self, shadow_frame, inst, inst_data);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void INVOKE_VIRTUAL() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoInvoke<kVirtual, false, do_access_check, /*is_mterp=*/ false>(
+ self, shadow_frame, inst, inst_data, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+ }
+
+ ALWAYS_INLINE void INVOKE_VIRTUAL_RANGE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoInvoke<kVirtual, true, do_access_check, /*is_mterp=*/ false>(
+ self, shadow_frame, inst, inst_data, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+ }
+
+ ALWAYS_INLINE void INVOKE_SUPER() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoInvoke<kSuper, false, do_access_check, /*is_mterp=*/ false>(
+ self, shadow_frame, inst, inst_data, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+ }
+
+ ALWAYS_INLINE void INVOKE_SUPER_RANGE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoInvoke<kSuper, true, do_access_check, /*is_mterp=*/ false>(
+ self, shadow_frame, inst, inst_data, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+ }
+
+ ALWAYS_INLINE void INVOKE_DIRECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoInvoke<kDirect, false, do_access_check, /*is_mterp=*/ false>(
+ self, shadow_frame, inst, inst_data, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+ }
+
+ ALWAYS_INLINE void INVOKE_DIRECT_RANGE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoInvoke<kDirect, true, do_access_check, /*is_mterp=*/ false>(
+ self, shadow_frame, inst, inst_data, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+ }
+
+ ALWAYS_INLINE void INVOKE_INTERFACE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoInvoke<kInterface, false, do_access_check, /*is_mterp=*/ false>(
+ self, shadow_frame, inst, inst_data, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+ }
+
+ ALWAYS_INLINE void INVOKE_INTERFACE_RANGE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoInvoke<kInterface, true, do_access_check, /*is_mterp=*/ false>(
+ self, shadow_frame, inst, inst_data, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+ }
+
+ ALWAYS_INLINE void INVOKE_STATIC() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoInvoke<kStatic, false, do_access_check, /*is_mterp=*/ false>(
+ self, shadow_frame, inst, inst_data, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+ }
+
+ ALWAYS_INLINE void INVOKE_STATIC_RANGE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoInvoke<kStatic, true, do_access_check, /*is_mterp=*/ false>(
+ self, shadow_frame, inst, inst_data, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+ }
+
+ ALWAYS_INLINE void INVOKE_VIRTUAL_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoInvoke<kVirtual, false, do_access_check, /*is_mterp=*/ false,
+ /*is_quick=*/ true>(self, shadow_frame, inst, inst_data, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+ }
+
+ ALWAYS_INLINE void INVOKE_VIRTUAL_RANGE_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoInvoke<kVirtual, true, do_access_check, /*is_mterp=*/ false,
+ /*is_quick=*/ true>(self, shadow_frame, inst, inst_data, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+ }
+
+ ALWAYS_INLINE void INVOKE_POLYMORPHIC() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
+ bool success = DoInvokePolymorphic</* is_range= */ false>(
+ self, shadow_frame, inst, inst_data, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(!success);
+ }
+
+ ALWAYS_INLINE void INVOKE_POLYMORPHIC_RANGE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
+ bool success = DoInvokePolymorphic</* is_range= */ true>(
+ self, shadow_frame, inst, inst_data, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(!success);
+ }
+
+ ALWAYS_INLINE void INVOKE_CUSTOM() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
+ bool success = DoInvokeCustom</* is_range= */ false>(
+ self, shadow_frame, inst, inst_data, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+ }
+
+ ALWAYS_INLINE void INVOKE_CUSTOM_RANGE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
+ bool success = DoInvokeCustom</* is_range= */ true>(
+ self, shadow_frame, inst, inst_data, ResultRegister());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+ }
+
+ ALWAYS_INLINE void NEG_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(
+ inst->VRegA_12x(inst_data), -shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void NOT_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(
+ inst->VRegA_12x(inst_data), ~shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void NEG_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(
+ inst->VRegA_12x(inst_data), -shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void NOT_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(
+ inst->VRegA_12x(inst_data), ~shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void NEG_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegFloat(
+ inst->VRegA_12x(inst_data), -shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void NEG_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegDouble(
+ inst->VRegA_12x(inst_data), -shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void INT_TO_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void INT_TO_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegFloat(inst->VRegA_12x(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void INT_TO_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegDouble(inst->VRegA_12x(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void LONG_TO_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_12x(inst_data),
+ shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void LONG_TO_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegFloat(inst->VRegA_12x(inst_data),
+ shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void LONG_TO_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegDouble(inst->VRegA_12x(inst_data),
+ shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void FLOAT_TO_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ float val = shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data));
+ int32_t result = art_float_to_integral<int32_t, float>(val);
+ shadow_frame.SetVReg(inst->VRegA_12x(inst_data), result);
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void FLOAT_TO_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ float val = shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data));
+ int64_t result = art_float_to_integral<int64_t, float>(val);
+ shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data), result);
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void FLOAT_TO_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegDouble(inst->VRegA_12x(inst_data),
+ shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void DOUBLE_TO_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ double val = shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data));
+ int32_t result = art_float_to_integral<int32_t, double>(val);
+ shadow_frame.SetVReg(inst->VRegA_12x(inst_data), result);
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void DOUBLE_TO_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ double val = shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data));
+ int64_t result = art_float_to_integral<int64_t, double>(val);
+ shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data), result);
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void DOUBLE_TO_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegFloat(inst->VRegA_12x(inst_data),
+ shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void INT_TO_BYTE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_12x(inst_data), static_cast<int8_t>(
+ shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void INT_TO_CHAR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_12x(inst_data), static_cast<uint16_t>(
+ shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void INT_TO_SHORT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_12x(inst_data), static_cast<int16_t>(
+ shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void ADD_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+ SafeAdd(shadow_frame.GetVReg(inst->VRegB_23x()),
+ shadow_frame.GetVReg(inst->VRegC_23x())));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void SUB_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+ SafeSub(shadow_frame.GetVReg(inst->VRegB_23x()),
+ shadow_frame.GetVReg(inst->VRegC_23x())));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void MUL_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+ SafeMul(shadow_frame.GetVReg(inst->VRegB_23x()),
+ shadow_frame.GetVReg(inst->VRegC_23x())));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void DIV_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIntDivide(shadow_frame, inst->VRegA_23x(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_23x()),
+ shadow_frame.GetVReg(inst->VRegC_23x()));
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void REM_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIntRemainder(shadow_frame, inst->VRegA_23x(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_23x()),
+ shadow_frame.GetVReg(inst->VRegC_23x()));
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void SHL_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_23x()) <<
+ (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x1f));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void SHR_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_23x()) >>
+ (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x1f));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void USHR_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+ static_cast<uint32_t>(shadow_frame.GetVReg(inst->VRegB_23x())) >>
+ (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x1f));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void AND_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_23x()) &
+ shadow_frame.GetVReg(inst->VRegC_23x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void OR_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_23x()) |
+ shadow_frame.GetVReg(inst->VRegC_23x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void XOR_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_23x()) ^
+ shadow_frame.GetVReg(inst->VRegC_23x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void ADD_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+ SafeAdd(shadow_frame.GetVRegLong(inst->VRegB_23x()),
+ shadow_frame.GetVRegLong(inst->VRegC_23x())));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void SUB_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+ SafeSub(shadow_frame.GetVRegLong(inst->VRegB_23x()),
+ shadow_frame.GetVRegLong(inst->VRegC_23x())));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void MUL_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+ SafeMul(shadow_frame.GetVRegLong(inst->VRegB_23x()),
+ shadow_frame.GetVRegLong(inst->VRegC_23x())));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void DIV_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ DoLongDivide(shadow_frame, inst->VRegA_23x(inst_data),
+ shadow_frame.GetVRegLong(inst->VRegB_23x()),
+ shadow_frame.GetVRegLong(inst->VRegC_23x()));
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_2xx);
+ }
+
+ ALWAYS_INLINE void REM_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ DoLongRemainder(shadow_frame, inst->VRegA_23x(inst_data),
+ shadow_frame.GetVRegLong(inst->VRegB_23x()),
+ shadow_frame.GetVRegLong(inst->VRegC_23x()));
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_2xx);
+ }
+
+ ALWAYS_INLINE void AND_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVRegLong(inst->VRegB_23x()) &
+ shadow_frame.GetVRegLong(inst->VRegC_23x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void OR_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVRegLong(inst->VRegB_23x()) |
+ shadow_frame.GetVRegLong(inst->VRegC_23x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void XOR_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVRegLong(inst->VRegB_23x()) ^
+ shadow_frame.GetVRegLong(inst->VRegC_23x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void SHL_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVRegLong(inst->VRegB_23x()) <<
+ (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x3f));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void SHR_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVRegLong(inst->VRegB_23x()) >>
+ (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x3f));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void USHR_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+ static_cast<uint64_t>(shadow_frame.GetVRegLong(inst->VRegB_23x())) >>
+ (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x3f));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void ADD_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVRegFloat(inst->VRegB_23x()) +
+ shadow_frame.GetVRegFloat(inst->VRegC_23x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void SUB_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVRegFloat(inst->VRegB_23x()) -
+ shadow_frame.GetVRegFloat(inst->VRegC_23x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void MUL_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVRegFloat(inst->VRegB_23x()) *
+ shadow_frame.GetVRegFloat(inst->VRegC_23x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void DIV_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVRegFloat(inst->VRegB_23x()) /
+ shadow_frame.GetVRegFloat(inst->VRegC_23x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void REM_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
+ fmodf(shadow_frame.GetVRegFloat(inst->VRegB_23x()),
+ shadow_frame.GetVRegFloat(inst->VRegC_23x())));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void ADD_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVRegDouble(inst->VRegB_23x()) +
+ shadow_frame.GetVRegDouble(inst->VRegC_23x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void SUB_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVRegDouble(inst->VRegB_23x()) -
+ shadow_frame.GetVRegDouble(inst->VRegC_23x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void MUL_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVRegDouble(inst->VRegB_23x()) *
+ shadow_frame.GetVRegDouble(inst->VRegC_23x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void DIV_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
+ shadow_frame.GetVRegDouble(inst->VRegB_23x()) /
+ shadow_frame.GetVRegDouble(inst->VRegC_23x()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void REM_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
+ fmod(shadow_frame.GetVRegDouble(inst->VRegB_23x()),
+ shadow_frame.GetVRegDouble(inst->VRegC_23x())));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void ADD_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVReg(vregA, SafeAdd(shadow_frame.GetVReg(vregA),
+ shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void SUB_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVReg(vregA,
+ SafeSub(shadow_frame.GetVReg(vregA),
+ shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void MUL_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVReg(vregA,
+ SafeMul(shadow_frame.GetVReg(vregA),
+ shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void DIV_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ bool success = DoIntDivide(shadow_frame, vregA, shadow_frame.GetVReg(vregA),
+ shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_1xx);
+ }
+
+ ALWAYS_INLINE void REM_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ bool success = DoIntRemainder(shadow_frame, vregA, shadow_frame.GetVReg(vregA),
+ shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_1xx);
+ }
+
+ ALWAYS_INLINE void SHL_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVReg(vregA,
+ shadow_frame.GetVReg(vregA) <<
+ (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x1f));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void SHR_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVReg(vregA,
+ shadow_frame.GetVReg(vregA) >>
+ (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x1f));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void USHR_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVReg(vregA,
+ static_cast<uint32_t>(shadow_frame.GetVReg(vregA)) >>
+ (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x1f));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void AND_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVReg(vregA,
+ shadow_frame.GetVReg(vregA) &
+ shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void OR_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVReg(vregA,
+ shadow_frame.GetVReg(vregA) |
+ shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void XOR_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVReg(vregA,
+ shadow_frame.GetVReg(vregA) ^
+ shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void ADD_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegLong(vregA,
+ SafeAdd(shadow_frame.GetVRegLong(vregA),
+ shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void SUB_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegLong(vregA,
+ SafeSub(shadow_frame.GetVRegLong(vregA),
+ shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void MUL_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegLong(vregA,
+ SafeMul(shadow_frame.GetVRegLong(vregA),
+ shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void DIV_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ DoLongDivide(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
+ shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx);
+ }
+
+ ALWAYS_INLINE void REM_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ DoLongRemainder(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
+ shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx);
+ }
+
+ ALWAYS_INLINE void AND_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegLong(vregA,
+ shadow_frame.GetVRegLong(vregA) &
+ shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void OR_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegLong(vregA,
+ shadow_frame.GetVRegLong(vregA) |
+ shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void XOR_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegLong(vregA,
+ shadow_frame.GetVRegLong(vregA) ^
+ shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void SHL_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegLong(vregA,
+ shadow_frame.GetVRegLong(vregA) <<
+ (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x3f));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void SHR_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegLong(vregA,
+ shadow_frame.GetVRegLong(vregA) >>
+ (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x3f));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void USHR_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegLong(vregA,
+ static_cast<uint64_t>(shadow_frame.GetVRegLong(vregA)) >>
+ (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x3f));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void ADD_FLOAT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegFloat(vregA,
+ shadow_frame.GetVRegFloat(vregA) +
+ shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void SUB_FLOAT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegFloat(vregA,
+ shadow_frame.GetVRegFloat(vregA) -
+ shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void MUL_FLOAT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegFloat(vregA,
+ shadow_frame.GetVRegFloat(vregA) *
+ shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void DIV_FLOAT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegFloat(vregA,
+ shadow_frame.GetVRegFloat(vregA) /
+ shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void REM_FLOAT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegFloat(vregA,
+ fmodf(shadow_frame.GetVRegFloat(vregA),
+ shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data))));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void ADD_DOUBLE_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegDouble(vregA,
+ shadow_frame.GetVRegDouble(vregA) +
+ shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void SUB_DOUBLE_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegDouble(vregA,
+ shadow_frame.GetVRegDouble(vregA) -
+ shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void MUL_DOUBLE_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegDouble(vregA,
+ shadow_frame.GetVRegDouble(vregA) *
+ shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void DIV_DOUBLE_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegDouble(vregA,
+ shadow_frame.GetVRegDouble(vregA) /
+ shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void REM_DOUBLE_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ uint4_t vregA = inst->VRegA_12x(inst_data);
+ shadow_frame.SetVRegDouble(vregA,
+ fmod(shadow_frame.GetVRegDouble(vregA),
+ shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data))));
+ inst = inst->Next_1xx();
+ }
+
+ ALWAYS_INLINE void ADD_INT_LIT16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
+ SafeAdd(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
+ inst->VRegC_22s()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void RSUB_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
+ SafeSub(inst->VRegC_22s(),
+ shadow_frame.GetVReg(inst->VRegB_22s(inst_data))));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void MUL_INT_LIT16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
+ SafeMul(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
+ inst->VRegC_22s()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void DIV_INT_LIT16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIntDivide(shadow_frame, inst->VRegA_22s(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
+ inst->VRegC_22s());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void REM_INT_LIT16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIntRemainder(shadow_frame, inst->VRegA_22s(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
+ inst->VRegC_22s());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void AND_INT_LIT16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) &
+ inst->VRegC_22s());
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void OR_INT_LIT16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) |
+ inst->VRegC_22s());
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void XOR_INT_LIT16() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) ^
+ inst->VRegC_22s());
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void ADD_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+ SafeAdd(shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void RSUB_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+ SafeSub(inst->VRegC_22b(), shadow_frame.GetVReg(inst->VRegB_22b())));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void MUL_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+ SafeMul(shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b()));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void DIV_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIntDivide(shadow_frame, inst->VRegA_22b(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void REM_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ bool success = DoIntRemainder(shadow_frame, inst->VRegA_22b(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b());
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+ }
+
+ ALWAYS_INLINE void AND_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_22b()) &
+ inst->VRegC_22b());
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void OR_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_22b()) |
+ inst->VRegC_22b());
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void XOR_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_22b()) ^
+ inst->VRegC_22b());
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void SHL_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_22b()) <<
+ (inst->VRegC_22b() & 0x1f));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void SHR_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+ shadow_frame.GetVReg(inst->VRegB_22b()) >>
+ (inst->VRegC_22b() & 0x1f));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void USHR_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+ PREAMBLE();
+ shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+ static_cast<uint32_t>(shadow_frame.GetVReg(inst->VRegB_22b())) >>
+ (inst->VRegC_22b() & 0x1f));
+ inst = inst->Next_2xx();
+ }
+
+ ALWAYS_INLINE void UNUSED_3E() REQUIRES_SHARED(Locks::mutator_lock_) {
+ UnexpectedOpcode(inst, shadow_frame);
+ }
+
+ ALWAYS_INLINE void UNUSED_3F() REQUIRES_SHARED(Locks::mutator_lock_) {
+ UnexpectedOpcode(inst, shadow_frame);
+ }
+
+ ALWAYS_INLINE void UNUSED_40() REQUIRES_SHARED(Locks::mutator_lock_) {
+ UnexpectedOpcode(inst, shadow_frame);
+ }
+
+ ALWAYS_INLINE void UNUSED_41() REQUIRES_SHARED(Locks::mutator_lock_) {
+ UnexpectedOpcode(inst, shadow_frame);
+ }
+
+ ALWAYS_INLINE void UNUSED_42() REQUIRES_SHARED(Locks::mutator_lock_) {
+ UnexpectedOpcode(inst, shadow_frame);
+ }
+
+ ALWAYS_INLINE void UNUSED_43() REQUIRES_SHARED(Locks::mutator_lock_) {
+ UnexpectedOpcode(inst, shadow_frame);
+ }
+
+ ALWAYS_INLINE void UNUSED_79() REQUIRES_SHARED(Locks::mutator_lock_) {
+ UnexpectedOpcode(inst, shadow_frame);
+ }
+
+ ALWAYS_INLINE void UNUSED_7A() REQUIRES_SHARED(Locks::mutator_lock_) {
+ UnexpectedOpcode(inst, shadow_frame);
+ }
+
+ ALWAYS_INLINE void UNUSED_F3() REQUIRES_SHARED(Locks::mutator_lock_) {
+ UnexpectedOpcode(inst, shadow_frame);
+ }
+
+ ALWAYS_INLINE void UNUSED_F4() REQUIRES_SHARED(Locks::mutator_lock_) {
+ UnexpectedOpcode(inst, shadow_frame);
+ }
+
+ ALWAYS_INLINE void UNUSED_F5() REQUIRES_SHARED(Locks::mutator_lock_) {
+ UnexpectedOpcode(inst, shadow_frame);
+ }
+
+ ALWAYS_INLINE void UNUSED_F6() REQUIRES_SHARED(Locks::mutator_lock_) {
+ UnexpectedOpcode(inst, shadow_frame);
+ }
+
+ ALWAYS_INLINE void UNUSED_F7() REQUIRES_SHARED(Locks::mutator_lock_) {
+ UnexpectedOpcode(inst, shadow_frame);
+ }
+
+ ALWAYS_INLINE void UNUSED_F8() REQUIRES_SHARED(Locks::mutator_lock_) {
+ UnexpectedOpcode(inst, shadow_frame);
+ }
+
+ ALWAYS_INLINE void UNUSED_F9() REQUIRES_SHARED(Locks::mutator_lock_) {
+ UnexpectedOpcode(inst, shadow_frame);
+ }
+
+ ALWAYS_INLINE InstructionHandler(SwitchImplContext* ctx,
+ const instrumentation::Instrumentation* instrumentation,
+ Thread* self,
+ ShadowFrame& shadow_frame,
+ uint16_t dex_pc,
+ const Instruction*& inst,
+ uint16_t inst_data,
+ bool& exit_interpreter_loop)
+ : ctx(ctx),
+ instrumentation(instrumentation),
+ self(self),
+ shadow_frame(shadow_frame),
+ dex_pc(dex_pc),
+ inst(inst),
+ inst_data(inst_data),
+ exit_interpreter_loop(exit_interpreter_loop) {
+ }
+
+ private:
+ static constexpr bool do_assignability_check = do_access_check;
+
+ const CodeItemDataAccessor& Accessor() { return ctx->accessor; }
+ const uint16_t* Insns() { return ctx->accessor.Insns(); }
+ JValue* ResultRegister() { return &ctx->result_register; }
+
+ SwitchImplContext* const ctx;
+ const instrumentation::Instrumentation* const instrumentation;
+ Thread* const self;
+ ShadowFrame& shadow_frame;
+ uint32_t const dex_pc;
+ const Instruction*& inst;
+ uint16_t const inst_data;
+ bool& exit_interpreter_loop;
+};
+
+#undef HANDLE_BACKWARD_BRANCH
+#undef HANDLE_ASYNC_EXCEPTION
+#undef HOTNESS_UPDATE
+#undef BRANCH_INSTRUMENTATION
+#undef PREAMBLE
+#undef PREAMBLE_SAVE
+#undef HANDLE_MONITOR_CHECKS
+#undef POSSIBLY_HANDLE_PENDING_EXCEPTION
+#undef POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE
+#undef POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC
+#undef POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL
+#undef HANDLE_PENDING_EXCEPTION
+#undef HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION
+#undef CHECK_FORCE_RETURN
+
// TODO On ASAN builds this function gets a huge stack frame. Since normally we run in the mterp
// this shouldn't cause any problems for stack overflow detection. Remove this once b/117341496 is
// fixed.
@@ -276,9 +2735,6 @@
Thread* self = ctx->self;
const CodeItemDataAccessor& accessor = ctx->accessor;
ShadowFrame& shadow_frame = ctx->shadow_frame;
- JValue result_register = ctx->result_register;
- bool interpret_one_instruction = ctx->interpret_one_instruction;
- constexpr bool do_assignability_check = do_access_check;
if (UNLIKELY(!shadow_frame.HasReferenceArray())) {
LOG(FATAL) << "Invalid shadow frame for interpreter use";
ctx->result = JValue();
@@ -291,2295 +2747,40 @@
const uint16_t* const insns = accessor.Insns();
const Instruction* inst = Instruction::At(insns + dex_pc);
uint16_t inst_data;
- jit::Jit* jit = Runtime::Current()->GetJit();
DCHECK(!shadow_frame.GetForceRetryInstruction())
<< "Entered interpreter from invoke without retry instruction being handled!";
- do {
+ bool const interpret_one_instruction = ctx->interpret_one_instruction;
+ while (true) {
dex_pc = inst->GetDexPc(insns);
shadow_frame.SetDexPC(dex_pc);
TraceExecution(shadow_frame, inst, dex_pc);
inst_data = inst->Fetch16(0);
switch (inst->Opcode(inst_data)) {
- case Instruction::NOP:
- PREAMBLE();
- inst = inst->Next_1xx();
- break;
- case Instruction::MOVE:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_12x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::MOVE_FROM16:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_22x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::MOVE_16:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_32x(),
- shadow_frame.GetVReg(inst->VRegB_32x()));
- inst = inst->Next_3xx();
- break;
- case Instruction::MOVE_WIDE:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::MOVE_WIDE_FROM16:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_22x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_22x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::MOVE_WIDE_16:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_32x(),
- shadow_frame.GetVRegLong(inst->VRegB_32x()));
- inst = inst->Next_3xx();
- break;
- case Instruction::MOVE_OBJECT:
- PREAMBLE();
- shadow_frame.SetVRegReference(inst->VRegA_12x(inst_data),
- shadow_frame.GetVRegReference(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::MOVE_OBJECT_FROM16:
- PREAMBLE();
- shadow_frame.SetVRegReference(inst->VRegA_22x(inst_data),
- shadow_frame.GetVRegReference(inst->VRegB_22x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::MOVE_OBJECT_16:
- PREAMBLE();
- shadow_frame.SetVRegReference(inst->VRegA_32x(),
- shadow_frame.GetVRegReference(inst->VRegB_32x()));
- inst = inst->Next_3xx();
- break;
- case Instruction::MOVE_RESULT:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_11x(inst_data), result_register.GetI());
- inst = inst->Next_1xx();
- break;
- case Instruction::MOVE_RESULT_WIDE:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_11x(inst_data), result_register.GetJ());
- inst = inst->Next_1xx();
- break;
- case Instruction::MOVE_RESULT_OBJECT:
- PREAMBLE_SAVE(&result_register);
- shadow_frame.SetVRegReference(inst->VRegA_11x(inst_data), result_register.GetL());
- inst = inst->Next_1xx();
- break;
- case Instruction::MOVE_EXCEPTION: {
- PREAMBLE();
- ObjPtr<mirror::Throwable> exception = self->GetException();
- DCHECK(exception != nullptr) << "No pending exception on MOVE_EXCEPTION instruction";
- shadow_frame.SetVRegReference(inst->VRegA_11x(inst_data), exception);
- self->ClearException();
- inst = inst->Next_1xx();
- break;
+#define OPCODE_CASE(OPCODE, OPCODE_NAME, pname, f, i, a, e, v) \
+ case OPCODE: { \
+ bool exit_loop = false; \
+ InstructionHandler<do_access_check, transaction_active> handler( \
+ ctx, instrumentation, self, shadow_frame, dex_pc, inst, inst_data, exit_loop); \
+ /* TODO: Call PREAMBLE here, instead of explicitly in each handler */ \
+ handler.OPCODE_NAME(); \
+ /* TODO: Advance 'inst' here, instead of explicitly in each handler */ \
+ if (UNLIKELY(exit_loop)) { \
+ return; \
+ } \
+ break; \
}
- case Instruction::RETURN_VOID_NO_BARRIER: {
- PREAMBLE();
- JValue result;
- self->AllowThreadSuspension();
- HANDLE_MONITOR_CHECKS();
- if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
- !SendMethodExitEvents(self,
- instrumentation,
- shadow_frame,
- shadow_frame.GetThisObject(accessor.InsSize()),
- shadow_frame.GetMethod(),
- inst->GetDexPc(insns),
- result))) {
- HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
- }
- if (interpret_one_instruction) {
- /* Signal mterp to return to caller */
- shadow_frame.SetDexPC(dex::kDexNoIndex);
- }
- ctx->result = result;
- return;
- }
- case Instruction::RETURN_VOID: {
- PREAMBLE();
- QuasiAtomic::ThreadFenceForConstructor();
- JValue result;
- self->AllowThreadSuspension();
- HANDLE_MONITOR_CHECKS();
- if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
- !SendMethodExitEvents(self,
- instrumentation,
- shadow_frame,
- shadow_frame.GetThisObject(accessor.InsSize()),
- shadow_frame.GetMethod(),
- inst->GetDexPc(insns),
- result))) {
- HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
- }
- if (interpret_one_instruction) {
- /* Signal mterp to return to caller */
- shadow_frame.SetDexPC(dex::kDexNoIndex);
- }
- ctx->result = result;
- return;
- }
- case Instruction::RETURN: {
- PREAMBLE();
- JValue result;
- result.SetJ(0);
- result.SetI(shadow_frame.GetVReg(inst->VRegA_11x(inst_data)));
- self->AllowThreadSuspension();
- HANDLE_MONITOR_CHECKS();
- if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
- !SendMethodExitEvents(self,
- instrumentation,
- shadow_frame,
- shadow_frame.GetThisObject(accessor.InsSize()),
- shadow_frame.GetMethod(),
- inst->GetDexPc(insns),
- result))) {
- HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
- }
- if (interpret_one_instruction) {
- /* Signal mterp to return to caller */
- shadow_frame.SetDexPC(dex::kDexNoIndex);
- }
- ctx->result = result;
- return;
- }
- case Instruction::RETURN_WIDE: {
- PREAMBLE();
- JValue result;
- result.SetJ(shadow_frame.GetVRegLong(inst->VRegA_11x(inst_data)));
- self->AllowThreadSuspension();
- HANDLE_MONITOR_CHECKS();
- if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
- !SendMethodExitEvents(self,
- instrumentation,
- shadow_frame,
- shadow_frame.GetThisObject(accessor.InsSize()),
- shadow_frame.GetMethod(),
- inst->GetDexPc(insns),
- result))) {
- HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
- }
- if (interpret_one_instruction) {
- /* Signal mterp to return to caller */
- shadow_frame.SetDexPC(dex::kDexNoIndex);
- }
- ctx->result = result;
- return;
- }
- case Instruction::RETURN_OBJECT: {
- PREAMBLE();
- JValue result;
- self->AllowThreadSuspension();
- HANDLE_MONITOR_CHECKS();
- const size_t ref_idx = inst->VRegA_11x(inst_data);
- ObjPtr<mirror::Object> obj_result = shadow_frame.GetVRegReference(ref_idx);
- if (do_assignability_check && obj_result != nullptr) {
- ObjPtr<mirror::Class> return_type = shadow_frame.GetMethod()->ResolveReturnType();
- // Re-load since it might have moved.
- obj_result = shadow_frame.GetVRegReference(ref_idx);
- if (return_type == nullptr) {
- // Return the pending exception.
- HANDLE_PENDING_EXCEPTION();
- }
- if (!obj_result->VerifierInstanceOf(return_type)) {
- // This should never happen.
- std::string temp1, temp2;
- self->ThrowNewExceptionF("Ljava/lang/InternalError;",
- "Returning '%s' that is not instance of return type '%s'",
- obj_result->GetClass()->GetDescriptor(&temp1),
- return_type->GetDescriptor(&temp2));
- HANDLE_PENDING_EXCEPTION();
- }
- }
- result.SetL(obj_result);
- if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
- !SendMethodExitEvents(self,
- instrumentation,
- shadow_frame,
- shadow_frame.GetThisObject(accessor.InsSize()),
- shadow_frame.GetMethod(),
- inst->GetDexPc(insns),
- result))) {
- HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
- }
- // Re-load since it might have moved during the MethodExitEvent.
- result.SetL(shadow_frame.GetVRegReference(ref_idx));
- if (interpret_one_instruction) {
- /* Signal mterp to return to caller */
- shadow_frame.SetDexPC(dex::kDexNoIndex);
- }
- ctx->result = result;
- return;
- }
- case Instruction::CONST_4: {
- PREAMBLE();
- uint4_t dst = inst->VRegA_11n(inst_data);
- int4_t val = inst->VRegB_11n(inst_data);
- shadow_frame.SetVReg(dst, val);
- if (val == 0) {
- shadow_frame.SetVRegReference(dst, nullptr);
- }
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::CONST_16: {
- PREAMBLE();
- uint8_t dst = inst->VRegA_21s(inst_data);
- int16_t val = inst->VRegB_21s();
- shadow_frame.SetVReg(dst, val);
- if (val == 0) {
- shadow_frame.SetVRegReference(dst, nullptr);
- }
- inst = inst->Next_2xx();
- break;
- }
- case Instruction::CONST: {
- PREAMBLE();
- uint8_t dst = inst->VRegA_31i(inst_data);
- int32_t val = inst->VRegB_31i();
- shadow_frame.SetVReg(dst, val);
- if (val == 0) {
- shadow_frame.SetVRegReference(dst, nullptr);
- }
- inst = inst->Next_3xx();
- break;
- }
- case Instruction::CONST_HIGH16: {
- PREAMBLE();
- uint8_t dst = inst->VRegA_21h(inst_data);
- int32_t val = static_cast<int32_t>(inst->VRegB_21h() << 16);
- shadow_frame.SetVReg(dst, val);
- if (val == 0) {
- shadow_frame.SetVRegReference(dst, nullptr);
- }
- inst = inst->Next_2xx();
- break;
- }
- case Instruction::CONST_WIDE_16:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_21s(inst_data), inst->VRegB_21s());
- inst = inst->Next_2xx();
- break;
- case Instruction::CONST_WIDE_32:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_31i(inst_data), inst->VRegB_31i());
- inst = inst->Next_3xx();
- break;
- case Instruction::CONST_WIDE:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_51l(inst_data), inst->VRegB_51l());
- inst = inst->Next_51l();
- break;
- case Instruction::CONST_WIDE_HIGH16:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_21h(inst_data),
- static_cast<uint64_t>(inst->VRegB_21h()) << 48);
- inst = inst->Next_2xx();
- break;
- case Instruction::CONST_STRING: {
- PREAMBLE();
- ObjPtr<mirror::String> s = ResolveString(self,
- shadow_frame,
- dex::StringIndex(inst->VRegB_21c()));
- if (UNLIKELY(s == nullptr)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), s);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::CONST_STRING_JUMBO: {
- PREAMBLE();
- ObjPtr<mirror::String> s = ResolveString(self,
- shadow_frame,
- dex::StringIndex(inst->VRegB_31c()));
- if (UNLIKELY(s == nullptr)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- shadow_frame.SetVRegReference(inst->VRegA_31c(inst_data), s);
- inst = inst->Next_3xx();
- }
- break;
- }
- case Instruction::CONST_CLASS: {
- PREAMBLE();
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
- shadow_frame.GetMethod(),
- self,
- false,
- do_access_check);
- if (UNLIKELY(c == nullptr)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), c);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::CONST_METHOD_HANDLE: {
- PREAMBLE();
- ClassLinker* cl = Runtime::Current()->GetClassLinker();
- ObjPtr<mirror::MethodHandle> mh = cl->ResolveMethodHandle(self,
- inst->VRegB_21c(),
- shadow_frame.GetMethod());
- if (UNLIKELY(mh == nullptr)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), mh);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::CONST_METHOD_TYPE: {
- PREAMBLE();
- ClassLinker* cl = Runtime::Current()->GetClassLinker();
- ObjPtr<mirror::MethodType> mt = cl->ResolveMethodType(self,
- dex::ProtoIndex(inst->VRegB_21c()),
- shadow_frame.GetMethod());
- if (UNLIKELY(mt == nullptr)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), mt);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::MONITOR_ENTER: {
- PREAMBLE();
- HANDLE_ASYNC_EXCEPTION();
- ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
- if (UNLIKELY(obj == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- DoMonitorEnter<do_assignability_check>(self, &shadow_frame, obj);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx);
- }
- break;
- }
- case Instruction::MONITOR_EXIT: {
- PREAMBLE();
- HANDLE_ASYNC_EXCEPTION();
- ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
- if (UNLIKELY(obj == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- DoMonitorExit<do_assignability_check>(self, &shadow_frame, obj);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx);
- }
- break;
- }
- case Instruction::CHECK_CAST: {
- PREAMBLE();
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
- shadow_frame.GetMethod(),
- self,
- false,
- do_access_check);
- if (UNLIKELY(c == nullptr)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegA_21c(inst_data));
- if (UNLIKELY(obj != nullptr && !obj->InstanceOf(c))) {
- ThrowClassCastException(c, obj->GetClass());
- HANDLE_PENDING_EXCEPTION();
- } else {
- inst = inst->Next_2xx();
- }
- }
- break;
- }
- case Instruction::INSTANCE_OF: {
- PREAMBLE();
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegC_22c()),
- shadow_frame.GetMethod(),
- self,
- false,
- do_access_check);
- if (UNLIKELY(c == nullptr)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
- shadow_frame.SetVReg(inst->VRegA_22c(inst_data),
- (obj != nullptr && obj->InstanceOf(c)) ? 1 : 0);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::ARRAY_LENGTH: {
- PREAMBLE();
- ObjPtr<mirror::Object> array = shadow_frame.GetVRegReference(inst->VRegB_12x(inst_data));
- if (UNLIKELY(array == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- } else {
- shadow_frame.SetVReg(inst->VRegA_12x(inst_data), array->AsArray()->GetLength());
- inst = inst->Next_1xx();
- }
- break;
- }
- case Instruction::NEW_INSTANCE: {
- PREAMBLE();
- ObjPtr<mirror::Object> obj = nullptr;
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
- shadow_frame.GetMethod(),
- self,
- false,
- do_access_check);
- if (LIKELY(c != nullptr)) {
- if (UNLIKELY(c->IsStringClass())) {
- gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
- obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
- } else {
- obj = AllocObjectFromCode<true>(
- c.Ptr(),
- self,
- Runtime::Current()->GetHeap()->GetCurrentAllocator());
- }
- }
- if (UNLIKELY(obj == nullptr)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- obj->GetClass()->AssertInitializedOrInitializingInThread(self);
- // Don't allow finalizable objects to be allocated during a transaction since these can't
- // be finalized without a started runtime.
- if (transaction_active && obj->GetClass()->IsFinalizable()) {
- AbortTransactionF(self, "Allocating finalizable object in transaction: %s",
- obj->PrettyTypeOf().c_str());
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), obj);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::NEW_ARRAY: {
- PREAMBLE();
- int32_t length = shadow_frame.GetVReg(inst->VRegB_22c(inst_data));
- ObjPtr<mirror::Object> obj = AllocArrayFromCode<do_access_check, true>(
- dex::TypeIndex(inst->VRegC_22c()),
- length,
- shadow_frame.GetMethod(),
- self,
- Runtime::Current()->GetHeap()->GetCurrentAllocator());
- if (UNLIKELY(obj == nullptr)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- shadow_frame.SetVRegReference(inst->VRegA_22c(inst_data), obj);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::FILLED_NEW_ARRAY: {
- PREAMBLE();
- bool success =
- DoFilledNewArray<false, do_access_check, transaction_active>(inst, shadow_frame, self,
- &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
- break;
- }
- case Instruction::FILLED_NEW_ARRAY_RANGE: {
- PREAMBLE();
- bool success =
- DoFilledNewArray<true, do_access_check, transaction_active>(inst, shadow_frame,
- self, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
- break;
- }
- case Instruction::FILL_ARRAY_DATA: {
- PREAMBLE();
- const uint16_t* payload_addr = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
- const Instruction::ArrayDataPayload* payload =
- reinterpret_cast<const Instruction::ArrayDataPayload*>(payload_addr);
- ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegA_31t(inst_data));
- bool success = FillArrayData(obj, payload);
- if (!success) {
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- if (transaction_active) {
- RecordArrayElementsInTransaction(obj->AsArray(), payload->element_count);
- }
- inst = inst->Next_3xx();
- break;
- }
- case Instruction::THROW: {
- PREAMBLE();
- HANDLE_ASYNC_EXCEPTION();
- ObjPtr<mirror::Object> exception =
- shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
- if (UNLIKELY(exception == nullptr)) {
- ThrowNullPointerException("throw with null exception");
- } else if (do_assignability_check && !exception->GetClass()->IsThrowableClass()) {
- // This should never happen.
- std::string temp;
- self->ThrowNewExceptionF("Ljava/lang/InternalError;",
- "Throwing '%s' that is not instance of Throwable",
- exception->GetClass()->GetDescriptor(&temp));
- } else {
- self->SetException(exception->AsThrowable());
- }
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- case Instruction::GOTO: {
- PREAMBLE();
- HANDLE_ASYNC_EXCEPTION();
- int8_t offset = inst->VRegA_10t(inst_data);
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- break;
- }
- case Instruction::GOTO_16: {
- PREAMBLE();
- HANDLE_ASYNC_EXCEPTION();
- int16_t offset = inst->VRegA_20t();
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- break;
- }
- case Instruction::GOTO_32: {
- PREAMBLE();
- HANDLE_ASYNC_EXCEPTION();
- int32_t offset = inst->VRegA_30t();
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- break;
- }
- case Instruction::PACKED_SWITCH: {
- PREAMBLE();
- int32_t offset = DoPackedSwitch(inst, shadow_frame, inst_data);
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- break;
- }
- case Instruction::SPARSE_SWITCH: {
- PREAMBLE();
- int32_t offset = DoSparseSwitch(inst, shadow_frame, inst_data);
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- break;
- }
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wfloat-equal"
-
- case Instruction::CMPL_FLOAT: {
- PREAMBLE();
- float val1 = shadow_frame.GetVRegFloat(inst->VRegB_23x());
- float val2 = shadow_frame.GetVRegFloat(inst->VRegC_23x());
- int32_t result;
- if (val1 > val2) {
- result = 1;
- } else if (val1 == val2) {
- result = 0;
- } else {
- result = -1;
- }
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
- inst = inst->Next_2xx();
- break;
- }
- case Instruction::CMPG_FLOAT: {
- PREAMBLE();
- float val1 = shadow_frame.GetVRegFloat(inst->VRegB_23x());
- float val2 = shadow_frame.GetVRegFloat(inst->VRegC_23x());
- int32_t result;
- if (val1 < val2) {
- result = -1;
- } else if (val1 == val2) {
- result = 0;
- } else {
- result = 1;
- }
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
- inst = inst->Next_2xx();
- break;
- }
- case Instruction::CMPL_DOUBLE: {
- PREAMBLE();
- double val1 = shadow_frame.GetVRegDouble(inst->VRegB_23x());
- double val2 = shadow_frame.GetVRegDouble(inst->VRegC_23x());
- int32_t result;
- if (val1 > val2) {
- result = 1;
- } else if (val1 == val2) {
- result = 0;
- } else {
- result = -1;
- }
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
- inst = inst->Next_2xx();
- break;
- }
-
- case Instruction::CMPG_DOUBLE: {
- PREAMBLE();
- double val1 = shadow_frame.GetVRegDouble(inst->VRegB_23x());
- double val2 = shadow_frame.GetVRegDouble(inst->VRegC_23x());
- int32_t result;
- if (val1 < val2) {
- result = -1;
- } else if (val1 == val2) {
- result = 0;
- } else {
- result = 1;
- }
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
- inst = inst->Next_2xx();
- break;
- }
-
-#pragma clang diagnostic pop
-
- case Instruction::CMP_LONG: {
- PREAMBLE();
- int64_t val1 = shadow_frame.GetVRegLong(inst->VRegB_23x());
- int64_t val2 = shadow_frame.GetVRegLong(inst->VRegC_23x());
- int32_t result;
- if (val1 > val2) {
- result = 1;
- } else if (val1 == val2) {
- result = 0;
- } else {
- result = -1;
- }
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
- inst = inst->Next_2xx();
- break;
- }
- case Instruction::IF_EQ: {
- PREAMBLE();
- if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) ==
- shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
- int16_t offset = inst->VRegC_22t();
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::IF_NE: {
- PREAMBLE();
- if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) !=
- shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
- int16_t offset = inst->VRegC_22t();
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::IF_LT: {
- PREAMBLE();
- if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) <
- shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
- int16_t offset = inst->VRegC_22t();
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::IF_GE: {
- PREAMBLE();
- if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) >=
- shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
- int16_t offset = inst->VRegC_22t();
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::IF_GT: {
- PREAMBLE();
- if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) >
- shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
- int16_t offset = inst->VRegC_22t();
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::IF_LE: {
- PREAMBLE();
- if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) <=
- shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
- int16_t offset = inst->VRegC_22t();
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::IF_EQZ: {
- PREAMBLE();
- if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) == 0) {
- int16_t offset = inst->VRegB_21t();
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::IF_NEZ: {
- PREAMBLE();
- if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) != 0) {
- int16_t offset = inst->VRegB_21t();
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::IF_LTZ: {
- PREAMBLE();
- if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) < 0) {
- int16_t offset = inst->VRegB_21t();
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::IF_GEZ: {
- PREAMBLE();
- if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) >= 0) {
- int16_t offset = inst->VRegB_21t();
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::IF_GTZ: {
- PREAMBLE();
- if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) > 0) {
- int16_t offset = inst->VRegB_21t();
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::IF_LEZ: {
- PREAMBLE();
- if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) <= 0) {
- int16_t offset = inst->VRegB_21t();
- BRANCH_INSTRUMENTATION(offset);
- inst = inst->RelativeAt(offset);
- HANDLE_BACKWARD_BRANCH(offset);
- } else {
- BRANCH_INSTRUMENTATION(2);
- inst = inst->Next_2xx();
- }
- break;
- }
- case Instruction::AGET_BOOLEAN: {
- PREAMBLE();
- ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- ObjPtr<mirror::BooleanArray> array = a->AsBooleanArray();
- if (array->CheckIsValidIndex(index)) {
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
- inst = inst->Next_2xx();
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- break;
- }
- case Instruction::AGET_BYTE: {
- PREAMBLE();
- ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- ObjPtr<mirror::ByteArray> array = a->AsByteArray();
- if (array->CheckIsValidIndex(index)) {
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
- inst = inst->Next_2xx();
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- break;
- }
- case Instruction::AGET_CHAR: {
- PREAMBLE();
- ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- ObjPtr<mirror::CharArray> array = a->AsCharArray();
- if (array->CheckIsValidIndex(index)) {
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
- inst = inst->Next_2xx();
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- break;
- }
- case Instruction::AGET_SHORT: {
- PREAMBLE();
- ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- ObjPtr<mirror::ShortArray> array = a->AsShortArray();
- if (array->CheckIsValidIndex(index)) {
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
- inst = inst->Next_2xx();
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- break;
- }
- case Instruction::AGET: {
- PREAMBLE();
- ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- DCHECK(a->IsIntArray() || a->IsFloatArray()) << a->PrettyTypeOf();
- ObjPtr<mirror::IntArray> array = ObjPtr<mirror::IntArray>::DownCast(a);
- if (array->CheckIsValidIndex(index)) {
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
- inst = inst->Next_2xx();
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- break;
- }
- case Instruction::AGET_WIDE: {
- PREAMBLE();
- ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- DCHECK(a->IsLongArray() || a->IsDoubleArray()) << a->PrettyTypeOf();
- ObjPtr<mirror::LongArray> array = ObjPtr<mirror::LongArray>::DownCast(a);
- if (array->CheckIsValidIndex(index)) {
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
- inst = inst->Next_2xx();
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- break;
- }
- case Instruction::AGET_OBJECT: {
- PREAMBLE();
- ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- ObjPtr<mirror::ObjectArray<mirror::Object>> array = a->AsObjectArray<mirror::Object>();
- if (array->CheckIsValidIndex(index)) {
- shadow_frame.SetVRegReference(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
- inst = inst->Next_2xx();
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- break;
- }
- case Instruction::APUT_BOOLEAN: {
- PREAMBLE();
- ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- uint8_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- ObjPtr<mirror::BooleanArray> array = a->AsBooleanArray();
- if (array->CheckIsValidIndex(index)) {
- array->SetWithoutChecks<transaction_active>(index, val);
- inst = inst->Next_2xx();
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- break;
- }
- case Instruction::APUT_BYTE: {
- PREAMBLE();
- ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- int8_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- ObjPtr<mirror::ByteArray> array = a->AsByteArray();
- if (array->CheckIsValidIndex(index)) {
- array->SetWithoutChecks<transaction_active>(index, val);
- inst = inst->Next_2xx();
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- break;
- }
- case Instruction::APUT_CHAR: {
- PREAMBLE();
- ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- uint16_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- ObjPtr<mirror::CharArray> array = a->AsCharArray();
- if (array->CheckIsValidIndex(index)) {
- array->SetWithoutChecks<transaction_active>(index, val);
- inst = inst->Next_2xx();
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- break;
- }
- case Instruction::APUT_SHORT: {
- PREAMBLE();
- ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- int16_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- ObjPtr<mirror::ShortArray> array = a->AsShortArray();
- if (array->CheckIsValidIndex(index)) {
- array->SetWithoutChecks<transaction_active>(index, val);
- inst = inst->Next_2xx();
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- break;
- }
- case Instruction::APUT: {
- PREAMBLE();
- ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- int32_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- DCHECK(a->IsIntArray() || a->IsFloatArray()) << a->PrettyTypeOf();
- ObjPtr<mirror::IntArray> array = ObjPtr<mirror::IntArray>::DownCast(a);
- if (array->CheckIsValidIndex(index)) {
- array->SetWithoutChecks<transaction_active>(index, val);
- inst = inst->Next_2xx();
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- break;
- }
- case Instruction::APUT_WIDE: {
- PREAMBLE();
- ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- int64_t val = shadow_frame.GetVRegLong(inst->VRegA_23x(inst_data));
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- DCHECK(a->IsLongArray() || a->IsDoubleArray()) << a->PrettyTypeOf();
- ObjPtr<mirror::LongArray> array = ObjPtr<mirror::LongArray>::DownCast(a);
- if (array->CheckIsValidIndex(index)) {
- array->SetWithoutChecks<transaction_active>(index, val);
- inst = inst->Next_2xx();
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- break;
- }
- case Instruction::APUT_OBJECT: {
- PREAMBLE();
- ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
- if (UNLIKELY(a == nullptr)) {
- ThrowNullPointerExceptionFromInterpreter();
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
- ObjPtr<mirror::Object> val = shadow_frame.GetVRegReference(inst->VRegA_23x(inst_data));
- ObjPtr<mirror::ObjectArray<mirror::Object>> array = a->AsObjectArray<mirror::Object>();
- if (array->CheckIsValidIndex(index) && array->CheckAssignable(val)) {
- array->SetWithoutChecks<transaction_active>(index, val);
- inst = inst->Next_2xx();
- } else {
- HANDLE_PENDING_EXCEPTION();
- }
- break;
- }
- case Instruction::IGET_BOOLEAN: {
- PREAMBLE();
- bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimBoolean, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IGET_BYTE: {
- PREAMBLE();
- bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimByte, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IGET_CHAR: {
- PREAMBLE();
- bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimChar, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IGET_SHORT: {
- PREAMBLE();
- bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimShort, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IGET: {
- PREAMBLE();
- bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimInt, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IGET_WIDE: {
- PREAMBLE();
- bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimLong, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IGET_OBJECT: {
- PREAMBLE();
- bool success = DoFieldGet<InstanceObjectRead, Primitive::kPrimNot, do_access_check>(
- self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IGET_QUICK: {
- PREAMBLE();
- bool success = DoIGetQuick<Primitive::kPrimInt>(shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IGET_WIDE_QUICK: {
- PREAMBLE();
- bool success = DoIGetQuick<Primitive::kPrimLong>(shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IGET_OBJECT_QUICK: {
- PREAMBLE();
- bool success = DoIGetQuick<Primitive::kPrimNot>(shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IGET_BOOLEAN_QUICK: {
- PREAMBLE();
- bool success = DoIGetQuick<Primitive::kPrimBoolean>(shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IGET_BYTE_QUICK: {
- PREAMBLE();
- bool success = DoIGetQuick<Primitive::kPrimByte>(shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IGET_CHAR_QUICK: {
- PREAMBLE();
- bool success = DoIGetQuick<Primitive::kPrimChar>(shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IGET_SHORT_QUICK: {
- PREAMBLE();
- bool success = DoIGetQuick<Primitive::kPrimShort>(shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::SGET_BOOLEAN: {
- PREAMBLE();
- bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::SGET_BYTE: {
- PREAMBLE();
- bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::SGET_CHAR: {
- PREAMBLE();
- bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::SGET_SHORT: {
- PREAMBLE();
- bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::SGET: {
- PREAMBLE();
- bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::SGET_WIDE: {
- PREAMBLE();
- bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::SGET_OBJECT: {
- PREAMBLE();
- bool success = DoFieldGet<StaticObjectRead, Primitive::kPrimNot, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IPUT_BOOLEAN: {
- PREAMBLE();
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IPUT_BYTE: {
- PREAMBLE();
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IPUT_CHAR: {
- PREAMBLE();
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IPUT_SHORT: {
- PREAMBLE();
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IPUT: {
- PREAMBLE();
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IPUT_WIDE: {
- PREAMBLE();
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IPUT_OBJECT: {
- PREAMBLE();
- bool success = DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IPUT_QUICK: {
- PREAMBLE();
- bool success = DoIPutQuick<Primitive::kPrimInt, transaction_active>(
- shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IPUT_BOOLEAN_QUICK: {
- PREAMBLE();
- bool success = DoIPutQuick<Primitive::kPrimBoolean, transaction_active>(
- shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IPUT_BYTE_QUICK: {
- PREAMBLE();
- bool success = DoIPutQuick<Primitive::kPrimByte, transaction_active>(
- shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IPUT_CHAR_QUICK: {
- PREAMBLE();
- bool success = DoIPutQuick<Primitive::kPrimChar, transaction_active>(
- shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IPUT_SHORT_QUICK: {
- PREAMBLE();
- bool success = DoIPutQuick<Primitive::kPrimShort, transaction_active>(
- shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IPUT_WIDE_QUICK: {
- PREAMBLE();
- bool success = DoIPutQuick<Primitive::kPrimLong, transaction_active>(
- shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::IPUT_OBJECT_QUICK: {
- PREAMBLE();
- bool success = DoIPutQuick<Primitive::kPrimNot, transaction_active>(
- shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::SPUT_BOOLEAN: {
- PREAMBLE();
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::SPUT_BYTE: {
- PREAMBLE();
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::SPUT_CHAR: {
- PREAMBLE();
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::SPUT_SHORT: {
- PREAMBLE();
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::SPUT: {
- PREAMBLE();
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::SPUT_WIDE: {
- PREAMBLE();
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::SPUT_OBJECT: {
- PREAMBLE();
- bool success = DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check,
- transaction_active>(self, shadow_frame, inst, inst_data);
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::INVOKE_VIRTUAL: {
- PREAMBLE();
- bool success = DoInvoke<kVirtual, false, do_access_check, /*is_mterp=*/ false>(
- self, shadow_frame, inst, inst_data, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
- break;
- }
- case Instruction::INVOKE_VIRTUAL_RANGE: {
- PREAMBLE();
- bool success = DoInvoke<kVirtual, true, do_access_check, /*is_mterp=*/ false>(
- self, shadow_frame, inst, inst_data, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
- break;
- }
- case Instruction::INVOKE_SUPER: {
- PREAMBLE();
- bool success = DoInvoke<kSuper, false, do_access_check, /*is_mterp=*/ false>(
- self, shadow_frame, inst, inst_data, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
- break;
- }
- case Instruction::INVOKE_SUPER_RANGE: {
- PREAMBLE();
- bool success = DoInvoke<kSuper, true, do_access_check, /*is_mterp=*/ false>(
- self, shadow_frame, inst, inst_data, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
- break;
- }
- case Instruction::INVOKE_DIRECT: {
- PREAMBLE();
- bool success = DoInvoke<kDirect, false, do_access_check, /*is_mterp=*/ false>(
- self, shadow_frame, inst, inst_data, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
- break;
- }
- case Instruction::INVOKE_DIRECT_RANGE: {
- PREAMBLE();
- bool success = DoInvoke<kDirect, true, do_access_check, /*is_mterp=*/ false>(
- self, shadow_frame, inst, inst_data, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
- break;
- }
- case Instruction::INVOKE_INTERFACE: {
- PREAMBLE();
- bool success = DoInvoke<kInterface, false, do_access_check, /*is_mterp=*/ false>(
- self, shadow_frame, inst, inst_data, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
- break;
- }
- case Instruction::INVOKE_INTERFACE_RANGE: {
- PREAMBLE();
- bool success = DoInvoke<kInterface, true, do_access_check, /*is_mterp=*/ false>(
- self, shadow_frame, inst, inst_data, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
- break;
- }
- case Instruction::INVOKE_STATIC: {
- PREAMBLE();
- bool success = DoInvoke<kStatic, false, do_access_check, /*is_mterp=*/ false>(
- self, shadow_frame, inst, inst_data, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
- break;
- }
- case Instruction::INVOKE_STATIC_RANGE: {
- PREAMBLE();
- bool success = DoInvoke<kStatic, true, do_access_check, /*is_mterp=*/ false>(
- self, shadow_frame, inst, inst_data, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
- break;
- }
- case Instruction::INVOKE_VIRTUAL_QUICK: {
- PREAMBLE();
- bool success = DoInvoke<kVirtual, false, do_access_check, /*is_mterp=*/ false,
- /*is_quick=*/ true>(self, shadow_frame, inst, inst_data, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
- break;
- }
- case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
- PREAMBLE();
- bool success = DoInvoke<kVirtual, true, do_access_check, /*is_mterp=*/ false,
- /*is_quick=*/ true>(self, shadow_frame, inst, inst_data, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
- break;
- }
- case Instruction::INVOKE_POLYMORPHIC: {
- PREAMBLE();
- DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
- bool success = DoInvokePolymorphic</* is_range= */ false>(
- self, shadow_frame, inst, inst_data, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(!success);
- break;
- }
- case Instruction::INVOKE_POLYMORPHIC_RANGE: {
- PREAMBLE();
- DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
- bool success = DoInvokePolymorphic</* is_range= */ true>(
- self, shadow_frame, inst, inst_data, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(!success);
- break;
- }
- case Instruction::INVOKE_CUSTOM: {
- PREAMBLE();
- DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
- bool success = DoInvokeCustom</* is_range= */ false>(
- self, shadow_frame, inst, inst_data, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
- break;
- }
- case Instruction::INVOKE_CUSTOM_RANGE: {
- PREAMBLE();
- DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
- bool success = DoInvokeCustom</* is_range= */ true>(
- self, shadow_frame, inst, inst_data, &result_register);
- POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
- break;
- }
- case Instruction::NEG_INT:
- PREAMBLE();
- shadow_frame.SetVReg(
- inst->VRegA_12x(inst_data), -shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::NOT_INT:
- PREAMBLE();
- shadow_frame.SetVReg(
- inst->VRegA_12x(inst_data), ~shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::NEG_LONG:
- PREAMBLE();
- shadow_frame.SetVRegLong(
- inst->VRegA_12x(inst_data), -shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::NOT_LONG:
- PREAMBLE();
- shadow_frame.SetVRegLong(
- inst->VRegA_12x(inst_data), ~shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::NEG_FLOAT:
- PREAMBLE();
- shadow_frame.SetVRegFloat(
- inst->VRegA_12x(inst_data), -shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::NEG_DOUBLE:
- PREAMBLE();
- shadow_frame.SetVRegDouble(
- inst->VRegA_12x(inst_data), -shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::INT_TO_LONG:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::INT_TO_FLOAT:
- PREAMBLE();
- shadow_frame.SetVRegFloat(inst->VRegA_12x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::INT_TO_DOUBLE:
- PREAMBLE();
- shadow_frame.SetVRegDouble(inst->VRegA_12x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::LONG_TO_INT:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_12x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::LONG_TO_FLOAT:
- PREAMBLE();
- shadow_frame.SetVRegFloat(inst->VRegA_12x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::LONG_TO_DOUBLE:
- PREAMBLE();
- shadow_frame.SetVRegDouble(inst->VRegA_12x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::FLOAT_TO_INT: {
- PREAMBLE();
- float val = shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data));
- int32_t result = art_float_to_integral<int32_t, float>(val);
- shadow_frame.SetVReg(inst->VRegA_12x(inst_data), result);
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::FLOAT_TO_LONG: {
- PREAMBLE();
- float val = shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data));
- int64_t result = art_float_to_integral<int64_t, float>(val);
- shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data), result);
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::FLOAT_TO_DOUBLE:
- PREAMBLE();
- shadow_frame.SetVRegDouble(inst->VRegA_12x(inst_data),
- shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::DOUBLE_TO_INT: {
- PREAMBLE();
- double val = shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data));
- int32_t result = art_float_to_integral<int32_t, double>(val);
- shadow_frame.SetVReg(inst->VRegA_12x(inst_data), result);
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::DOUBLE_TO_LONG: {
- PREAMBLE();
- double val = shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data));
- int64_t result = art_float_to_integral<int64_t, double>(val);
- shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data), result);
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::DOUBLE_TO_FLOAT:
- PREAMBLE();
- shadow_frame.SetVRegFloat(inst->VRegA_12x(inst_data),
- shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- case Instruction::INT_TO_BYTE:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_12x(inst_data), static_cast<int8_t>(
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
- inst = inst->Next_1xx();
- break;
- case Instruction::INT_TO_CHAR:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_12x(inst_data), static_cast<uint16_t>(
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
- inst = inst->Next_1xx();
- break;
- case Instruction::INT_TO_SHORT:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_12x(inst_data), static_cast<int16_t>(
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
- inst = inst->Next_1xx();
- break;
- case Instruction::ADD_INT: {
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- SafeAdd(shadow_frame.GetVReg(inst->VRegB_23x()),
- shadow_frame.GetVReg(inst->VRegC_23x())));
- inst = inst->Next_2xx();
- break;
- }
- case Instruction::SUB_INT:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- SafeSub(shadow_frame.GetVReg(inst->VRegB_23x()),
- shadow_frame.GetVReg(inst->VRegC_23x())));
- inst = inst->Next_2xx();
- break;
- case Instruction::MUL_INT:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- SafeMul(shadow_frame.GetVReg(inst->VRegB_23x()),
- shadow_frame.GetVReg(inst->VRegC_23x())));
- inst = inst->Next_2xx();
- break;
- case Instruction::DIV_INT: {
- PREAMBLE();
- bool success = DoIntDivide(shadow_frame, inst->VRegA_23x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_23x()),
- shadow_frame.GetVReg(inst->VRegC_23x()));
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::REM_INT: {
- PREAMBLE();
- bool success = DoIntRemainder(shadow_frame, inst->VRegA_23x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_23x()),
- shadow_frame.GetVReg(inst->VRegC_23x()));
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::SHL_INT:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_23x()) <<
- (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x1f));
- inst = inst->Next_2xx();
- break;
- case Instruction::SHR_INT:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_23x()) >>
- (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x1f));
- inst = inst->Next_2xx();
- break;
- case Instruction::USHR_INT:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- static_cast<uint32_t>(shadow_frame.GetVReg(inst->VRegB_23x())) >>
- (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x1f));
- inst = inst->Next_2xx();
- break;
- case Instruction::AND_INT:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_23x()) &
- shadow_frame.GetVReg(inst->VRegC_23x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::OR_INT:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_23x()) |
- shadow_frame.GetVReg(inst->VRegC_23x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::XOR_INT:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
- shadow_frame.GetVReg(inst->VRegB_23x()) ^
- shadow_frame.GetVReg(inst->VRegC_23x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::ADD_LONG:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- SafeAdd(shadow_frame.GetVRegLong(inst->VRegB_23x()),
- shadow_frame.GetVRegLong(inst->VRegC_23x())));
- inst = inst->Next_2xx();
- break;
- case Instruction::SUB_LONG:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- SafeSub(shadow_frame.GetVRegLong(inst->VRegB_23x()),
- shadow_frame.GetVRegLong(inst->VRegC_23x())));
- inst = inst->Next_2xx();
- break;
- case Instruction::MUL_LONG:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- SafeMul(shadow_frame.GetVRegLong(inst->VRegB_23x()),
- shadow_frame.GetVRegLong(inst->VRegC_23x())));
- inst = inst->Next_2xx();
- break;
- case Instruction::DIV_LONG:
- PREAMBLE();
- DoLongDivide(shadow_frame, inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_23x()),
- shadow_frame.GetVRegLong(inst->VRegC_23x()));
- POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_2xx);
- break;
- case Instruction::REM_LONG:
- PREAMBLE();
- DoLongRemainder(shadow_frame, inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_23x()),
- shadow_frame.GetVRegLong(inst->VRegC_23x()));
- POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_2xx);
- break;
- case Instruction::AND_LONG:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_23x()) &
- shadow_frame.GetVRegLong(inst->VRegC_23x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::OR_LONG:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_23x()) |
- shadow_frame.GetVRegLong(inst->VRegC_23x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::XOR_LONG:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_23x()) ^
- shadow_frame.GetVRegLong(inst->VRegC_23x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::SHL_LONG:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_23x()) <<
- (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x3f));
- inst = inst->Next_2xx();
- break;
- case Instruction::SHR_LONG:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegLong(inst->VRegB_23x()) >>
- (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x3f));
- inst = inst->Next_2xx();
- break;
- case Instruction::USHR_LONG:
- PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
- static_cast<uint64_t>(shadow_frame.GetVRegLong(inst->VRegB_23x())) >>
- (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x3f));
- inst = inst->Next_2xx();
- break;
- case Instruction::ADD_FLOAT:
- PREAMBLE();
- shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegFloat(inst->VRegB_23x()) +
- shadow_frame.GetVRegFloat(inst->VRegC_23x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::SUB_FLOAT:
- PREAMBLE();
- shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegFloat(inst->VRegB_23x()) -
- shadow_frame.GetVRegFloat(inst->VRegC_23x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::MUL_FLOAT:
- PREAMBLE();
- shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegFloat(inst->VRegB_23x()) *
- shadow_frame.GetVRegFloat(inst->VRegC_23x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::DIV_FLOAT:
- PREAMBLE();
- shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegFloat(inst->VRegB_23x()) /
- shadow_frame.GetVRegFloat(inst->VRegC_23x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::REM_FLOAT:
- PREAMBLE();
- shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
- fmodf(shadow_frame.GetVRegFloat(inst->VRegB_23x()),
- shadow_frame.GetVRegFloat(inst->VRegC_23x())));
- inst = inst->Next_2xx();
- break;
- case Instruction::ADD_DOUBLE:
- PREAMBLE();
- shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegDouble(inst->VRegB_23x()) +
- shadow_frame.GetVRegDouble(inst->VRegC_23x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::SUB_DOUBLE:
- PREAMBLE();
- shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegDouble(inst->VRegB_23x()) -
- shadow_frame.GetVRegDouble(inst->VRegC_23x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::MUL_DOUBLE:
- PREAMBLE();
- shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegDouble(inst->VRegB_23x()) *
- shadow_frame.GetVRegDouble(inst->VRegC_23x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::DIV_DOUBLE:
- PREAMBLE();
- shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
- shadow_frame.GetVRegDouble(inst->VRegB_23x()) /
- shadow_frame.GetVRegDouble(inst->VRegC_23x()));
- inst = inst->Next_2xx();
- break;
- case Instruction::REM_DOUBLE:
- PREAMBLE();
- shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
- fmod(shadow_frame.GetVRegDouble(inst->VRegB_23x()),
- shadow_frame.GetVRegDouble(inst->VRegC_23x())));
- inst = inst->Next_2xx();
- break;
- case Instruction::ADD_INT_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA, SafeAdd(shadow_frame.GetVReg(vregA),
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::SUB_INT_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- SafeSub(shadow_frame.GetVReg(vregA),
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::MUL_INT_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- SafeMul(shadow_frame.GetVReg(vregA),
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::DIV_INT_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- bool success = DoIntDivide(shadow_frame, vregA, shadow_frame.GetVReg(vregA),
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_1xx);
- break;
- }
- case Instruction::REM_INT_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- bool success = DoIntRemainder(shadow_frame, vregA, shadow_frame.GetVReg(vregA),
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_1xx);
- break;
- }
- case Instruction::SHL_INT_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- shadow_frame.GetVReg(vregA) <<
- (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x1f));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::SHR_INT_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- shadow_frame.GetVReg(vregA) >>
- (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x1f));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::USHR_INT_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- static_cast<uint32_t>(shadow_frame.GetVReg(vregA)) >>
- (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x1f));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::AND_INT_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- shadow_frame.GetVReg(vregA) &
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::OR_INT_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- shadow_frame.GetVReg(vregA) |
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::XOR_INT_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVReg(vregA,
- shadow_frame.GetVReg(vregA) ^
- shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::ADD_LONG_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- SafeAdd(shadow_frame.GetVRegLong(vregA),
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::SUB_LONG_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- SafeSub(shadow_frame.GetVRegLong(vregA),
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::MUL_LONG_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- SafeMul(shadow_frame.GetVRegLong(vregA),
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::DIV_LONG_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- DoLongDivide(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx);
- break;
- }
- case Instruction::REM_LONG_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- DoLongRemainder(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx);
- break;
- }
- case Instruction::AND_LONG_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- shadow_frame.GetVRegLong(vregA) &
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::OR_LONG_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- shadow_frame.GetVRegLong(vregA) |
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::XOR_LONG_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- shadow_frame.GetVRegLong(vregA) ^
- shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::SHL_LONG_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- shadow_frame.GetVRegLong(vregA) <<
- (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x3f));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::SHR_LONG_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- shadow_frame.GetVRegLong(vregA) >>
- (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x3f));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::USHR_LONG_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegLong(vregA,
- static_cast<uint64_t>(shadow_frame.GetVRegLong(vregA)) >>
- (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x3f));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::ADD_FLOAT_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegFloat(vregA,
- shadow_frame.GetVRegFloat(vregA) +
- shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::SUB_FLOAT_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegFloat(vregA,
- shadow_frame.GetVRegFloat(vregA) -
- shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::MUL_FLOAT_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegFloat(vregA,
- shadow_frame.GetVRegFloat(vregA) *
- shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::DIV_FLOAT_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegFloat(vregA,
- shadow_frame.GetVRegFloat(vregA) /
- shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::REM_FLOAT_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegFloat(vregA,
- fmodf(shadow_frame.GetVRegFloat(vregA),
- shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data))));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::ADD_DOUBLE_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegDouble(vregA,
- shadow_frame.GetVRegDouble(vregA) +
- shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::SUB_DOUBLE_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegDouble(vregA,
- shadow_frame.GetVRegDouble(vregA) -
- shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::MUL_DOUBLE_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegDouble(vregA,
- shadow_frame.GetVRegDouble(vregA) *
- shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::DIV_DOUBLE_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegDouble(vregA,
- shadow_frame.GetVRegDouble(vregA) /
- shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::REM_DOUBLE_2ADDR: {
- PREAMBLE();
- uint4_t vregA = inst->VRegA_12x(inst_data);
- shadow_frame.SetVRegDouble(vregA,
- fmod(shadow_frame.GetVRegDouble(vregA),
- shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data))));
- inst = inst->Next_1xx();
- break;
- }
- case Instruction::ADD_INT_LIT16:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
- SafeAdd(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
- inst->VRegC_22s()));
- inst = inst->Next_2xx();
- break;
- case Instruction::RSUB_INT_LIT16:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
- SafeSub(inst->VRegC_22s(),
- shadow_frame.GetVReg(inst->VRegB_22s(inst_data))));
- inst = inst->Next_2xx();
- break;
- case Instruction::MUL_INT_LIT16:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
- SafeMul(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
- inst->VRegC_22s()));
- inst = inst->Next_2xx();
- break;
- case Instruction::DIV_INT_LIT16: {
- PREAMBLE();
- bool success = DoIntDivide(shadow_frame, inst->VRegA_22s(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
- inst->VRegC_22s());
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::REM_INT_LIT16: {
- PREAMBLE();
- bool success = DoIntRemainder(shadow_frame, inst->VRegA_22s(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
- inst->VRegC_22s());
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::AND_INT_LIT16:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) &
- inst->VRegC_22s());
- inst = inst->Next_2xx();
- break;
- case Instruction::OR_INT_LIT16:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) |
- inst->VRegC_22s());
- inst = inst->Next_2xx();
- break;
- case Instruction::XOR_INT_LIT16:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) ^
- inst->VRegC_22s());
- inst = inst->Next_2xx();
- break;
- case Instruction::ADD_INT_LIT8:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- SafeAdd(shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b()));
- inst = inst->Next_2xx();
- break;
- case Instruction::RSUB_INT_LIT8:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- SafeSub(inst->VRegC_22b(), shadow_frame.GetVReg(inst->VRegB_22b())));
- inst = inst->Next_2xx();
- break;
- case Instruction::MUL_INT_LIT8:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- SafeMul(shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b()));
- inst = inst->Next_2xx();
- break;
- case Instruction::DIV_INT_LIT8: {
- PREAMBLE();
- bool success = DoIntDivide(shadow_frame, inst->VRegA_22b(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b());
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::REM_INT_LIT8: {
- PREAMBLE();
- bool success = DoIntRemainder(shadow_frame, inst->VRegA_22b(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b());
- POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
- break;
- }
- case Instruction::AND_INT_LIT8:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22b()) &
- inst->VRegC_22b());
- inst = inst->Next_2xx();
- break;
- case Instruction::OR_INT_LIT8:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22b()) |
- inst->VRegC_22b());
- inst = inst->Next_2xx();
- break;
- case Instruction::XOR_INT_LIT8:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22b()) ^
- inst->VRegC_22b());
- inst = inst->Next_2xx();
- break;
- case Instruction::SHL_INT_LIT8:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22b()) <<
- (inst->VRegC_22b() & 0x1f));
- inst = inst->Next_2xx();
- break;
- case Instruction::SHR_INT_LIT8:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- shadow_frame.GetVReg(inst->VRegB_22b()) >>
- (inst->VRegC_22b() & 0x1f));
- inst = inst->Next_2xx();
- break;
- case Instruction::USHR_INT_LIT8:
- PREAMBLE();
- shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
- static_cast<uint32_t>(shadow_frame.GetVReg(inst->VRegB_22b())) >>
- (inst->VRegC_22b() & 0x1f));
- inst = inst->Next_2xx();
- break;
- case Instruction::UNUSED_3E ... Instruction::UNUSED_43:
- case Instruction::UNUSED_79 ... Instruction::UNUSED_7A:
- case Instruction::UNUSED_F3 ... Instruction::UNUSED_F9:
- UnexpectedOpcode(inst, shadow_frame);
+DEX_INSTRUCTION_LIST(OPCODE_CASE)
+#undef OPCODE_CASE
}
- } while (!interpret_one_instruction);
- // Record where we stopped.
- shadow_frame.SetDexPC(inst->GetDexPc(insns));
- ctx->result = result_register;
- return;
+ if (UNLIKELY(interpret_one_instruction)) {
+ // Record where we stopped.
+ shadow_frame.SetDexPC(inst->GetDexPc(insns));
+ ctx->result = ctx->result_register;
+ return;
+ }
+ }
} // NOLINT(readability/fn_size)
} // namespace interpreter
diff --git a/runtime/intrinsics_list.h b/runtime/intrinsics_list.h
index 2f91f5d..093dd7f 100644
--- a/runtime/intrinsics_list.h
+++ b/runtime/intrinsics_list.h
@@ -219,6 +219,7 @@
V(VarHandleLoadLoadFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "loadLoadFence", "()V") \
V(VarHandleStoreStoreFence, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "storeStoreFence", "()V") \
V(ReachabilityFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/ref/Reference;", "reachabilityFence", "(Ljava/lang/Object;)V") \
+ V(CRC32Update, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/util/zip/CRC32;", "update", "(II)I") \
SIGNATURE_POLYMORPHIC_INTRINSICS_LIST(V)
#endif // ART_RUNTIME_INTRINSICS_LIST_H_
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index e021b77..a739c2d 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -31,8 +31,10 @@
#include "mirror/array.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
+#include "art_field-inl.h"
#include "native_util.h"
#include "scoped_fast_native_object_access-inl.h"
+#include "well_known_classes.h"
namespace art {
@@ -504,6 +506,33 @@
std::atomic_thread_fence(std::memory_order_seq_cst);
}
+static void Unsafe_park(JNIEnv* env, jobject, jboolean isAbsolute, jlong time) {
+ ScopedObjectAccess soa(env);
+ Thread::Current()->Park(isAbsolute, time);
+}
+
+static void Unsafe_unpark(JNIEnv* env, jobject, jobject jthread) {
+ art::ScopedFastNativeObjectAccess soa(env);
+ if (jthread == nullptr || !env->IsInstanceOf(jthread, WellKnownClasses::java_lang_Thread)) {
+ ThrowIllegalArgumentException("Argument to unpark() was not a Thread");
+ return;
+ }
+ art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
+ art::Thread* thread = art::Thread::FromManagedThread(soa, jthread);
+ if (thread != nullptr) {
+ thread->Unpark();
+ } else {
+ // If thread is null, that means that either the thread is not started yet,
+ // or the thread has already terminated. Setting the field to true will be
+ // respected when the thread does start, and is harmless if the thread has
+ // already terminated.
+ ArtField* unparked =
+ jni::DecodeArtField(WellKnownClasses::java_lang_Thread_unparkedBeforeStart);
+ // JNI must use non transactional mode.
+ unparked->SetBoolean<false>(soa.Decode<mirror::Object>(jthread), JNI_TRUE);
+ }
+}
+
static JNINativeMethod gMethods[] = {
FAST_NATIVE_METHOD(Unsafe, compareAndSwapInt, "(Ljava/lang/Object;JII)Z"),
FAST_NATIVE_METHOD(Unsafe, compareAndSwapLong, "(Ljava/lang/Object;JJJ)Z"),
@@ -546,6 +575,8 @@
FAST_NATIVE_METHOD(Unsafe, putShort, "(Ljava/lang/Object;JS)V"),
FAST_NATIVE_METHOD(Unsafe, putFloat, "(Ljava/lang/Object;JF)V"),
FAST_NATIVE_METHOD(Unsafe, putDouble, "(Ljava/lang/Object;JD)V"),
+ FAST_NATIVE_METHOD(Unsafe, unpark, "(Ljava/lang/Object;)V"),
+ NATIVE_METHOD(Unsafe, park, "(ZJ)V"),
// Each of the getFoo variants are overloaded with a call that operates
// directively on a native pointer.
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 34b84f5..3c0125b 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -791,10 +791,6 @@
std::string error_msg;
if (!jit::Jit::LoadCompiler(&error_msg)) {
LOG(WARNING) << "Failed to load JIT compiler with error " << error_msg;
- } else if (!IsZygote()) {
- // If we are the zygote then we need to wait until after forking to create the code cache
- // due to SELinux restrictions on r/w/x memory regions.
- CreateJitCodeCache(/*rwx_memory_allowed=*/true);
}
}
@@ -900,6 +896,11 @@
}
if (jit_ == nullptr) {
+ // The system server's code cache was initialized specially. For other zygote forks or
+ // processes create it now.
+ if (!is_system_server) {
+ CreateJitCodeCache(/*rwx_memory_allowed=*/true);
+ }
// Note that when running ART standalone (not zygote, nor zygote fork),
// the jit may have already been created.
CreateJit();
@@ -1101,6 +1102,10 @@
sentinel_ = GcRoot<mirror::Object>(sentinel);
}
+GcRoot<mirror::Object> Runtime::GetSentinel() {
+ return sentinel_;
+}
+
static inline void CreatePreAllocatedException(Thread* self,
Runtime* runtime,
GcRoot<mirror::Throwable>* exception,
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 4fb0d2e..be5b3c1 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -691,6 +691,9 @@
// Called from class linker.
void SetSentinel(mirror::Object* sentinel) REQUIRES_SHARED(Locks::mutator_lock_);
+ // For testing purpose only.
+ // TODO: Remove this when this is no longer needed (b/116087961).
+ GcRoot<mirror::Object> GetSentinel() REQUIRES_SHARED(Locks::mutator_lock_);
// Create a normal LinearAlloc or low 4gb version if we are 64 bit AOT compiler.
LinearAlloc* CreateLinearAlloc();
diff --git a/runtime/thread.cc b/runtime/thread.cc
index dda3b82..66e852a 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -44,6 +44,7 @@
#include "arch/context.h"
#include "art_field-inl.h"
#include "art_method-inl.h"
+#include "base/atomic.h"
#include "base/bit_utils.h"
#include "base/casts.h"
#include "base/file_utils.h"
@@ -285,6 +286,116 @@
<< "No deoptimization context for thread " << *this;
}
+enum {
+ kPermitAvailable = 0, // Incrementing consumes the permit
+ kNoPermit = 1, // Incrementing marks as waiter waiting
+ kNoPermitWaiterWaiting = 2
+};
+
+void Thread::Park(bool is_absolute, int64_t time) {
+ DCHECK(this == Thread::Current());
+#if ART_USE_FUTEXES
+ // Consume the permit, or mark as waiting. This cannot cause park_state to go
+ // outside of its valid range (0, 1, 2), because in all cases where 2 is
+ // assigned it is set back to 1 before returning, and this method cannot run
+ // concurrently with itself since it operates on the current thread.
+ int old_state = tls32_.park_state_.fetch_add(1, std::memory_order_relaxed);
+ if (old_state == kNoPermit) {
+ // no permit was available. block thread until later.
+ // TODO: Call to signal jvmti here
+ int result = 0;
+ if (!is_absolute && time == 0) {
+ // Thread.getState() is documented to return waiting for untimed parks.
+ ScopedThreadSuspension sts(this, ThreadState::kWaiting);
+ DCHECK_EQ(NumberOfHeldMutexes(), 0u);
+ result = futex(tls32_.park_state_.Address(),
+ FUTEX_WAIT_PRIVATE,
+ /* sleep if val = */ kNoPermitWaiterWaiting,
+ /* timeout */ nullptr,
+ nullptr,
+ 0);
+ } else if (time > 0) {
+ // Only actually suspend and futex_wait if we're going to wait for some
+ // positive amount of time - the kernel will reject negative times with
+ // EINVAL, and a zero time will just noop.
+
+ // Thread.getState() is documented to return timed wait for timed parks.
+ ScopedThreadSuspension sts(this, ThreadState::kTimedWaiting);
+ DCHECK_EQ(NumberOfHeldMutexes(), 0u);
+ timespec timespec;
+ if (is_absolute) {
+ // Time is millis when scheduled for an absolute time
+ timespec.tv_nsec = (time % 1000) * 1000000;
+ timespec.tv_sec = time / 1000;
+ // This odd looking pattern is recommended by futex documentation to
+ // wait until an absolute deadline, with otherwise identical behavior to
+ // FUTEX_WAIT_PRIVATE. This also allows parkUntil() to return at the
+ // correct time when the system clock changes.
+ result = futex(tls32_.park_state_.Address(),
+ FUTEX_WAIT_BITSET_PRIVATE | FUTEX_CLOCK_REALTIME,
+ /* sleep if val = */ kNoPermitWaiterWaiting,
+ ×pec,
+ nullptr,
+ FUTEX_BITSET_MATCH_ANY);
+ } else {
+ // Time is nanos when scheduled for a relative time
+ timespec.tv_sec = time / 1000000000;
+ timespec.tv_nsec = time % 1000000000;
+ result = futex(tls32_.park_state_.Address(),
+ FUTEX_WAIT_PRIVATE,
+ /* sleep if val = */ kNoPermitWaiterWaiting,
+ ×pec,
+ nullptr,
+ 0);
+ }
+ }
+ if (result == -1) {
+ switch (errno) {
+ case EAGAIN:
+ case ETIMEDOUT:
+ case EINTR: break; // park() is allowed to spuriously return
+ default: PLOG(FATAL) << "Failed to park";
+ }
+ }
+ // Mark as no longer waiting, and consume permit if there is one.
+ tls32_.park_state_.store(kNoPermit, std::memory_order_relaxed);
+ // TODO: Call to signal jvmti here
+ } else {
+ // the fetch_add has consumed the permit. immediately return.
+ DCHECK_EQ(old_state, kPermitAvailable);
+ }
+#else
+ #pragma clang diagnostic push
+ #pragma clang diagnostic warning "-W#warnings"
+ #warning "LockSupport.park/unpark implemented as noops without FUTEX support."
+ #pragma clang diagnostic pop
+ UNUSED(is_absolute, time);
+ UNIMPLEMENTED(WARNING);
+ sched_yield();
+#endif
+}
+
+void Thread::Unpark() {
+#if ART_USE_FUTEXES
+ // Set permit available; will be consumed either by fetch_add (when the thread
+ // tries to park) or store (when the parked thread is woken up)
+ if (tls32_.park_state_.exchange(kPermitAvailable, std::memory_order_relaxed)
+ == kNoPermitWaiterWaiting) {
+ int result = futex(tls32_.park_state_.Address(),
+ FUTEX_WAKE_PRIVATE,
+ /* number of waiters = */ 1,
+ nullptr,
+ nullptr,
+ 0);
+ if (result == -1) {
+ PLOG(FATAL) << "Failed to unpark";
+ }
+ }
+#else
+ UNIMPLEMENTED(WARNING);
+#endif
+}
+
void Thread::PushStackedShadowFrame(ShadowFrame* sf, StackedShadowFrameType type) {
StackedShadowFrameRecord* record = new StackedShadowFrameRecord(
sf, type, tlsPtr_.stacked_shadow_frame_record);
@@ -489,6 +600,22 @@
runtime->GetRuntimeCallbacks()->ThreadStart(self);
+ // Unpark ourselves if the java peer was unparked before it started (see
+ // b/28845097#comment49 for more information)
+
+ ArtField* unparkedField = jni::DecodeArtField(
+ WellKnownClasses::java_lang_Thread_unparkedBeforeStart);
+ bool should_unpark = false;
+ {
+ // Hold the lock here, so that if another thread calls unpark before the thread starts
+ // we don't observe the unparkedBeforeStart field before the unparker writes to it,
+ // which could cause a lost unpark.
+ art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
+ should_unpark = unparkedField->GetBoolean(self->tlsPtr_.opeer) == JNI_TRUE;
+ }
+ if (should_unpark) {
+ self->Unpark();
+ }
// Invoke the 'run' method of our java.lang.Thread.
ObjPtr<mirror::Object> receiver = self->tlsPtr_.opeer;
jmethodID mid = WellKnownClasses::java_lang_Thread_run;
@@ -2133,6 +2260,9 @@
tls32_.state_and_flags.as_struct.flags = 0;
tls32_.state_and_flags.as_struct.state = kNative;
tls32_.interrupted.store(false, std::memory_order_relaxed);
+ // Initialize with no permit; if the java Thread was unparked before being
+ // started, it will unpark itself before calling into java code.
+ tls32_.park_state_.store(kNoPermit, std::memory_order_relaxed);
memset(&tlsPtr_.held_mutexes[0], 0, sizeof(tlsPtr_.held_mutexes));
std::fill(tlsPtr_.rosalloc_runs,
tlsPtr_.rosalloc_runs + kNumRosAllocThreadLocalSizeBracketsInThread,
@@ -2449,12 +2579,15 @@
}
void Thread::Interrupt(Thread* self) {
- MutexLock mu(self, *wait_mutex_);
- if (tls32_.interrupted.load(std::memory_order_seq_cst)) {
- return;
+ {
+ MutexLock mu(self, *wait_mutex_);
+ if (tls32_.interrupted.load(std::memory_order_seq_cst)) {
+ return;
+ }
+ tls32_.interrupted.store(true, std::memory_order_seq_cst);
+ NotifyLocked(self);
}
- tls32_.interrupted.store(true, std::memory_order_seq_cst);
- NotifyLocked(self);
+ Unpark();
}
void Thread::Notify() {
diff --git a/runtime/thread.h b/runtime/thread.h
index 941867c..b304cef 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -581,6 +581,11 @@
return poison_object_cookie_;
}
+ // Parking for 0ns of relative time means an untimed park, negative (though
+ // should be handled in java code) returns immediately
+ void Park(bool is_absolute, int64_t time) REQUIRES_SHARED(Locks::mutator_lock_);
+ void Unpark();
+
private:
void NotifyLocked(Thread* self) REQUIRES(wait_mutex_);
@@ -1543,6 +1548,8 @@
// Thread "interrupted" status; stays raised until queried or thrown.
Atomic<bool32_t> interrupted;
+ AtomicInteger park_state_;
+
// True if the thread is allowed to access a weak ref (Reference::GetReferent() and system
// weaks) and to potentially mark an object alive/gray. This is used for concurrent reference
// processing of the CC collector only. This is thread local so that we can enable/disable weak
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 206418f..94faa62 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -128,6 +128,7 @@
jfieldID WellKnownClasses::java_lang_Thread_name;
jfieldID WellKnownClasses::java_lang_Thread_priority;
jfieldID WellKnownClasses::java_lang_Thread_nativePeer;
+jfieldID WellKnownClasses::java_lang_Thread_unparkedBeforeStart;
jfieldID WellKnownClasses::java_lang_ThreadGroup_groups;
jfieldID WellKnownClasses::java_lang_ThreadGroup_ngroups;
jfieldID WellKnownClasses::java_lang_ThreadGroup_mainThreadGroup;
@@ -376,6 +377,7 @@
java_lang_Thread_name = CacheField(env, java_lang_Thread, false, "name", "Ljava/lang/String;");
java_lang_Thread_priority = CacheField(env, java_lang_Thread, false, "priority", "I");
java_lang_Thread_nativePeer = CacheField(env, java_lang_Thread, false, "nativePeer", "J");
+ java_lang_Thread_unparkedBeforeStart = CacheField(env, java_lang_Thread, false, "unparkedBeforeStart", "Z");
java_lang_ThreadGroup_groups = CacheField(env, java_lang_ThreadGroup, false, "groups", "[Ljava/lang/ThreadGroup;");
java_lang_ThreadGroup_ngroups = CacheField(env, java_lang_ThreadGroup, false, "ngroups", "I");
java_lang_ThreadGroup_mainThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "mainThreadGroup", "Ljava/lang/ThreadGroup;");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index ce5ab1d..8c85228 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -137,6 +137,7 @@
static jfieldID java_lang_Thread_name;
static jfieldID java_lang_Thread_priority;
static jfieldID java_lang_Thread_nativePeer;
+ static jfieldID java_lang_Thread_unparkedBeforeStart;
static jfieldID java_lang_ThreadGroup_groups;
static jfieldID java_lang_ThreadGroup_ngroups;
static jfieldID java_lang_ThreadGroup_mainThreadGroup;
diff --git a/test/004-ThreadStress/src-art/Main.java b/test/004-ThreadStress/src-art/Main.java
index b8bfafb..e717852 100644
--- a/test/004-ThreadStress/src-art/Main.java
+++ b/test/004-ThreadStress/src-art/Main.java
@@ -53,6 +53,7 @@
// -sleep:X .......... frequency of Sleep (double)
// -wait:X ........... frequency of Wait (double)
// -timedwait:X ...... frequency of TimedWait (double)
+// -timedpark:X ...... frequency of TimedPark (double)
// -syncandwork:X .... frequency of SyncAndWork (double)
// -queuedwait:X ..... frequency of QueuedWait (double)
@@ -264,19 +265,6 @@
}
}
- private final static class UnparkAllThreads extends Operation {
- public UnparkAllThreads() {}
-
- @Override
- public boolean perform() {
- Set<Thread> threads = Thread.getAllStackTraces().keySet();
- for (Thread candidate : threads) {
- LockSupport.unpark(candidate);
- }
- return true;
- }
- }
-
private final static class SyncAndWork extends Operation {
private final Object lock;
@@ -346,9 +334,8 @@
frequencyMap.put(new NonMovingAlloc(), 0.025); // 5/200
frequencyMap.put(new StackTrace(), 0.1); // 20/200
frequencyMap.put(new Exit(), 0.225); // 45/200
- frequencyMap.put(new Sleep(), 0.125); // 15/200
- frequencyMap.put(new TimedPark(), 0.025); // 5/200
- frequencyMap.put(new UnparkAllThreads(), 0.025); // 5/200
+ frequencyMap.put(new Sleep(), 0.075); // 15/200
+ frequencyMap.put(new TimedPark(), 0.05); // 10/200
frequencyMap.put(new TimedWait(lock), 0.05); // 10/200
frequencyMap.put(new Wait(lock), 0.075); // 15/200
frequencyMap.put(new QueuedWait(semaphore), 0.05); // 10/200
@@ -370,10 +357,9 @@
Map<Operation, Double> frequencyMap = new HashMap<Operation, Double>();
frequencyMap.put(new Sleep(), 0.2); // 40/200
frequencyMap.put(new TimedWait(lock), 0.1); // 20/200
- frequencyMap.put(new Wait(lock), 0.1); // 20/200
+ frequencyMap.put(new Wait(lock), 0.2); // 40/200
frequencyMap.put(new SyncAndWork(lock), 0.4); // 80/200
frequencyMap.put(new TimedPark(), 0.1); // 20/200
- frequencyMap.put(new UnparkAllThreads(), 0.1); // 20/200
return frequencyMap;
}
@@ -419,6 +405,8 @@
op = new Wait(lock);
} else if (split[0].equals("-timedwait")) {
op = new TimedWait(lock);
+ } else if (split[0].equals("-timedpark")) {
+ op = new TimedPark();
} else if (split[0].equals("-syncandwork")) {
op = new SyncAndWork(lock);
} else if (split[0].equals("-queuedwait")) {
@@ -723,7 +711,7 @@
}
// The notifier thread is a daemon just loops forever to wake
- // up threads in operation Wait.
+ // up threads in operations Wait and Park.
if (lock != null) {
Thread notifier = new Thread("Notifier") {
public void run() {
@@ -731,6 +719,11 @@
synchronized (lock) {
lock.notifyAll();
}
+ for (Thread runner : runners) {
+ if (runner != null) {
+ LockSupport.unpark(runner);
+ }
+ }
}
}
};
diff --git a/test/099-vmdebug/check b/test/099-vmdebug/check
index d124ce8..6a3fed5 100755
--- a/test/099-vmdebug/check
+++ b/test/099-vmdebug/check
@@ -15,6 +15,6 @@
# limitations under the License.
# Strip the process pids and line numbers from exact error messages.
-sed -e '/^dalvikvm\(\|32\|64\) E.*\] /d' "$2" > "$2.tmp"
+sed -e '/^.*dalvikvm\(\|32\|64\) E.*\] /d' "$2" > "$2.tmp"
diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
diff --git a/test/143-string-value/check b/test/143-string-value/check
index 2a3476c..b5e51ce 100755
--- a/test/143-string-value/check
+++ b/test/143-string-value/check
@@ -15,6 +15,6 @@
# limitations under the License.
# Strip error log messages.
-sed -e '/^dalvikvm\(\|32\|64\) E.*\] /d' "$2" > "$2.tmp"
+sed -e '/^.*dalvikvm\(\|32\|64\) E.*\] /d' "$2" > "$2.tmp"
diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
diff --git a/test/160-read-barrier-stress/src/Main.java b/test/160-read-barrier-stress/src/Main.java
index 5865094..5e49e66 100644
--- a/test/160-read-barrier-stress/src/Main.java
+++ b/test/160-read-barrier-stress/src/Main.java
@@ -121,6 +121,23 @@
assertSameObject(f4444, la[i4444]);
assertDifferentObject(f4999, la[i4998]);
assertSameObject(f4999, la[i4999]);
+
+ la = largeArray;
+ // Group the ArrayGets so they aren't divided by a function call; this will enable
+ // interm. address sharing for arm64.
+ Object tmp1 = la[i0];
+ Object tmp2 = la[i0 + 1];
+ Object tmp3 = la[i0 + 1024];
+ Object tmp4 = la[i0 + 4444];
+ Object tmp5 = la[i0 + 4998];
+ Object tmp6 = la[i0 + 4999];
+
+ assertSameObject(f0000, tmp1);
+ assertDifferentObject(f0000, tmp2);
+ assertSameObject(f1024, tmp3);
+ assertSameObject(f4444, tmp4);
+ assertDifferentObject(f4999, tmp5);
+ assertSameObject(f4999, tmp6);
}
}
diff --git a/test/527-checker-array-access-split/src/Main.java b/test/527-checker-array-access-split/src/Main.java
index f83c924..f39b5e2 100644
--- a/test/527-checker-array-access-split/src/Main.java
+++ b/test/527-checker-array-access-split/src/Main.java
@@ -572,6 +572,75 @@
buf1[end] = 'n';
}
+ //
+ // Check that IntermediateAddress can be shared for object ArrayGets.
+ //
+ /// CHECK-START-ARM64: int Main.checkObjectArrayGet(int, java.lang.Integer[], java.lang.Integer[]) instruction_simplifier_arm64 (before)
+ /// CHECK: <<Parameter:l\d+>> ParameterValue
+ /// CHECK: <<Array:l\d+>> NullCheck [<<Parameter>>]
+ /// CHECK: ArrayGet [<<Array>>,{{i\d+}}]
+ /// CHECK: ArrayGet [<<Array>>,{{i\d+}}]
+ /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+ /// CHECK: ArrayGet [<<Array>>,{{i\d+}}]
+ /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+ /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+
+ /// CHECK-START-ARM64: int Main.checkObjectArrayGet(int, java.lang.Integer[], java.lang.Integer[]) instruction_simplifier_arm64 (after)
+ /// CHECK: <<Parameter:l\d+>> ParameterValue
+ /// CHECK: <<DataOffset:i\d+>> IntConstant 12
+ /// CHECK: <<Array:l\d+>> NullCheck [<<Parameter>>]
+ /// CHECK: <<IntAddr1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: ArrayGet [<<IntAddr1>>,{{i\d+}}]
+ /// CHECK: <<IntAddr2:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: ArrayGet [<<IntAddr2>>,{{i\d+}}]
+ /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+ /// CHECK: <<IntAddr3:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: ArrayGet [<<IntAddr3>>,{{i\d+}}]
+ /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+ /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+ //
+ /// CHECK-NOT: IntermediateAddress
+
+ /// CHECK-START-ARM64: int Main.checkObjectArrayGet(int, java.lang.Integer[], java.lang.Integer[]) GVN$after_arch (after)
+ /// CHECK: <<Parameter:l\d+>> ParameterValue
+ /// CHECK: <<DataOffset:i\d+>> IntConstant 12
+ /// CHECK: <<Array:l\d+>> NullCheck [<<Parameter>>]
+ /// CHECK: <<IntAddr1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: ArrayGet [<<IntAddr1>>,{{i\d+}}]
+ /// CHECK: ArrayGet [<<IntAddr1>>,{{i\d+}}]
+ /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+ /// CHECK: <<IntAddr3:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: ArrayGet [<<IntAddr3>>,{{i\d+}}]
+ /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+ /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+ //
+ /// CHECK-NOT: IntermediateAddress
+ public final static int checkObjectArrayGet(int index, Integer[] a, Integer[] b) {
+ Integer five = Integer.valueOf(5);
+ int tmp1 = a[index];
+ tmp1 += a[index + 1];
+ a[index + 1] = five;
+ tmp1 += a[index + 2];
+ a[index + 2] = five;
+ a[index + 3] = five;
+ return tmp1;
+ }
+
+ /// CHECK-START-ARM64: int Main.testIntAddressObjDisasm(java.lang.Integer[], int) disassembly (after)
+ /// CHECK: <<IntAddr:i\d+>> IntermediateAddress
+ /// CHECK: add w<<AddrReg:\d+>>, {{w\d+}}, #0xc
+ /// CHECK: ArrayGet [<<IntAddr>>,{{i\d+}}]
+ /// CHECK: ldr {{w\d+}}, [x<<AddrReg>>, x{{\d+}}, lsl #2]
+ /// CHECK: ArrayGet [<<IntAddr>>,{{i\d+}}]
+ /// CHECK: ldr {{w\d+}}, [x<<AddrReg>>, x{{\d+}}, lsl #2]
+
+ /// CHECK-START-ARM64: int Main.testIntAddressObjDisasm(java.lang.Integer[], int) disassembly (after)
+ /// CHECK: add {{w\d+}}, {{w\d+}}, #0xc
+ /// CHECK-NOT: add {{w\d+}}, {{w\d+}}, #0xc
+ private int testIntAddressObjDisasm(Integer[] obj, int x) {
+ return obj[x] + obj[x + 1];
+ }
+
public final static int ARRAY_SIZE = 128;
public static void main(String[] args) {
diff --git a/test/580-crc32/expected.txt b/test/580-crc32/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/580-crc32/expected.txt
diff --git a/test/580-crc32/info.txt b/test/580-crc32/info.txt
new file mode 100644
index 0000000..24f31e0
--- /dev/null
+++ b/test/580-crc32/info.txt
@@ -0,0 +1 @@
+This test case is used to test java.util.zip.CRC32.
diff --git a/test/580-crc32/src/Main.java b/test/580-crc32/src/Main.java
new file mode 100644
index 0000000..7fc1273
--- /dev/null
+++ b/test/580-crc32/src/Main.java
@@ -0,0 +1,131 @@
+/*
+ * 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.util.zip.CRC32;
+
+/**
+ * The ART compiler can use intrinsics for the java.util.zip.CRC32 method:
+ * private native static int update(int crc, int b)
+ *
+ * As the method is private it is not possible to check the use of intrinsics
+ * for it directly.
+ * The tests check that correct checksums are produced.
+ */
+public class Main {
+ private static CRC32 crc32 = new CRC32();
+
+ public Main() {
+ }
+
+ public static long TestInt(int value) {
+ crc32.reset();
+ crc32.update(value);
+ return crc32.getValue();
+ }
+
+ public static long TestInt(int... values) {
+ crc32.reset();
+ for (int value : values) {
+ crc32.update(value);
+ }
+ return crc32.getValue();
+ }
+
+ public static void assertEqual(long expected, long actual) {
+ if (expected != actual) {
+ throw new Error("Expected: " + expected + ", found: " + actual);
+ }
+ }
+
+ public static void main(String args[]) {
+ // public void update(int b)
+ //
+ // Tests for checksums of the byte 0x0
+ assertEqual(0xD202EF8DL, TestInt(0x0));
+ assertEqual(0xD202EF8DL, TestInt(0x0100));
+ assertEqual(0xD202EF8DL, TestInt(0x010000));
+ assertEqual(0xD202EF8DL, TestInt(0x01000000));
+ assertEqual(0xD202EF8DL, TestInt(0xff00));
+ assertEqual(0xD202EF8DL, TestInt(0xffff00));
+ assertEqual(0xD202EF8DL, TestInt(0xffffff00));
+ assertEqual(0xD202EF8DL, TestInt(0x1200));
+ assertEqual(0xD202EF8DL, TestInt(0x123400));
+ assertEqual(0xD202EF8DL, TestInt(0x12345600));
+ assertEqual(0xD202EF8DL, TestInt(Integer.MIN_VALUE));
+
+ // Tests for checksums of the byte 0x1
+ assertEqual(0xA505DF1BL, TestInt(0x1));
+ assertEqual(0xA505DF1BL, TestInt(0x0101));
+ assertEqual(0xA505DF1BL, TestInt(0x010001));
+ assertEqual(0xA505DF1BL, TestInt(0x01000001));
+ assertEqual(0xA505DF1BL, TestInt(0xff01));
+ assertEqual(0xA505DF1BL, TestInt(0xffff01));
+ assertEqual(0xA505DF1BL, TestInt(0xffffff01));
+ assertEqual(0xA505DF1BL, TestInt(0x1201));
+ assertEqual(0xA505DF1BL, TestInt(0x123401));
+ assertEqual(0xA505DF1BL, TestInt(0x12345601));
+
+ // Tests for checksums of the byte 0x0f
+ assertEqual(0x42BDF21CL, TestInt(0x0f));
+ assertEqual(0x42BDF21CL, TestInt(0x010f));
+ assertEqual(0x42BDF21CL, TestInt(0x01000f));
+ assertEqual(0x42BDF21CL, TestInt(0x0100000f));
+ assertEqual(0x42BDF21CL, TestInt(0xff0f));
+ assertEqual(0x42BDF21CL, TestInt(0xffff0f));
+ assertEqual(0x42BDF21CL, TestInt(0xffffff0f));
+ assertEqual(0x42BDF21CL, TestInt(0x120f));
+ assertEqual(0x42BDF21CL, TestInt(0x12340f));
+ assertEqual(0x42BDF21CL, TestInt(0x1234560f));
+
+ // Tests for checksums of the byte 0xff
+ assertEqual(0xFF000000L, TestInt(0x00ff));
+ assertEqual(0xFF000000L, TestInt(0x01ff));
+ assertEqual(0xFF000000L, TestInt(0x0100ff));
+ assertEqual(0xFF000000L, TestInt(0x010000ff));
+ assertEqual(0xFF000000L, TestInt(0x0000ffff));
+ assertEqual(0xFF000000L, TestInt(0x00ffffff));
+ assertEqual(0xFF000000L, TestInt(0xffffffff));
+ assertEqual(0xFF000000L, TestInt(0x12ff));
+ assertEqual(0xFF000000L, TestInt(0x1234ff));
+ assertEqual(0xFF000000L, TestInt(0x123456ff));
+ assertEqual(0xFF000000L, TestInt(Integer.MAX_VALUE));
+
+ // Tests for sequences
+ assertEqual(0xFF41D912L, TestInt(0, 0, 0));
+ assertEqual(0xFF41D912L, TestInt(0x0100, 0x010000, 0x01000000));
+ assertEqual(0xFF41D912L, TestInt(0xff00, 0xffff00, 0xffffff00));
+ assertEqual(0xFF41D912L, TestInt(0x1200, 0x123400, 0x12345600));
+
+ assertEqual(0x909FB2F2L, TestInt(1, 1, 1));
+ assertEqual(0x909FB2F2L, TestInt(0x0101, 0x010001, 0x01000001));
+ assertEqual(0x909FB2F2L, TestInt(0xff01, 0xffff01, 0xffffff01));
+ assertEqual(0x909FB2F2L, TestInt(0x1201, 0x123401, 0x12345601));
+
+ assertEqual(0xE33A9F71L, TestInt(0x0f, 0x0f, 0x0f));
+ assertEqual(0xE33A9F71L, TestInt(0x010f, 0x01000f, 0x0100000f));
+ assertEqual(0xE33A9F71L, TestInt(0xff0f, 0xffff0f, 0xffffff0f));
+ assertEqual(0xE33A9F71L, TestInt(0x120f, 0x12340f, 0x1234560f));
+
+ assertEqual(0xFFFFFF00L, TestInt(0x0ff, 0x0ff, 0x0ff));
+ assertEqual(0xFFFFFF00L, TestInt(0x01ff, 0x0100ff, 0x010000ff));
+ assertEqual(0xFFFFFF00L, TestInt(0x00ffff, 0x00ffffff, 0xffffffff));
+ assertEqual(0xFFFFFF00L, TestInt(0x12ff, 0x1234ff, 0x123456ff));
+
+ assertEqual(0xB6CC4292L, TestInt(0x01, 0x02));
+
+ assertEqual(0xB2DE047CL, TestInt(0x0, -1, Integer.MIN_VALUE, Integer.MAX_VALUE));
+ }
+}
diff --git a/test/624-checker-stringops/smali/Smali.smali b/test/624-checker-stringops/smali/Smali.smali
index 8600a0a..f8b9275 100644
--- a/test/624-checker-stringops/smali/Smali.smali
+++ b/test/624-checker-stringops/smali/Smali.smali
@@ -34,7 +34,7 @@
invoke-virtual {v0, v1}, Ljava/lang/StringBuffer;->append(Ljava/lang/String;)Ljava/lang/StringBuffer;
move-result-object v1
- const-string v2, "x"
+ const-string v2, "y"
invoke-virtual {v1, v2}, Ljava/lang/StringBuffer;->append(Ljava/lang/String;)Ljava/lang/StringBuffer;
move-result-object v1
@@ -70,7 +70,7 @@
invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
- const-string v2, "x"
+ const-string v2, "y"
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
diff --git a/test/624-checker-stringops/src/Main.java b/test/624-checker-stringops/src/Main.java
index 3aa6e56..f52d81a 100644
--- a/test/624-checker-stringops/src/Main.java
+++ b/test/624-checker-stringops/src/Main.java
@@ -120,7 +120,7 @@
/// CHECK-DAG: InvokeVirtual [<<New>>] intrinsic:StringBufferLength
static int bufferLen2() {
StringBuffer s = new StringBuffer();
- return s.append("x").append("x").length();
+ return s.append("x").append("y").length();
}
static int bufferLen2Smali() throws Exception {
@@ -150,7 +150,7 @@
/// CHECK-DAG: InvokeVirtual [<<New>>] intrinsic:StringBuilderLength
static int builderLen2() {
StringBuilder s = new StringBuilder();
- return s.append("x").append("x").length();
+ return s.append("x").append("y").length();
}
static int builderLen2Smali() throws Exception {
diff --git a/test/911-get-stack-trace/expected.txt b/test/911-get-stack-trace/expected.txt
index b0a400a..8dd49aa 100644
--- a/test/911-get-stack-trace/expected.txt
+++ b/test/911-get-stack-trace/expected.txt
@@ -21,7 +21,7 @@
baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
bar (IIILart/ControlData;)J 0 26
foo (IIILart/ControlData;)I 0 21
- doTest ()V 33 25
+ doTest ()V 31 25
run ()V 0 25
---------
print (Ljava/lang/Thread;II)V 0 38
@@ -41,7 +41,7 @@
baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
bar (IIILart/ControlData;)J 0 26
foo (IIILart/ControlData;)I 0 21
- doTest ()V 37 26
+ doTest ()V 35 26
run ()V 0 25
---------
getStackTrace (Ljava/lang/Thread;II)[[Ljava/lang/String; -1 -2
@@ -62,7 +62,7 @@
baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
bar (IIILart/ControlData;)J 0 26
foo (IIILart/ControlData;)I 0 21
- doTest ()V 60 32
+ doTest ()V 58 32
run ()V 0 25
---------
bar (IIILart/ControlData;)J 0 26
@@ -388,7 +388,7 @@
Test911
getAllStackTraces (I)[[Ljava/lang/Object; -1 -2
printAll (I)V 0 75
- doTest ()V 120 59
+ doTest ()V 118 59
run ()V 24 37
---------
@@ -643,7 +643,7 @@
Test911
getAllStackTraces (I)[[Ljava/lang/Object; -1 -2
printAll (I)V 0 75
- doTest ()V 125 61
+ doTest ()V 123 61
run ()V 24 37
---------
@@ -675,7 +675,7 @@
Test911
getThreadListStackTraces ([Ljava/lang/Thread;I)[[Ljava/lang/Object; -1 -2
printList ([Ljava/lang/Thread;I)V 0 68
- doTest ()V 110 54
+ doTest ()V 108 54
run ()V 32 41
---------
@@ -732,7 +732,7 @@
Test911
getThreadListStackTraces ([Ljava/lang/Thread;I)[[Ljava/lang/Object; -1 -2
printList ([Ljava/lang/Thread;I)V 0 68
- doTest ()V 115 56
+ doTest ()V 113 56
run ()V 32 41
---------
@@ -857,7 +857,7 @@
4
JVMTI_ERROR_ILLEGAL_ARGUMENT
[public static native java.lang.Object[] art.Frames.getFrameLocation(java.lang.Thread,int), ffffffff]
-[public static void art.Frames.doTestSameThread(), 40]
+[public static void art.Frames.doTestSameThread(), 3e]
[public static void art.Frames.doTest() throws java.lang.Exception, 0]
[public void art.Test911$1.run(), 28]
JVMTI_ERROR_NO_MORE_FRAMES
diff --git a/test/913-heaps/expected.txt b/test/913-heaps/expected.txt
index 065b854..1bd56d1 100644
--- a/test/913-heaps/expected.txt
+++ b/test/913-heaps/expected.txt
@@ -1,9 +1,9 @@
---
true true
-root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=124, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=132, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=124, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
1001@0 --(superclass)--> 1000@0 [size=123456780000, length=-1]
1002@0 --(interface)--> 2001@0 [size=123456780004, length=-1]
1002@0 --(superclass)--> 1001@0 [size=123456780001, length=-1]
@@ -44,14 +44,14 @@
---
root@root --(jni-global)--> 1@1000 [size=16, length=-1]
root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
-root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=124, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=132, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=124, length=-1]
root@root --(thread)--> 1@1000 [size=16, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
1001@0 --(superclass)--> 1000@0 [size=123456780005, length=-1]
1002@0 --(interface)--> 2001@0 [size=123456780009, length=-1]
1002@0 --(superclass)--> 1001@0 [size=123456780006, length=-1]
@@ -90,18 +90,18 @@
5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
6@1000 --(class)--> 1000@0 [size=123456780005, length=-1]
---
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
---
3@1001 --(class)--> 1001@0 [size=123456780011, length=-1]
---
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
---
3@1001 --(class)--> 1001@0 [size=123456780016, length=-1]
---
-root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=124, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=132, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=124, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
---
1001@0 --(superclass)--> 1000@0 [size=123456780020, length=-1]
3@1001 --(class)--> 1001@0 [size=123456780021, length=-1]
@@ -110,14 +110,14 @@
---
root@root --(jni-global)--> 1@1000 [size=16, length=-1]
root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
-root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=124, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=132, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=124, length=-1]
root@root --(thread)--> 1@1000 [size=16, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
---
1001@0 --(superclass)--> 1000@0 [size=123456780025, length=-1]
3@1001 --(class)--> 1001@0 [size=123456780026, length=-1]
@@ -198,10 +198,10 @@
---
---
---- untagged objects
-root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=124, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=132, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=124, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
1001@0 --(superclass)--> 1000@0 [size=123456780050, length=-1]
1002@0 --(interface)--> 2001@0 [size=123456780054, length=-1]
1002@0 --(superclass)--> 1001@0 [size=123456780051, length=-1]
@@ -242,14 +242,14 @@
---
root@root --(jni-global)--> 1@1000 [size=16, length=-1]
root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
-root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=124, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1]
root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=132, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=124, length=-1]
root@root --(thread)--> 1@1000 [size=16, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
1001@0 --(superclass)--> 1000@0 [size=123456780055, length=-1]
1002@0 --(interface)--> 2001@0 [size=123456780059, length=-1]
1002@0 --(superclass)--> 1001@0 [size=123456780056, length=-1]
@@ -289,9 +289,9 @@
6@1000 --(class)--> 1000@0 [size=123456780055, length=-1]
---
---- tagged classes
-root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=132, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=132, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=124, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=124, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
1001@0 --(superclass)--> 1000@0 [size=123456780060, length=-1]
1002@0 --(interface)--> 2001@0 [size=123456780064, length=-1]
1002@0 --(superclass)--> 1001@0 [size=123456780061, length=-1]
@@ -316,9 +316,9 @@
5@1002 --(field@8)--> 500@0 [size=20, length=2]
6@1000 --(class)--> 1000@0 [size=123456780060, length=-1]
---
-root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=132, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=132, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=124, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=124, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
1001@0 --(superclass)--> 1000@0 [size=123456780065, length=-1]
1002@0 --(interface)--> 2001@0 [size=123456780069, length=-1]
1002@0 --(superclass)--> 1001@0 [size=123456780066, length=-1]
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 64c1d4f..148aea4 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -59,6 +59,7 @@
ART_TEST_HOST_RUN_TEST_DEPENDENCIES := \
$(ART_HOST_EXECUTABLES) \
$(HOST_OUT_EXECUTABLES)/hprof-conv \
+ $(HOST_OUT_EXECUTABLES)/timeout_dumper \
$(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libtiagent) \
$(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libtiagentd) \
$(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libtistress) \
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 900b1d7..6488d24 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -31,6 +31,8 @@
GDB_SERVER="gdbserver"
HAVE_IMAGE="y"
HOST="n"
+BIONIC="n"
+CREATE_ANDROID_ROOT="n"
INTERPRETER="n"
JIT="n"
INVOKE_WITH=""
@@ -209,6 +211,13 @@
HOST="y"
ANDROID_ROOT="$ANDROID_HOST_OUT"
shift
+ elif [ "x$1" = "x--bionic" ]; then
+ BIONIC="y"
+ # We need to create an ANDROID_ROOT because currently we cannot create
+ # the frameworks/libcore with linux_bionic so we need to use the normal
+ # host ones which are in a different location.
+ CREATE_ANDROID_ROOT="y"
+ shift
elif [ "x$1" = "x--no-prebuild" ]; then
PREBUILD="n"
shift
@@ -374,6 +383,10 @@
done
fi
+if [ "$CREATE_ANDROID_ROOT" = "y" ]; then
+ ANDROID_ROOT=$DEX_LOCATION/android-root
+fi
+
if [ "x$1" = "x" ] ; then
MAIN="Main"
else
@@ -644,6 +657,15 @@
fi
fi
+if [ "$BIONIC" = "y" ]; then
+ # This is the location that soong drops linux_bionic builds. Despite being
+ # called linux_bionic-x86 the build is actually amd64 (x86_64) only.
+ if [ ! -e "$OUT_DIR/soong/host/linux_bionic-x86" ]; then
+ echo "linux_bionic-x86 target doesn't seem to have been built!" >&2
+ exit 1
+ fi
+fi
+
# Prevent test from silently falling back to interpreter in no-prebuild mode. This happens
# when DEX_LOCATION path is too long, because vdex/odex filename is constructed by taking
# full path to dex, stripping leading '/', appending '@classes.vdex' and changing every
@@ -671,6 +693,21 @@
mkdir_locations="${DEX_LOCATION}/dalvik-cache/$ISA"
strip_cmdline="true"
sync_cmdline="true"
+linkroot_cmdline="true"
+linkroot_overlay_cmdline="true"
+
+linkdirs() {
+ find "$1" -maxdepth 1 -mindepth 1 -type d | xargs -i ln -sf '{}' "$2"
+}
+
+if [ "$CREATE_ANDROID_ROOT" = "y" ]; then
+ mkdir_locations="${mkdir_locations} ${ANDROID_ROOT}"
+ linkroot_cmdline="linkdirs ${ANDROID_HOST_OUT} ${ANDROID_ROOT}"
+ if [ "${BIONIC}" = "y" ]; then
+ # TODO Make this overlay more generic.
+ linkroot_overlay_cmdline="linkdirs $OUT_DIR/soong/host/linux_bionic-x86 ${ANDROID_ROOT}"
+ fi
+fi
# PROFILE takes precedence over RANDOM_PROFILE, since PROFILE tests require a
# specific profile to run properly.
@@ -942,14 +979,15 @@
# Note: We first send SIGRTMIN+2 (usually 36) to ART, which will induce a full thread dump
# before abort. However, dumping threads might deadlock, so we also use the "-k"
# option to definitely kill the child.
- cmdline="timeout -k 120s -s SIGRTMIN+2 ${TIME_OUT_VALUE}s $cmdline"
+ cmdline="timeout -k 120s -s SIGRTMIN+2 ${TIME_OUT_VALUE}s timeout_dumper $cmdline"
fi
if [ "$DEV_MODE" = "y" ]; then
for var in ANDROID_PRINTF_LOG ANDROID_DATA ANDROID_ROOT LD_LIBRARY_PATH DYLD_LIBRARY_PATH PATH LD_USE_LOAD_BIAS; do
echo EXPORT $var=${!var}
done
- echo "mkdir -p ${mkdir_locations} && $profman_cmdline && $dex2oat_cmdline && $dm_cmdline && $vdex_cmdline && $strip_cmdline && $sync_cmdline && $cmdline"
+ echo "$(declare -f linkdirs)"
+ echo "mkdir -p ${mkdir_locations} && $linkroot_cmdline && $linkroot_overlay_cmdline && $profman_cmdline && $dex2oat_cmdline && $dm_cmdline && $vdex_cmdline && $strip_cmdline && $sync_cmdline && $cmdline"
fi
cd $ANDROID_BUILD_TOP
@@ -963,6 +1001,8 @@
export ASAN_OPTIONS=$RUN_TEST_ASAN_OPTIONS
mkdir -p ${mkdir_locations} || exit 1
+ $linkroot_cmdline || { echo "create symlink android-root failed." >&2 ; exit 2; }
+ $linkroot_overlay_cmdline || { echo "overlay android-root failed." >&2 ; exit 2; }
$profman_cmdline || { echo "Profman failed." >&2 ; exit 2; }
$dex2oat_cmdline || { echo "Dex2oat failed." >&2 ; exit 2; }
$dm_cmdline || { echo "Dex2oat failed." >&2 ; exit 2; }
diff --git a/test/run-test b/test/run-test
index 229e201..2363152 100755
--- a/test/run-test
+++ b/test/run-test
@@ -88,6 +88,8 @@
export ANDROID_HOST_OUT=${OUT_DIR}/host/linux-x86
fi
+host_lib_root=${ANDROID_HOST_OUT}
+
# Allow changing DESUGAR script to something else, or to disable it with DESUGAR=false.
if [ -z "$DESUGAR" ]; then
export DESUGAR="$ANDROID_BUILD_TOP/art/tools/desugar.sh"
@@ -385,6 +387,14 @@
run_args="${run_args} --64"
suffix64="64"
shift
+ elif [ "x$1" = "x--bionic" ]; then
+ # soong linux_bionic builds are 64bit only.
+ run_args="${run_args} --bionic --host --64"
+ suffix64="64"
+ target_mode="no"
+ DEX_LOCATION=$tmp_dir
+ host_lib_root=$OUT_DIR/soong/host/linux_bionic-x86
+ shift
elif [ "x$1" = "x--trace" ]; then
trace="true"
shift
@@ -584,7 +594,7 @@
if [ "$target_mode" = "no" ]; then
guess_host_arch_name
run_args="${run_args} --boot ${ANDROID_HOST_OUT}/framework/core${image_suffix}.art"
- run_args="${run_args} --runtime-option -Djava.library.path=${ANDROID_HOST_OUT}/lib${suffix64}:${ANDROID_HOST_OUT}/nativetest${suffix64}"
+ run_args="${run_args} --runtime-option -Djava.library.path=${host_lib_root}/lib${suffix64}:${host_lib_root}/nativetest${suffix64}"
else
guess_target_arch_name
run_args="${run_args} --runtime-option -Djava.library.path=/data/nativetest${suffix64}/art/${target_arch_name}"
@@ -711,6 +721,7 @@
echo " --output-path [path] Location where to store the build" \
"files."
echo " --64 Run the test in 64-bit mode"
+ echo " --bionic Use the (host, 64-bit only) linux_bionic libc runtime"
echo " --trace Run with method tracing"
echo " --strace Run with syscall tracing from strace."
echo " --stream Run method tracing in streaming mode (requires --trace)"
diff --git a/tools/build_linux_bionic_tests.sh b/tools/build_linux_bionic_tests.sh
new file mode 100755
index 0000000..dba2d50
--- /dev/null
+++ b/tools/build_linux_bionic_tests.sh
@@ -0,0 +1,101 @@
+#!/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.
+
+
+if [[ -z $ANDROID_BUILD_TOP ]]; then
+ pushd .
+else
+ pushd $ANDROID_BUILD_TOP
+fi
+
+if [ ! -d art ]; then
+ echo "Script needs to be run at the root of the android tree"
+ exit 1
+fi
+
+source build/envsetup.sh >&/dev/null # for get_build_var
+
+out_dir=$(get_build_var OUT_DIR)
+
+# TODO(b/31559095) Figure out a better way to do this.
+#
+# There is no good way to force soong to generate host-bionic builds currently
+# so this is a hacky workaround.
+
+# First build all the targets still in .mk files (also build normal glibc host
+# targets so we know what's needed to run the tests).
+build/soong/soong_ui.bash --make-mode "$@" test-art-host-run-test-dependencies build-art-host-tests
+if [ $? != 0 ]; then
+ exit 1
+fi
+
+tmp_soong_var=$(mktemp --tmpdir soong.variables.bak.XXXXXX)
+
+echo "Saving soong.variables to " $tmp_soong_var
+cat $out_dir/soong/soong.variables > ${tmp_soong_var}
+python3 <<END - ${tmp_soong_var} ${out_dir}/soong/soong.variables
+import json
+import sys
+x = json.load(open(sys.argv[1]))
+x['Allow_missing_dependencies'] = True
+x['HostArch'] = 'x86_64'
+x['CrossHost'] = 'linux_bionic'
+x['CrossHostArch'] = 'x86_64'
+if 'CrossHostSecondaryArch' in x:
+ del x['CrossHostSecondaryArch']
+json.dump(x, open(sys.argv[2], mode='w'))
+END
+if [ $? != 0 ]; then
+ mv $tmp_soong_var $out_dir/soong/soong.variables
+ exit 2
+fi
+
+soong_out=$out_dir/soong/host/linux_bionic-x86
+declare -a bionic_targets
+# These are the binaries actually used in tests. Since some of the files are
+# java targets or 32 bit we cannot just do the same find for the bin files.
+#
+# We look at what the earlier build generated to figure out what to ask soong to
+# build since we cannot use the .mk defined phony targets.
+bionic_targets=(
+ $soong_out/bin/dalvikvm
+ $soong_out/bin/dalvikvm64
+ $soong_out/bin/dex2oat
+ $soong_out/bin/dex2oatd
+ $soong_out/bin/profman
+ $soong_out/bin/profmand
+ $soong_out/bin/hiddenapi
+ $soong_out/bin/hprof-conv
+ $(find $ANDROID_HOST_OUT/lib64 -type f | sed "s:$ANDROID_HOST_OUT:$soong_out:g")
+ $(find $ANDROID_HOST_OUT/nativetest64 -type f | sed "s:$ANDROID_HOST_OUT:$soong_out:g"))
+
+echo building ${bionic_targets[*]}
+
+build/soong/soong_ui.bash --make-mode --skip-make "$@" ${bionic_targets[*]}
+ret=$?
+
+mv $tmp_soong_var $out_dir/soong/soong.variables
+
+# Having built with host-bionic confuses soong somewhat by making it think the
+# linux_bionic targets are needed for art phony targets like
+# test-art-host-run-test-dependencies. To work around this blow away all
+# ninja files in OUT_DIR. The build system is smart enough to not need to
+# rebuild stuff so this should be fine.
+rm -f $OUT_DIR/*.ninja $OUT_DIR/soong/*.ninja
+
+popd
+
+exit $ret
diff --git a/tools/timeout_dumper/Android.bp b/tools/timeout_dumper/Android.bp
new file mode 100644
index 0000000..dfd5442
--- /dev/null
+++ b/tools/timeout_dumper/Android.bp
@@ -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.
+//
+
+art_cc_binary {
+ name: "timeout_dumper",
+
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ device_supported: false,
+
+ defaults: ["art_defaults"],
+
+ srcs: ["timeout_dumper.cc"],
+
+ shared_libs: [
+ "libbacktrace",
+ "libbase",
+ ],
+ sanitize: {
+ address: true,
+ },
+}
diff --git a/tools/timeout_dumper/timeout_dumper.cc b/tools/timeout_dumper/timeout_dumper.cc
new file mode 100644
index 0000000..cb3eaa5
--- /dev/null
+++ b/tools/timeout_dumper/timeout_dumper.cc
@@ -0,0 +1,590 @@
+/*
+ * 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.
+ */
+
+#include <dirent.h>
+#include <poll.h>
+#include <sys/prctl.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <csignal>
+#include <cstdlib>
+#include <cstring>
+#include <thread>
+#include <memory>
+#include <set>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+namespace art {
+namespace {
+
+using android::base::StringPrintf;
+using android::base::unique_fd;
+
+constexpr bool kUseAddr2line = true;
+
+namespace timeout_signal {
+
+class SignalSet {
+ public:
+ SignalSet() {
+ if (sigemptyset(&set_) == -1) {
+ PLOG(FATAL) << "sigemptyset failed";
+ }
+ }
+
+ void Add(int signal) {
+ if (sigaddset(&set_, signal) == -1) {
+ PLOG(FATAL) << "sigaddset " << signal << " failed";
+ }
+ }
+
+ void Block() {
+ if (pthread_sigmask(SIG_BLOCK, &set_, nullptr) != 0) {
+ PLOG(FATAL) << "pthread_sigmask failed";
+ }
+ }
+
+ int Wait() {
+ // Sleep in sigwait() until a signal arrives. gdb causes EINTR failures.
+ int signal_number;
+ int rc = TEMP_FAILURE_RETRY(sigwait(&set_, &signal_number));
+ if (rc != 0) {
+ PLOG(FATAL) << "sigwait failed";
+ }
+ return signal_number;
+ }
+
+ private:
+ sigset_t set_;
+};
+
+int GetTimeoutSignal() {
+ return SIGRTMIN + 2;
+}
+
+} // namespace timeout_signal
+
+namespace addr2line {
+
+constexpr const char* kAddr2linePath =
+ "/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/bin/x86_64-linux-addr2line";
+
+std::unique_ptr<std::string> FindAddr2line() {
+ const char* env_value = getenv("ANDROID_BUILD_TOP");
+ if (env_value != nullptr) {
+ std::string path = std::string(env_value) + kAddr2linePath;
+ if (access(path.c_str(), X_OK) == 0) {
+ return std::make_unique<std::string>(path);
+ }
+ }
+
+ std::string path = std::string(".") + kAddr2linePath;
+ if (access(path.c_str(), X_OK) == 0) {
+ return std::make_unique<std::string>(path);
+ }
+
+ constexpr const char* kHostAddr2line = "/usr/bin/addr2line";
+ if (access(kHostAddr2line, F_OK) == 0) {
+ return std::make_unique<std::string>(kHostAddr2line);
+ }
+
+ return nullptr;
+}
+
+// The state of an open pipe to addr2line. In "server" mode, addr2line takes input on stdin
+// and prints the result to stdout. This struct keeps the state of the open connection.
+struct Addr2linePipe {
+ Addr2linePipe(int in_fd, int out_fd, const std::string& file_name, pid_t pid)
+ : in(in_fd), out(out_fd), file(file_name), child_pid(pid), odd(true) {}
+
+ ~Addr2linePipe() {
+ kill(child_pid, SIGKILL);
+ }
+
+ unique_fd in; // The file descriptor that is connected to the output of addr2line.
+ unique_fd out; // The file descriptor that is connected to the input of addr2line.
+
+ const std::string file; // The file addr2line is working on, so that we know when to close
+ // and restart.
+ const pid_t child_pid; // The pid of the child, which we should kill when we're done.
+ bool odd; // Print state for indentation of lines.
+};
+
+std::unique_ptr<Addr2linePipe> Connect(const std::string& name, const char* args[]) {
+ int caller_to_addr2line[2];
+ int addr2line_to_caller[2];
+
+ if (pipe(caller_to_addr2line) == -1) {
+ return nullptr;
+ }
+ if (pipe(addr2line_to_caller) == -1) {
+ close(caller_to_addr2line[0]);
+ close(caller_to_addr2line[1]);
+ return nullptr;
+ }
+
+ pid_t pid = fork();
+ if (pid == -1) {
+ close(caller_to_addr2line[0]);
+ close(caller_to_addr2line[1]);
+ close(addr2line_to_caller[0]);
+ close(addr2line_to_caller[1]);
+ return nullptr;
+ }
+
+ if (pid == 0) {
+ dup2(caller_to_addr2line[0], STDIN_FILENO);
+ dup2(addr2line_to_caller[1], STDOUT_FILENO);
+
+ close(caller_to_addr2line[0]);
+ close(caller_to_addr2line[1]);
+ close(addr2line_to_caller[0]);
+ close(addr2line_to_caller[1]);
+
+ execv(args[0], const_cast<char* const*>(args));
+ exit(1);
+ } else {
+ close(caller_to_addr2line[0]);
+ close(addr2line_to_caller[1]);
+ return std::make_unique<Addr2linePipe>(addr2line_to_caller[0],
+ caller_to_addr2line[1],
+ name,
+ pid);
+ }
+}
+
+void WritePrefix(std::ostream& os, const char* prefix, bool odd) {
+ if (prefix != nullptr) {
+ os << prefix;
+ }
+ os << " ";
+ if (!odd) {
+ os << " ";
+ }
+}
+
+void Drain(size_t expected,
+ const char* prefix,
+ std::unique_ptr<Addr2linePipe>* pipe /* inout */,
+ std::ostream& os) {
+ DCHECK(pipe != nullptr);
+ DCHECK(pipe->get() != nullptr);
+ int in = pipe->get()->in.get();
+ DCHECK_GE(in, 0);
+
+ bool prefix_written = false;
+
+ for (;;) {
+ constexpr uint32_t kWaitTimeExpectedMilli = 500;
+ constexpr uint32_t kWaitTimeUnexpectedMilli = 50;
+
+ int timeout = expected > 0 ? kWaitTimeExpectedMilli : kWaitTimeUnexpectedMilli;
+ struct pollfd read_fd{in, POLLIN, 0};
+ int retval = TEMP_FAILURE_RETRY(poll(&read_fd, 1, timeout));
+ if (retval == -1) {
+ // An error occurred.
+ pipe->reset();
+ return;
+ }
+
+ if (retval == 0) {
+ // Timeout.
+ return;
+ }
+
+ if (!(read_fd.revents & POLLIN)) {
+ // addr2line call exited.
+ pipe->reset();
+ return;
+ }
+
+ constexpr size_t kMaxBuffer = 128; // Relatively small buffer. Should be OK as we're on an
+ // alt stack, but just to be sure...
+ char buffer[kMaxBuffer];
+ memset(buffer, 0, kMaxBuffer);
+ int bytes_read = TEMP_FAILURE_RETRY(read(in, buffer, kMaxBuffer - 1));
+ if (bytes_read <= 0) {
+ // This should not really happen...
+ pipe->reset();
+ return;
+ }
+ buffer[bytes_read] = '\0';
+
+ char* tmp = buffer;
+ while (*tmp != 0) {
+ if (!prefix_written) {
+ WritePrefix(os, prefix, (*pipe)->odd);
+ prefix_written = true;
+ }
+ char* new_line = strchr(tmp, '\n');
+ if (new_line == nullptr) {
+ os << tmp;
+
+ break;
+ } else {
+ char saved = *(new_line + 1);
+ *(new_line + 1) = 0;
+ os << tmp;
+ *(new_line + 1) = saved;
+
+ tmp = new_line + 1;
+ prefix_written = false;
+ (*pipe)->odd = !(*pipe)->odd;
+
+ if (expected > 0) {
+ expected--;
+ }
+ }
+ }
+ }
+}
+
+void Addr2line(const std::string& addr2line,
+ const std::string& map_src,
+ uintptr_t offset,
+ std::ostream& os,
+ const char* prefix,
+ std::unique_ptr<Addr2linePipe>* pipe /* inout */) {
+ DCHECK(pipe != nullptr);
+
+ if (map_src == "[vdso]" || android::base::EndsWith(map_src, ".vdex")) {
+ // addr2line will not work on the vdso.
+ // vdex files are special frames injected for the interpreter
+ // so they don't have any line number information available.
+ return;
+ }
+
+ if (*pipe == nullptr || (*pipe)->file != map_src) {
+ if (*pipe != nullptr) {
+ Drain(0, prefix, pipe, os);
+ }
+ pipe->reset(); // Close early.
+
+ const char* args[7] = {
+ addr2line.c_str(),
+ "--functions",
+ "--inlines",
+ "--demangle",
+ "-e",
+ map_src.c_str(),
+ nullptr
+ };
+ *pipe = Connect(map_src, args);
+ }
+
+ Addr2linePipe* pipe_ptr = pipe->get();
+ if (pipe_ptr == nullptr) {
+ // Failed...
+ return;
+ }
+
+ // Send the offset.
+ const std::string hex_offset = StringPrintf("%zx\n", offset);
+
+ if (!android::base::WriteFully(pipe_ptr->out.get(), hex_offset.data(), hex_offset.length())) {
+ // Error. :-(
+ pipe->reset();
+ return;
+ }
+
+ // Now drain (expecting two lines).
+ Drain(2U, prefix, pipe, os);
+}
+
+} // namespace addr2line
+
+namespace ptrace {
+
+std::set<pid_t> PtraceSiblings(pid_t pid) {
+ std::set<pid_t> ret;
+ std::string task_path = android::base::StringPrintf("/proc/%d/task", pid);
+
+ std::unique_ptr<DIR, int (*)(DIR*)> d(opendir(task_path.c_str()), closedir);
+
+ // Bail early if the task directory cannot be opened.
+ if (d == nullptr) {
+ PLOG(ERROR) << "Failed to scan task folder";
+ return ret;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(d.get())) != nullptr) {
+ // Ignore "." and "..".
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
+ continue;
+ }
+
+ char* end;
+ pid_t tid = strtoul(de->d_name, &end, 10);
+ if (*end) {
+ continue;
+ }
+
+ if (tid == pid) {
+ continue;
+ }
+
+ if (::ptrace(PTRACE_ATTACH, tid, 0, 0) != 0) {
+ PLOG(ERROR) << "Failed to attach to tid " << tid;
+ continue;
+ }
+
+ ret.insert(tid);
+ }
+ return ret;
+}
+
+} // namespace ptrace
+
+bool WaitForSigStoppedOrError(pid_t pid) {
+ int status;
+ pid_t res = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
+ if (res == -1) {
+ PLOG(ERROR) << "Failed to waitpid for " << pid;
+ return false;
+ }
+ if (!(WIFSTOPPED(status))) {
+ LOG(ERROR) << "Did not get expected stopped signal for " << pid;
+ return false;
+ }
+ return true;
+}
+
+#ifdef __LP64__
+constexpr bool kIs64Bit = true;
+#else
+constexpr bool kIs64Bit = false;
+#endif
+
+void DumpThread(pid_t pid,
+ pid_t tid,
+ const std::string* addr2line_path,
+ const char* prefix,
+ BacktraceMap* map) {
+ if (pid != tid && !WaitForSigStoppedOrError(tid)) {
+ return;
+ }
+
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map));
+ if (backtrace == nullptr) {
+ LOG(ERROR) << prefix << "(failed to create Backtrace for thread " << tid << ")";
+ return;
+ }
+ backtrace->SetSkipFrames(0);
+ if (!backtrace->Unwind(0, nullptr)) {
+ LOG(ERROR) << prefix << "(backtrace::Unwind failed for thread " << tid
+ << ": " << backtrace->GetErrorString(backtrace->GetError()) << ")";
+ return;
+ }
+ if (backtrace->NumFrames() == 0) {
+ LOG(ERROR) << prefix << "(no native stack frames for thread " << tid << ")";
+ return;
+ }
+
+ std::unique_ptr<addr2line::Addr2linePipe> addr2line_state;
+
+ for (Backtrace::const_iterator it = backtrace->begin();
+ it != backtrace->end(); ++it) {
+ std::ostringstream oss;
+ oss << prefix << StringPrintf("#%02zu pc ", it->num);
+ bool try_addr2line = false;
+ if (!BacktraceMap::IsValid(it->map)) {
+ oss << StringPrintf(kIs64Bit ? "%016" PRIx64 " ???" : "%08" PRIx64 " ???", it->pc);
+ } else {
+ oss << StringPrintf(kIs64Bit ? "%016" PRIx64 " " : "%08" PRIx64 " ", it->rel_pc);
+ if (it->map.name.empty()) {
+ oss << StringPrintf("<anonymous:%" PRIx64 ">", it->map.start);
+ } else {
+ oss << it->map.name;
+ }
+ if (it->map.offset != 0) {
+ oss << StringPrintf(" (offset %" PRIx64 ")", it->map.offset);
+ }
+ oss << " (";
+ if (!it->func_name.empty()) {
+ oss << it->func_name;
+ if (it->func_offset != 0) {
+ oss << "+" << it->func_offset;
+ }
+ // Functions found using the gdb jit interface will be in an empty
+ // map that cannot be found using addr2line.
+ if (!it->map.name.empty()) {
+ try_addr2line = true;
+ }
+ } else {
+ oss << "???";
+ }
+ oss << ")";
+ }
+ LOG(ERROR) << oss.str();
+ if (try_addr2line && addr2line_path != nullptr) {
+ addr2line::Addr2line(*addr2line_path,
+ it->map.name,
+ it->pc - it->map.start,
+ LOG_STREAM(ERROR),
+ prefix,
+ &addr2line_state);
+ }
+ }
+
+ if (addr2line_state != nullptr) {
+ addr2line::Drain(0, prefix, &addr2line_state, LOG_STREAM(ERROR));
+ }
+}
+
+bool WaitForMainSigStop(const std::atomic<bool>& saw_wif_stopped_for_main) {
+ constexpr uint32_t kWaitMicros = 10;
+ constexpr size_t kMaxLoopCount = 10 * 1000 * 1000 / kWaitMicros; // 10s wait.
+
+ for (size_t loop_count = 0; !saw_wif_stopped_for_main; ++loop_count) {
+ if (loop_count > kMaxLoopCount) {
+ LOG(ERROR) << "Waited too long for main pid to stop";
+ return false;
+ }
+
+ timespec tm;
+ tm.tv_sec = 0;
+ tm.tv_nsec = kWaitMicros * 1000;
+ nanosleep(&tm, nullptr);
+ }
+ return true;
+}
+
+void DumpProcess(pid_t forked_pid, const std::atomic<bool>& saw_wif_stopped_for_main) {
+ CHECK_EQ(0, ::ptrace(PTRACE_ATTACH, forked_pid, 0, 0));
+ std::set<pid_t> tids = ptrace::PtraceSiblings(forked_pid);
+ tids.insert(forked_pid);
+
+ // Check whether we have and should use addr2line.
+ std::unique_ptr<std::string> addr2line_path = addr2line::FindAddr2line();
+ if (addr2line_path != nullptr) {
+ LOG(ERROR) << "Found addr2line at " << *addr2line_path;
+ } else {
+ LOG(ERROR) << "Did not find usable addr2line";
+ }
+ bool use_addr2line = kUseAddr2line && addr2line_path != nullptr;
+ LOG(ERROR) << (use_addr2line ? "U" : "Not u") << "sing addr2line";
+
+ if (!WaitForMainSigStop(saw_wif_stopped_for_main)) {
+ return;
+ }
+
+ std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(forked_pid));
+ if (backtrace_map == nullptr) {
+ LOG(ERROR) << "Could not create BacktraceMap";
+ return;
+ }
+
+ for (pid_t tid : tids) {
+ LOG(ERROR) << "pid: " << forked_pid << " tid: " << tid;
+ DumpThread(forked_pid,
+ tid,
+ use_addr2line ? addr2line_path.get() : nullptr,
+ " ",
+ backtrace_map.get());
+ }
+}
+
+[[noreturn]]
+void WaitMainLoop(pid_t forked_pid, std::atomic<bool>* saw_wif_stopped_for_main) {
+ for (;;) {
+ // Consider switching to waitid to not get woken up for WIFSTOPPED.
+ int status;
+ pid_t res = TEMP_FAILURE_RETRY(waitpid(forked_pid, &status, 0));
+ if (res == -1) {
+ PLOG(FATAL) << "Failure during waitpid";
+ __builtin_unreachable();
+ }
+
+ if (WIFEXITED(status)) {
+ _exit(WEXITSTATUS(status));
+ __builtin_unreachable();
+ }
+ if (WIFSIGNALED(status)) {
+ _exit(1);
+ __builtin_unreachable();
+ }
+ if (WIFSTOPPED(status)) {
+ *saw_wif_stopped_for_main = true;
+ continue;
+ }
+ if (WIFCONTINUED(status)) {
+ continue;
+ }
+
+ LOG(FATAL) << "Unknown status " << std::hex << status;
+ }
+}
+
+[[noreturn]]
+void SetupAndWait(pid_t forked_pid) {
+ timeout_signal::SignalSet signals;
+ signals.Add(timeout_signal::GetTimeoutSignal());
+ signals.Block();
+
+ std::atomic<bool> saw_wif_stopped_for_main(false);
+
+ std::thread signal_catcher([&]() {
+ signals.Block();
+ int sig = signals.Wait();
+ CHECK_EQ(sig, timeout_signal::GetTimeoutSignal());
+
+ DumpProcess(forked_pid, saw_wif_stopped_for_main);
+
+ // Don't clean up. Just kill the child and exit.
+ kill(forked_pid, SIGKILL);
+ _exit(1);
+ });
+
+ WaitMainLoop(forked_pid, &saw_wif_stopped_for_main);
+}
+
+} // namespace
+} // namespace art
+
+int main(int argc ATTRIBUTE_UNUSED, char** argv) {
+ pid_t orig_ppid = getpid();
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ if (prctl(PR_SET_PDEATHSIG, SIGTERM) == -1) {
+ _exit(1);
+ }
+
+ if (getppid() != orig_ppid) {
+ _exit(2);
+ }
+
+ execvp(argv[1], &argv[1]);
+
+ _exit(3);
+ __builtin_unreachable();
+ }
+
+ art::SetupAndWait(pid);
+ __builtin_unreachable();
+}