summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/driver/compiler_driver-inl.h19
-rw-r--r--compiler/driver/compiler_driver.cc1
-rw-r--r--compiler/driver/compiler_driver.h37
-rw-r--r--compiler/optimizing/code_generator_arm64.cc43
-rw-r--r--compiler/optimizing/code_generator_arm64.h4
-rw-r--r--compiler/optimizing/instruction_simplifier_arm.cc5
-rw-r--r--compiler/optimizing/instruction_simplifier_shared.cc4
-rw-r--r--compiler/optimizing/intrinsics_arm64.cc34
-rw-r--r--compiler/optimizing/intrinsics_arm_vixl.cc1
-rw-r--r--compiler/optimizing/intrinsics_mips.cc2
-rw-r--r--compiler/optimizing/intrinsics_mips64.cc1
-rw-r--r--compiler/optimizing/intrinsics_x86.cc1
-rw-r--r--compiler/optimizing/intrinsics_x86_64.cc1
-rw-r--r--compiler/utils/assembler_thumb_test.cc2
-rw-r--r--dex2oat/dex2oat.cc15
-rw-r--r--dex2oat/dex2oat_test.cc399
-rw-r--r--dex2oat/linker/oat_writer.cc4
-rw-r--r--dex2oat/linker/oat_writer_test.cc6
-rw-r--r--disassembler/Android.bp32
-rw-r--r--disassembler/disassembler.cc63
-rw-r--r--libartbase/base/file_utils_test.cc10
-rw-r--r--runtime/art_method-inl.h1
-rw-r--r--runtime/class_linker.cc69
-rw-r--r--runtime/class_linker.h1
-rw-r--r--runtime/gc/collector/concurrent_copying.cc8
-rw-r--r--runtime/image.cc2
-rw-r--r--runtime/interpreter/interpreter_intrinsics.cc1
-rw-r--r--runtime/interpreter/interpreter_switch_impl-inl.h4783
-rw-r--r--runtime/intrinsics_list.h1
-rw-r--r--runtime/jit/jit.cc44
-rw-r--r--runtime/jit/jit.h13
-rw-r--r--runtime/jit/jit_code_cache.cc6
-rw-r--r--runtime/native/dalvik_system_VMRuntime.cc2
-rw-r--r--runtime/native/java_lang_reflect_Field.cc9
-rw-r--r--runtime/native/sun_misc_Unsafe.cc31
-rw-r--r--runtime/native_stack_dump.cc2
-rw-r--r--runtime/oat.h1
-rw-r--r--runtime/reflection.cc22
-rw-r--r--runtime/runtime.cc15
-rw-r--r--runtime/runtime.h3
-rw-r--r--runtime/thread.cc143
-rw-r--r--runtime/thread.h7
-rw-r--r--runtime/well_known_classes.cc2
-rw-r--r--runtime/well_known_classes.h1
-rw-r--r--test/004-ThreadStress/src-art/Main.java31
-rwxr-xr-xtest/099-vmdebug/check2
-rwxr-xr-xtest/143-string-value/check2
-rw-r--r--test/160-read-barrier-stress/src/Main.java17
-rw-r--r--test/1958-transform-try-jit/expected.txt2
-rw-r--r--test/1958-transform-try-jit/info.txt5
-rwxr-xr-xtest/1958-transform-try-jit/run17
-rw-r--r--test/1958-transform-try-jit/src/Main.java21
-rw-r--r--test/1958-transform-try-jit/src/art/Redefinition.java91
-rw-r--r--test/1958-transform-try-jit/src/art/Test1958.java106
-rw-r--r--test/527-checker-array-access-split/src/Main.java69
-rw-r--r--test/580-crc32/expected.txt0
-rw-r--r--test/580-crc32/info.txt1
-rw-r--r--test/580-crc32/src/Main.java131
-rw-r--r--test/624-checker-stringops/smali/Smali.smali4
-rw-r--r--test/624-checker-stringops/src/Main.java4
-rw-r--r--test/911-get-stack-trace/expected.txt16
-rw-r--r--test/913-heaps/expected.txt52
-rw-r--r--test/Android.run-test.mk1
-rwxr-xr-xtest/etc/run-test-jar44
-rwxr-xr-xtest/run-test13
-rwxr-xr-xtools/build_linux_bionic_tests.sh101
-rw-r--r--tools/timeout_dumper/Android.bp39
-rw-r--r--tools/timeout_dumper/timeout_dumper.cc609
68 files changed, 4462 insertions, 2767 deletions
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 294072d7e7..792f508199 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -99,25 +99,6 @@ inline std::pair<bool, bool> CompilerDriver::IsFastInstanceField(
return std::make_pair(fast_get, fast_put);
}
-inline ArtMethod* CompilerDriver::ResolveMethod(
- ScopedObjectAccess& soa,
- Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader,
- const DexCompilationUnit* mUnit,
- uint32_t method_idx,
- InvokeType invoke_type) {
- DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get());
- ArtMethod* resolved_method =
- mUnit->GetClassLinker()->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
- method_idx, dex_cache, class_loader, /* referrer */ nullptr, invoke_type);
- if (UNLIKELY(resolved_method == nullptr)) {
- DCHECK(soa.Self()->IsExceptionPending());
- // Clean up any exception left by type resolution.
- soa.Self()->ClearException();
- }
- return resolved_method;
-}
-
inline VerificationResults* CompilerDriver::GetVerificationResults() const {
DCHECK(Runtime::Current()->IsAotCompiler());
return verification_results_;
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index f8e2dff25a..f7bff4d336 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -258,7 +258,6 @@ CompilerDriver::CompilerDriver(
had_hard_verifier_failure_(false),
parallel_thread_count_(thread_count),
stats_(new AOTCompilationStats),
- compiler_context_(nullptr),
compiled_method_storage_(swap_fd),
max_arena_alloc_(0),
dex_to_dex_compiler_(this) {
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index b0f2dac683..94efdd8304 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -145,7 +145,6 @@ class CompilerDriver {
bool GetCompiledClass(const ClassReference& ref, ClassStatus* status) const;
CompiledMethod* GetCompiledMethod(MethodReference ref) const;
- size_t GetNonRelativeLinkerPatchCount() const;
// Add a compiled method.
void AddCompiledMethod(const MethodReference& method_ref, CompiledMethod* const compiled_method);
CompiledMethod* RemoveCompiledMethod(const MethodReference& method_ref);
@@ -180,16 +179,6 @@ class CompilerDriver {
uint16_t field_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Resolve a method. Returns null on failure, including incompatible class change.
- ArtMethod* ResolveMethod(
- ScopedObjectAccess& soa,
- Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader,
- const DexCompilationUnit* mUnit,
- uint32_t method_idx,
- InvokeType invoke_type)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
void ProcessedInstanceField(bool resolved);
void ProcessedStaticField(bool resolved, bool local);
@@ -208,14 +197,6 @@ class CompilerDriver {
const VerifiedMethod* GetVerifiedMethod(const DexFile* dex_file, uint32_t method_idx) const;
bool IsSafeCast(const DexCompilationUnit* mUnit, uint32_t dex_pc);
- void SetCompilerContext(void* compiler_context) {
- compiler_context_ = compiler_context;
- }
-
- void* GetCompilerContext() const {
- return compiler_context_;
- }
-
size_t GetThreadCount() const {
return parallel_thread_count_;
}
@@ -358,6 +339,12 @@ class CompilerDriver {
void FreeThreadPools();
void CheckThreadPools();
+ // Resolve const string literals that are loaded from dex code. If only_startup_strings is
+ // specified, only methods that are marked startup in the profile are resolved.
+ void ResolveConstStrings(const std::vector<const DexFile*>& dex_files,
+ bool only_startup_strings,
+ /*inout*/ TimingLogger* timings);
+
const CompilerOptions* const compiler_options_;
VerificationResults* const verification_results_;
@@ -372,13 +359,6 @@ class CompilerDriver {
typedef AtomicDexRefMap<MethodReference, CompiledMethod*> MethodTable;
- private:
- // Resolve const string literals that are loaded from dex code. If only_startup_strings is
- // specified, only methods that are marked startup in the profile are resolved.
- void ResolveConstStrings(const std::vector<const DexFile*>& dex_files,
- bool only_startup_strings,
- /*inout*/ TimingLogger* timings);
-
// All method references that this compiler has compiled.
MethodTable compiled_methods_;
@@ -407,11 +387,6 @@ class CompilerDriver {
class AOTCompilationStats;
std::unique_ptr<AOTCompilationStats> stats_;
- typedef void (*CompilerCallbackFn)(CompilerDriver& driver);
- typedef MutexLock* (*CompilerMutexLockFn)(CompilerDriver& driver);
-
- void* compiler_context_;
-
CompiledMethodStorage compiled_method_storage_;
size_t max_arena_alloc_;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index a9acf90762..48b50ea5d6 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2319,9 +2319,10 @@ void LocationsBuilderARM64::VisitArrayGet(HArrayGet* instruction) {
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 @@ void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) {
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 @@ void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) {
// 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 @@ void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) {
/* 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 @@ void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) {
// 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 @@ void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) {
// 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 @@ void CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier(HInstruction* ins
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 @@ void CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier(Location ref,
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 1ba58b1a9f..ada5742fc0 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -694,11 +694,11 @@ class CodeGeneratorARM64 : public CodeGenerator {
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 24fbb6cb4c..f968c19cf9 100644
--- a/compiler/optimizing/instruction_simplifier_arm.cc
+++ b/compiler/optimizing/instruction_simplifier_arm.cc
@@ -202,6 +202,11 @@ void InstructionSimplifierArmVisitor::VisitArrayGet(HArrayGet* instruction) {
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 ccdcb3532d..0f30f662cd 100644
--- a/compiler/optimizing/instruction_simplifier_shared.cc
+++ b/compiler/optimizing/instruction_simplifier_shared.cc
@@ -245,11 +245,11 @@ bool TryExtractArrayAccessAddress(HInstruction* access,
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 7684dc79f2..6d04b0e9d9 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -2916,6 +2916,40 @@ void IntrinsicLocationsBuilderARM64::VisitReachabilityFence(HInvoke* invoke) {
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 38e4c8968a..0c463a280e 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -3059,6 +3059,7 @@ UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathRoundDouble) // Could be done by changing
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 6f7f5e49c1..21fb7d7f1c 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -2696,6 +2696,8 @@ UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeCASLong)
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 2eb252908c..4b86f5d423 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -2346,6 +2346,7 @@ void IntrinsicCodeGeneratorMIPS64::VisitReachabilityFence(HInvoke* invoke ATTRIB
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 3504d7a6f8..6dd4681847 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -2967,6 +2967,7 @@ UNIMPLEMENTED_INTRINSIC(X86, IntegerHighestOneBit)
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 96f6eaaf33..7db26dc9be 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -2732,6 +2732,7 @@ void IntrinsicCodeGeneratorX86_64::VisitReachabilityFence(HInvoke* invoke ATTRIB
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 053e202523..3d262969a4 100644
--- a/compiler/utils/assembler_thumb_test.cc
+++ b/compiler/utils/assembler_thumb_test.cc
@@ -125,7 +125,7 @@ void DumpAndCheck(std::vector<uint8_t>& code, const char* testname, const char*
// 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.cc b/dex2oat/dex2oat.cc
index db610f1f4f..50785c5fce 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1045,8 +1045,8 @@ class Dex2Oat final {
}
void InsertCompileOptions(int argc, char** argv) {
- std::ostringstream oss;
if (!avoid_storing_invocation_) {
+ std::ostringstream oss;
for (int i = 0; i < argc; ++i) {
if (i > 0) {
oss << ' ';
@@ -1055,9 +1055,9 @@ class Dex2Oat final {
}
key_value_store_->Put(OatHeader::kDex2OatCmdLineKey, oss.str());
oss.str(""); // Reset.
+ oss << kRuntimeISA;
+ key_value_store_->Put(OatHeader::kDex2OatHostKey, oss.str());
}
- oss << kRuntimeISA;
- key_value_store_->Put(OatHeader::kDex2OatHostKey, oss.str());
key_value_store_->Put(
OatHeader::kDebuggableKey,
compiler_options_->debuggable_ ? OatHeader::kTrueValue : OatHeader::kFalseValue);
@@ -1513,15 +1513,6 @@ class Dex2Oat final {
std::vector<gc::space::ImageSpace*> image_spaces =
Runtime::Current()->GetHeap()->GetBootImageSpaces();
image_file_location_oat_checksum_ = image_spaces[0]->GetImageHeader().GetOatChecksum();
- // Store the boot image filename(s).
- std::vector<std::string> image_filenames;
- for (const gc::space::ImageSpace* image_space : image_spaces) {
- image_filenames.push_back(image_space->GetImageFilename());
- }
- std::string image_file_location = android::base::Join(image_filenames, ':');
- if (!image_file_location.empty()) {
- key_value_store_->Put(OatHeader::kImageLocationKey, image_file_location);
- }
} else {
image_file_location_oat_checksum_ = 0u;
}
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index d22b301585..baeebd9371 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 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
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 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
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 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
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 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
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 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
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 @@ class Dex2oatSwapTest : public Dex2oatTest {
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 @@ class Dex2oatVeryLargeTest : public Dex2oatTest {
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 @@ class Dex2oatLayoutTest : public Dex2oatTest {
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 @@ class Dex2oatUnquickenTest : public Dex2oatTest {
{
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 @@ class Dex2oatUnquickenTest : public Dex2oatTest {
{
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 @@ class Dex2oatUnquickenTest : public Dex2oatTest {
{
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 @@ class Dex2oatWatchdogTest : public Dex2oatTest {
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 @@ class Dex2oatClassLoaderContextTest : public Dex2oatTest {
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 @@ TEST_F(Dex2oatClassLoaderContextTest, ContextWithStrippedDexFilesBackedByOdex) {
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 @@ TEST_F(Dex2oatDeterminism, UnloadCompile) {
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 @@ TEST_F(Dex2oatDeterminism, UnloadCompile) {
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 @@ TEST_F(Dex2oatDedupeCode, DedupeTest) {
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 @@ TEST_F(Dex2oatTest, UncompressedTest) {
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 @@ TEST_F(Dex2oatTest, CompactDexGenerationFailure) {
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 @@ TEST_F(Dex2oatTest, CompactDexGenerationFailureMultiDex) {
}
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_F(Dex2oatTest, StderrLoggerOutput) {
// 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_F(Dex2oatTest, VerifyCompilationReason) {
// 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_F(Dex2oatTest, VerifyNoCompilationReason) {
// 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 @@ TEST_F(Dex2oatTest, DontExtract) {
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 @@ TEST_F(Dex2oatTest, DontExtract) {
}
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 @@ TEST_F(Dex2oatTest, QuickenedInput) {
{
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 @@ TEST_F(Dex2oatTest, QuickenedInput) {
{
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 @@ TEST_F(Dex2oatTest, AppImageNoProfile) {
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 @@ TEST_F(Dex2oatTest, AppImageResolveStrings) {
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 @@ TEST_F(Dex2oatClassLoaderContextTest, StoredClassLoaderContext) {
}
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/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 01c24fc197..28287bd083 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -766,10 +766,6 @@ void OatWriter::PrepareLayout(MultiOatRelativePatcher* relative_patcher) {
bss_start_ = (bss_size_ != 0u) ? RoundUp(oat_size_, kPageSize) : 0u;
CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
- if (GetCompilerOptions().IsBootImage()) {
- CHECK_EQ(image_writer_ != nullptr,
- oat_header_->GetStoreValueByKey(OatHeader::kImageLocationKey) == nullptr);
- }
write_state_ = WriteState::kWriteRoData;
}
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 83fb17cf05..af02bfc8bd 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -394,7 +394,6 @@ TEST_F(OatTest, WriteRead) {
ScratchFile tmp_base, tmp_oat(tmp_base, ".oat"), tmp_vdex(tmp_base, ".vdex");
SafeMap<std::string, std::string> key_value_store;
- key_value_store.Put(OatHeader::kImageLocationKey, "lue.art");
bool success = WriteElf(tmp_vdex.GetFile(),
tmp_oat.GetFile(),
class_linker->GetBootClassPath(),
@@ -418,7 +417,6 @@ TEST_F(OatTest, WriteRead) {
ASSERT_TRUE(oat_header.IsValid());
ASSERT_EQ(class_linker->GetBootClassPath().size(), oat_header.GetDexFileCount()); // core
ASSERT_EQ(42U, oat_header.GetImageFileLocationOatChecksum());
- ASSERT_EQ("lue.art", std::string(oat_header.GetStoreValueByKey(OatHeader::kImageLocationKey)));
ASSERT_TRUE(java_lang_dex_file_ != nullptr);
const DexFile& dex_file = *java_lang_dex_file_;
@@ -517,7 +515,6 @@ TEST_F(OatTest, EmptyTextSection) {
ScratchFile tmp_base, tmp_oat(tmp_base, ".oat"), tmp_vdex(tmp_base, ".vdex");
SafeMap<std::string, std::string> key_value_store;
- key_value_store.Put(OatHeader::kImageLocationKey, "test.art");
bool success = WriteElf(tmp_vdex.GetFile(),
tmp_oat.GetFile(),
dex_files,
@@ -584,7 +581,6 @@ void OatTest::TestDexFileInput(bool verify, bool low_4gb, bool use_profile) {
ScratchFile tmp_base, tmp_oat(tmp_base, ".oat"), tmp_vdex(tmp_base, ".vdex");
SafeMap<std::string, std::string> key_value_store;
- key_value_store.Put(OatHeader::kImageLocationKey, "test.art");
std::unique_ptr<ProfileCompilationInfo>
profile_compilation_info(use_profile ? new ProfileCompilationInfo() : nullptr);
success = WriteElf(tmp_vdex.GetFile(),
@@ -714,7 +710,6 @@ void OatTest::TestZipFileInput(bool verify) {
ASSERT_TRUE(success) << strerror(errno);
SafeMap<std::string, std::string> key_value_store;
- key_value_store.Put(OatHeader::kImageLocationKey, "test.art");
{
// Test using the AddDexFileSource() interface with the zip file.
std::vector<const char*> input_filenames = { zip_file.GetFilename().c_str() };
@@ -831,7 +826,6 @@ void OatTest::TestZipFileInputWithEmptyDex() {
ASSERT_TRUE(success) << strerror(errno);
SafeMap<std::string, std::string> key_value_store;
- key_value_store.Put(OatHeader::kImageLocationKey, "test.art");
std::vector<const char*> input_filenames = { zip_file.GetFilename().c_str() };
ScratchFile oat_file, vdex_file(oat_file, ".vdex");
std::unique_ptr<ProfileCompilationInfo> profile_compilation_info(new ProfileCompilationInfo());
diff --git a/disassembler/Android.bp b/disassembler/Android.bp
index 241b191641..a7c1802515 100644
--- a/disassembler/Android.bp
+++ b/disassembler/Android.bp
@@ -20,11 +20,39 @@ art_cc_defaults {
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 262e8152fb..aee690e036 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(DisassemblerOptions* disassembler_options)
}
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 f7c9c5e264..c9173076d1 100644
--- a/libartbase/base/file_utils_test.cc
+++ b/libartbase/base/file_utils_test.cc
@@ -83,11 +83,15 @@ TEST_F(FileUtilsTest, GetAndroidRootSafe) {
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 e9c17eeab5..d8da9129ed 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -402,6 +402,7 @@ inline hiddenapi::ApiList ArtMethod::GetHiddenApiAccessFlags()
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 9ba52c429d..67513f9ce6 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -965,9 +965,6 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) {
runtime->GetOatFileManager().RegisterImageOatFiles(spaces);
DCHECK(!oat_files.empty());
const OatHeader& default_oat_header = oat_files[0]->GetOatHeader();
- const char* image_file_location = oat_files[0]->GetOatHeader().
- GetStoreValueByKey(OatHeader::kImageLocationKey);
- CHECK(image_file_location == nullptr || *image_file_location == 0);
quick_resolution_trampoline_ = default_oat_header.GetQuickResolutionTrampoline();
quick_imt_conflict_trampoline_ = default_oat_header.GetQuickImtConflictTrampoline();
quick_generic_jni_trampoline_ = default_oat_header.GetQuickGenericJniTrampoline();
@@ -2034,11 +2031,15 @@ bool ClassLinker::AddImageSpace(
}
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) {
@@ -4011,33 +4012,31 @@ ObjPtr<mirror::Class> ClassLinker::CreateArrayClass(Thread* self,
return existing;
}
-ObjPtr<mirror::Class> ClassLinker::FindPrimitiveClass(char type) {
- ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots = GetClassRoots();
+ObjPtr<mirror::Class> ClassLinker::LookupPrimitiveClass(char type) {
+ ClassRoot class_root;
switch (type) {
- case 'B':
- return GetClassRoot(ClassRoot::kPrimitiveByte, class_roots);
- case 'C':
- return GetClassRoot(ClassRoot::kPrimitiveChar, class_roots);
- case 'D':
- return GetClassRoot(ClassRoot::kPrimitiveDouble, class_roots);
- case 'F':
- return GetClassRoot(ClassRoot::kPrimitiveFloat, class_roots);
- case 'I':
- return GetClassRoot(ClassRoot::kPrimitiveInt, class_roots);
- case 'J':
- return GetClassRoot(ClassRoot::kPrimitiveLong, class_roots);
- case 'S':
- return GetClassRoot(ClassRoot::kPrimitiveShort, class_roots);
- case 'Z':
- return GetClassRoot(ClassRoot::kPrimitiveBoolean, class_roots);
- case 'V':
- return GetClassRoot(ClassRoot::kPrimitiveVoid, class_roots);
+ case 'B': class_root = ClassRoot::kPrimitiveByte; break;
+ case 'C': class_root = ClassRoot::kPrimitiveChar; break;
+ case 'D': class_root = ClassRoot::kPrimitiveDouble; break;
+ case 'F': class_root = ClassRoot::kPrimitiveFloat; break;
+ case 'I': class_root = ClassRoot::kPrimitiveInt; break;
+ case 'J': class_root = ClassRoot::kPrimitiveLong; break;
+ case 'S': class_root = ClassRoot::kPrimitiveShort; break;
+ case 'Z': class_root = ClassRoot::kPrimitiveBoolean; break;
+ case 'V': class_root = ClassRoot::kPrimitiveVoid; break;
default:
- break;
+ return nullptr;
}
- std::string printable_type(PrintableChar(type));
- ThrowNoClassDefFoundError("Not a primitive type: %s", printable_type.c_str());
- return nullptr;
+ return GetClassRoot(class_root, this);
+}
+
+ObjPtr<mirror::Class> ClassLinker::FindPrimitiveClass(char type) {
+ ObjPtr<mirror::Class> result = LookupPrimitiveClass(type);
+ if (UNLIKELY(result == nullptr)) {
+ std::string printable_type(PrintableChar(type));
+ ThrowNoClassDefFoundError("Not a primitive type: %s", printable_type.c_str());
+ }
+ return result;
}
ObjPtr<mirror::Class> ClassLinker::InsertClass(const char* descriptor,
@@ -8033,7 +8032,7 @@ ObjPtr<mirror::Class> ClassLinker::DoLookupResolvedType(dex::TypeIndex type_idx,
if (descriptor[1] == '\0') {
// only the descriptors of primitive types should be 1 character long, also avoid class lookup
// for primitive classes that aren't backed by dex files.
- type = FindPrimitiveClass(descriptor[0]);
+ type = LookupPrimitiveClass(descriptor[0]);
} else {
Thread* const self = Thread::Current();
DCHECK(self != nullptr);
@@ -8562,7 +8561,7 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForField(
switch (handle_type) {
case DexFile::MethodHandleType::kStaticPut: {
method_params->Set(0, target_field->ResolveType());
- return_type = hs.NewHandle(FindPrimitiveClass('V'));
+ return_type = hs.NewHandle(GetClassRoot(ClassRoot::kPrimitiveVoid, this));
break;
}
case DexFile::MethodHandleType::kStaticGet: {
@@ -8572,7 +8571,7 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForField(
case DexFile::MethodHandleType::kInstancePut: {
method_params->Set(0, target_field->GetDeclaringClass());
method_params->Set(1, target_field->ResolveType());
- return_type = hs.NewHandle(FindPrimitiveClass('V'));
+ return_type = hs.NewHandle(GetClassRoot(ClassRoot::kPrimitiveVoid, this));
break;
}
case DexFile::MethodHandleType::kInstanceGet: {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 7afd575607..60e68d5f78 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -196,6 +196,7 @@ class ClassLinker {
REQUIRES(!Locks::classlinker_classes_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
+ ObjPtr<mirror::Class> LookupPrimitiveClass(char type) REQUIRES_SHARED(Locks::mutator_lock_);
ObjPtr<mirror::Class> FindPrimitiveClass(char type) REQUIRES_SHARED(Locks::mutator_lock_);
void DumpForSigQuit(std::ostream& os) REQUIRES(!Locks::classlinker_classes_lock_);
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index e0bbf43622..26a8d1310b 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -1658,7 +1658,9 @@ inline void ConcurrentCopying::ProcessMarkStackRef(mirror::Object* to_ref) {
<< " 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 @@ inline void ConcurrentCopying::ProcessMarkStackRef(mirror::Object* to_ref) {
<< " 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 376742afbc..59ac283779 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 17b3cd45aa..24a026a92e 100644
--- a/runtime/interpreter/interpreter_intrinsics.cc
+++ b/runtime/interpreter/interpreter_intrinsics.cc
@@ -558,6 +558,7 @@ bool MterpHandleIntrinsic(ShadowFrame* shadow_frame,
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 48e1728c8b..71b2336cb0 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 @@ namespace interpreter {
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 @@ namespace interpreter {
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 @@ namespace interpreter {
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 @@ namespace interpreter {
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 @@ namespace interpreter {
#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 @@ namespace interpreter {
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 @@ NO_INLINE static bool SendMethodExitEvents(Thread* self,
}
}
+// 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 @@ ATTRIBUTE_NO_SANITIZE_ADDRESS void ExecuteSwitchImplCpp(SwitchImplContext* ctx)
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 @@ ATTRIBUTE_NO_SANITIZE_ADDRESS void ExecuteSwitchImplCpp(SwitchImplContext* ctx)
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;
- }
- 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);
- }
- } while (!interpret_one_instruction);
- // Record where we stopped.
- shadow_frame.SetDexPC(inst->GetDexPc(insns));
- ctx->result = result_register;
- return;
+#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; \
+ }
+DEX_INSTRUCTION_LIST(OPCODE_CASE)
+#undef OPCODE_CASE
+ }
+ 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 2f91f5dfe0..093dd7f400 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/jit/jit.cc b/runtime/jit/jit.cc
index e876a1bc89..d67d9dced8 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -60,7 +60,6 @@ void* (*Jit::jit_load_)(bool*) = nullptr;
void (*Jit::jit_unload_)(void*) = nullptr;
bool (*Jit::jit_compile_method_)(void*, ArtMethod*, Thread*, bool) = nullptr;
void (*Jit::jit_types_loaded_)(void*, mirror::Class**, size_t count) = nullptr;
-bool Jit::generate_debug_info_ = false;
struct StressModeHelper {
DECLARE_RUNTIME_DEBUG_FLAG(kSlowMode);
@@ -176,11 +175,24 @@ Jit::Jit(JitCodeCache* code_cache, JitOptions* options)
lock_("JIT memory use lock") {}
Jit* Jit::Create(JitCodeCache* code_cache, JitOptions* options) {
- CHECK(jit_compiler_handle_ != nullptr) << "Jit::LoadLibrary() needs to be called first";
- std::unique_ptr<Jit> jit(new Jit(code_cache, options));
+ if (jit_load_ == nullptr) {
+ LOG(WARNING) << "Not creating JIT: library not loaded";
+ return nullptr;
+ }
+ bool will_generate_debug_symbols = false;
+ jit_compiler_handle_ = (jit_load_)(&will_generate_debug_symbols);
if (jit_compiler_handle_ == nullptr) {
+ LOG(WARNING) << "Not creating JIT: failed to allocate a compiler";
return nullptr;
}
+ std::unique_ptr<Jit> jit(new Jit(code_cache, options));
+ jit->generate_debug_info_ = will_generate_debug_symbols;
+
+ // With 'perf', we want a 1-1 mapping between an address and a method.
+ // We aren't able to keep method pointers live during the instrumentation method entry trampoline
+ // so we will just disable jit-gc if we are doing that.
+ code_cache->SetGarbageCollectCode(!jit->generate_debug_info_ &&
+ !Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled());
VLOG(jit) << "JIT created with initial_capacity="
<< PrettySize(options->GetCodeCacheInitialCapacity())
@@ -195,7 +207,7 @@ Jit* Jit::Create(JitCodeCache* code_cache, JitOptions* options) {
return jit.release();
}
-bool Jit::BindCompilerMethods(std::string* error_msg) {
+bool Jit::LoadCompilerLibrary(std::string* error_msg) {
jit_library_handle_ = dlopen(
kIsDebugBuild ? "libartd-compiler.so" : "libart-compiler.so", RTLD_NOW);
if (jit_library_handle_ == nullptr) {
@@ -234,23 +246,6 @@ bool Jit::BindCompilerMethods(std::string* error_msg) {
return true;
}
-bool Jit::LoadCompiler(std::string* error_msg) {
- if (jit_library_handle_ == nullptr && !BindCompilerMethods(error_msg)) {
- return false;
- }
- bool will_generate_debug_symbols = false;
- VLOG(jit) << "Calling JitLoad interpreter_only="
- << Runtime::Current()->GetInstrumentation()->InterpretOnly();
- jit_compiler_handle_ = (jit_load_)(&will_generate_debug_symbols);
- if (jit_compiler_handle_ == nullptr) {
- dlclose(jit_library_handle_);
- *error_msg = "JIT couldn't load compiler";
- return false;
- }
- generate_debug_info_ = will_generate_debug_symbols;
- return true;
-}
-
bool Jit::CompileMethod(ArtMethod* method, Thread* self, bool osr) {
DCHECK(Runtime::Current()->UseJitCompilation());
DCHECK(!method->IsRuntimeMethod());
@@ -300,11 +295,6 @@ bool Jit::CompileMethod(ArtMethod* method, Thread* self, bool osr) {
return success;
}
-bool Jit::ShouldGenerateDebugInfo() {
- CHECK(CompilerIsLoaded());
- return generate_debug_info_;
-}
-
void Jit::CreateThreadPool() {
// There is a DCHECK in the 'AddSamples' method to ensure the tread pool
// is not null when we instrument.
@@ -385,7 +375,7 @@ void Jit::NewTypeLoadedIfUsingJit(mirror::Class* type) {
return;
}
jit::Jit* jit = Runtime::Current()->GetJit();
- if (generate_debug_info_) {
+ if (jit->generate_debug_info_) {
DCHECK(jit->jit_types_loaded_ != nullptr);
jit->jit_types_loaded_(jit->jit_compiler_handle_, &type, 1);
}
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index b0ea19b303..46b0762629 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -282,13 +282,8 @@ class Jit {
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Load and initialize compiler.
- static bool LoadCompiler(std::string* error_msg);
-
- static bool CompilerIsLoaded() { return jit_compiler_handle_ != nullptr; }
-
- // Return whether debug info should be generated. Requires LoadCompiler() to have been called.
- static bool ShouldGenerateDebugInfo();
+ // Load the compiler library.
+ static bool LoadCompilerLibrary(std::string* error_msg);
ThreadPool* GetThreadPool() const {
return thread_pool_.get();
@@ -313,8 +308,8 @@ class Jit {
static bool (*jit_compile_method_)(void*, ArtMethod*, Thread*, bool);
static void (*jit_types_loaded_)(void*, mirror::Class**, size_t count);
- // We make this static to simplify the interaction with libart-compiler.so.
- static bool generate_debug_info_;
+ // Whether we should generate debug info when compiling.
+ bool generate_debug_info_;
// JIT resources owned by runtime.
jit::JitCodeCache* const code_cache_;
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index a15a9be6f5..359f97e705 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -436,12 +436,6 @@ JitCodeCache::JitCodeCache(MemMap&& data_pages,
SetFootprintLimit(current_capacity_);
}
- // With 'perf', we want a 1-1 mapping between an address and a method.
- // We aren't able to keep method pointers live during the instrumentation method entry trampoline
- // so we will just disable jit-gc if we are doing that.
- garbage_collect_code_ = !Jit::ShouldGenerateDebugInfo() &&
- !Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled();
-
VLOG(jit) << "Created jit code cache: initial data size="
<< PrettySize(initial_data_capacity)
<< ", initial code size="
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 32b88e6fa1..49b71cd801 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -371,7 +371,7 @@ static void PreloadDexCachesResolveType(Thread* self,
const char* class_name = dex_file->StringByTypeIdx(type_idx);
ClassLinker* linker = Runtime::Current()->GetClassLinker();
ObjPtr<mirror::Class> klass = (class_name[1] == '\0')
- ? linker->FindPrimitiveClass(class_name[0])
+ ? linker->LookupPrimitiveClass(class_name[0])
: linker->LookupClass(self, class_name, nullptr);
if (klass == nullptr) {
return;
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index b9ac88d999..f21ded9c23 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -334,14 +334,15 @@ static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject j
return;
}
ObjPtr<mirror::Class> field_type;
- const char* field_type_desciptor = f->GetArtField()->GetTypeDescriptor();
- Primitive::Type field_prim_type = Primitive::GetType(field_type_desciptor[0]);
+ const char* field_type_descriptor = f->GetArtField()->GetTypeDescriptor();
+ Primitive::Type field_prim_type = Primitive::GetType(field_type_descriptor[0]);
if (field_prim_type == Primitive::kPrimNot) {
field_type = f->GetType();
- DCHECK(field_type != nullptr);
} else {
- field_type = Runtime::Current()->GetClassLinker()->FindPrimitiveClass(field_type_desciptor[0]);
+ field_type =
+ Runtime::Current()->GetClassLinker()->LookupPrimitiveClass(field_type_descriptor[0]);
}
+ DCHECK(field_type != nullptr) << field_type_descriptor;
// We now don't expect suspension unless an exception is thrown.
// Unbox the value, if necessary.
ObjPtr<mirror::Object> boxed_value = soa.Decode<mirror::Object>(javaValue);
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index e021b77dae..a739c2d16e 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 @@ static void Unsafe_fullFence(JNIEnv*, jobject) {
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 @@ static JNINativeMethod gMethods[] = {
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/native_stack_dump.cc b/runtime/native_stack_dump.cc
index 10f589831f..88adad0f91 100644
--- a/runtime/native_stack_dump.cc
+++ b/runtime/native_stack_dump.cc
@@ -373,7 +373,7 @@ void DumpNativeStack(std::ostream& os,
}
os << std::endl;
if (try_addr2line && use_addr2line) {
- Addr2line(it->map.name, it->pc - it->map.start, os, prefix, &addr2line_state);
+ Addr2line(it->map.name, it->rel_pc, os, prefix, &addr2line_state);
}
}
diff --git a/runtime/oat.h b/runtime/oat.h
index 2a6d738178..b07294adeb 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -34,7 +34,6 @@ class PACKED(4) OatHeader {
// Last oat version changed reason: Remove interpreter alt tables.
static constexpr uint8_t kOatVersion[] = { '1', '6', '3', '\0' };
- static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
static constexpr const char* kDex2OatHostKey = "dex2oat-host";
static constexpr const char* kDebuggableKey = "debuggable";
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 646de757e0..80118365f0 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -886,32 +886,31 @@ static bool UnboxPrimitive(ObjPtr<mirror::Object> o,
JValue boxed_value;
ObjPtr<mirror::Class> klass = o->GetClass();
- ObjPtr<mirror::Class> src_class = nullptr;
- ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
+ Primitive::Type primitive_type;
ArtField* primitive_field = &klass->GetIFieldsPtr()->At(0);
if (klass->DescriptorEquals("Ljava/lang/Boolean;")) {
- src_class = class_linker->FindPrimitiveClass('Z');
+ primitive_type = Primitive::kPrimBoolean;
boxed_value.SetZ(primitive_field->GetBoolean(o));
} else if (klass->DescriptorEquals("Ljava/lang/Byte;")) {
- src_class = class_linker->FindPrimitiveClass('B');
+ primitive_type = Primitive::kPrimByte;
boxed_value.SetB(primitive_field->GetByte(o));
} else if (klass->DescriptorEquals("Ljava/lang/Character;")) {
- src_class = class_linker->FindPrimitiveClass('C');
+ primitive_type = Primitive::kPrimChar;
boxed_value.SetC(primitive_field->GetChar(o));
} else if (klass->DescriptorEquals("Ljava/lang/Float;")) {
- src_class = class_linker->FindPrimitiveClass('F');
+ primitive_type = Primitive::kPrimFloat;
boxed_value.SetF(primitive_field->GetFloat(o));
} else if (klass->DescriptorEquals("Ljava/lang/Double;")) {
- src_class = class_linker->FindPrimitiveClass('D');
+ primitive_type = Primitive::kPrimDouble;
boxed_value.SetD(primitive_field->GetDouble(o));
} else if (klass->DescriptorEquals("Ljava/lang/Integer;")) {
- src_class = class_linker->FindPrimitiveClass('I');
+ primitive_type = Primitive::kPrimInt;
boxed_value.SetI(primitive_field->GetInt(o));
} else if (klass->DescriptorEquals("Ljava/lang/Long;")) {
- src_class = class_linker->FindPrimitiveClass('J');
+ primitive_type = Primitive::kPrimLong;
boxed_value.SetJ(primitive_field->GetLong(o));
} else if (klass->DescriptorEquals("Ljava/lang/Short;")) {
- src_class = class_linker->FindPrimitiveClass('S');
+ primitive_type = Primitive::kPrimShort;
boxed_value.SetS(primitive_field->GetShort(o));
} else {
std::string temp;
@@ -923,7 +922,8 @@ static bool UnboxPrimitive(ObjPtr<mirror::Object> o,
}
return ConvertPrimitiveValue(unbox_for_result,
- src_class->GetPrimitiveType(), dst_class->GetPrimitiveType(),
+ primitive_type,
+ dst_class->GetPrimitiveType(),
boxed_value, unboxed_value);
}
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 34b84f52c6..e5772666d1 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -789,12 +789,8 @@ bool Runtime::Start() {
if (!safe_mode_ && (jit_options_->UseJitCompilation() || jit_options_->GetSaveProfilingInfo())) {
// Try to load compiler pre zygote to reduce PSS. b/27744947
std::string error_msg;
- if (!jit::Jit::LoadCompiler(&error_msg)) {
+ if (!jit::Jit::LoadCompilerLibrary(&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 @@ void Runtime::InitNonZygoteOrPostFork(
}
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 @@ void Runtime::SetSentinel(mirror::Object* sentinel) {
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 4fb0d2ede0..be5b3c119c 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -691,6 +691,9 @@ class Runtime {
// 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 dda3b82612..66e852a216 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 @@ void Thread::AssertHasDeoptimizationContext() {
<< "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,
+ &timespec,
+ 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,
+ &timespec,
+ 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 @@ void* Thread::CreateCallback(void* arg) {
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 @@ Thread::Thread(bool daemon)
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 @@ bool Thread::IsInterrupted() {
}
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 941867ce2d..b304cef74d 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -581,6 +581,11 @@ class Thread {
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 @@ class Thread {
// 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 206418fbc6..94faa626f6 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -128,6 +128,7 @@ jfieldID WellKnownClasses::java_lang_Thread_lock;
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 @@ void WellKnownClasses::Init(JNIEnv* env) {
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 ce5ab1df84..8c85228dfc 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -137,6 +137,7 @@ struct WellKnownClasses {
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 b8bfafb2d3..e7178523d3 100644
--- a/test/004-ThreadStress/src-art/Main.java
+++ b/test/004-ThreadStress/src-art/Main.java
@@ -53,6 +53,7 @@ import java.util.concurrent.locks.LockSupport;
// -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 @@ public class Main implements Runnable {
}
}
- 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 @@ public class Main implements Runnable {
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 @@ public class Main implements Runnable {
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 @@ public class Main implements Runnable {
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 @@ public class Main implements Runnable {
}
// 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 @@ public class Main implements Runnable {
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 d124ce8cfd..6a3fed55ba 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 2a3476c2ab..b5e51cecad 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 5865094002..5e49e664be 100644
--- a/test/160-read-barrier-stress/src/Main.java
+++ b/test/160-read-barrier-stress/src/Main.java
@@ -121,6 +121,23 @@ public class Main {
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/1958-transform-try-jit/expected.txt b/test/1958-transform-try-jit/expected.txt
new file mode 100644
index 0000000000..8cfaea2be0
--- /dev/null
+++ b/test/1958-transform-try-jit/expected.txt
@@ -0,0 +1,2 @@
+Before redefinition: hello
+After redefinition: Goodbye
diff --git a/test/1958-transform-try-jit/info.txt b/test/1958-transform-try-jit/info.txt
new file mode 100644
index 0000000000..0bf5ee53ee
--- /dev/null
+++ b/test/1958-transform-try-jit/info.txt
@@ -0,0 +1,5 @@
+Tests that JVMTI transformation seems to work even when we try to get a method
+inlined by the jit.
+
+Note this test deliberately avoids any internal libart calls so it can be
+included in CTS.
diff --git a/test/1958-transform-try-jit/run b/test/1958-transform-try-jit/run
new file mode 100755
index 0000000000..c6e62ae6cd
--- /dev/null
+++ b/test/1958-transform-try-jit/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+./default-run "$@" --jvmti
diff --git a/test/1958-transform-try-jit/src/Main.java b/test/1958-transform-try-jit/src/Main.java
new file mode 100644
index 0000000000..7f45c204fe
--- /dev/null
+++ b/test/1958-transform-try-jit/src/Main.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ art.Test1958.run();
+ }
+}
diff --git a/test/1958-transform-try-jit/src/art/Redefinition.java b/test/1958-transform-try-jit/src/art/Redefinition.java
new file mode 100644
index 0000000000..56d2938a01
--- /dev/null
+++ b/test/1958-transform-try-jit/src/art/Redefinition.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/1958-transform-try-jit/src/art/Test1958.java b/test/1958-transform-try-jit/src/art/Test1958.java
new file mode 100644
index 0000000000..100daa10ef
--- /dev/null
+++ b/test/1958-transform-try-jit/src/art/Test1958.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.reflect.Method;
+import java.util.Base64;
+
+public class Test1958 {
+ static class Runner {
+ public static String doSayHi() {
+ return sayHiHelper(true);
+ }
+
+ public static String dontSayHi() {
+ return sayHiHelper(false);
+ }
+
+ // We are trying to get the definition of Transform.sayHi inlined into this function.
+ public static String sayHiHelper(boolean sayHi) {
+ if (sayHi) {
+ return Transform.sayHi();
+ } else {
+ return "NOPE!";
+ }
+ }
+ }
+
+ static class Transform {
+ public static String sayHi() {
+ // Use lower 'h' to make sure the string will have a different string id
+ // than the transformation (the transformation code is the same except
+ // the actual printed String, which was making the test inacurately passing
+ // in JIT mode when loading the string from the dex cache, as the string ids
+ // of the two different strings were the same).
+ // We know the string ids will be different because lexicographically:
+ // "Goodbye" < "LTransform;" < "hello".
+ return "hello";
+ }
+ }
+
+ /**
+ * base64 encoded class/dex file for
+ * static class Transform {
+ * public static String sayHi() {
+ * return "Goodbye";
+ * }
+ * }
+ */
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADUAFQoABAANCAAOBwAQBwATAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1i" +
+ "ZXJUYWJsZQEABXNheUhpAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3VyY2VGaWxlAQANVGVz" +
+ "dDE5NTguamF2YQwABQAGAQAHR29vZGJ5ZQcAFAEAFmFydC9UZXN0MTk1OCRUcmFuc2Zvcm0BAAlU" +
+ "cmFuc2Zvcm0BAAxJbm5lckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAMYXJ0L1Rlc3QxOTU4" +
+ "ACAAAwAEAAAAAAACAAAABQAGAAEABwAAAB0AAQABAAAABSq3AAGxAAAAAQAIAAAABgABAAAABgAJ" +
+ "AAkACgABAAcAAAAbAAEAAAAAAAMSArAAAAABAAgAAAAGAAEAAAAIAAIACwAAAAIADAASAAAACgAB" +
+ "AAMADwARAAg=");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQCRmEaLPLzpKe+CHcDM8YhIJCPWwcFR5yegAwAAcAAAAHhWNBIAAAAAAAAAAPQCAAAR" +
+ "AAAAcAAAAAcAAAC0AAAAAgAAANAAAAAAAAAAAAAAAAMAAADoAAAAAQAAAAABAACAAgAAIAEAAFgB" +
+ "AABgAQAAaQEAAGwBAACGAQAAlgEAALoBAADaAQAA7gEAAAICAAARAgAAHAIAAB8CAAAsAgAAMgIA" +
+ "ADkCAABAAgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACwAAAAIAAAAFAAAAAAAAAAsAAAAGAAAA" +
+ "AAAAAAAAAQAAAAAAAAAAAA4AAAAEAAEAAAAAAAAAAAAAAAAABAAAAAAAAAAJAAAA5AIAAMYCAAAA" +
+ "AAAAAQAAAAAAAABUAQAAAwAAABoAAQARAAAAAQABAAEAAABQAQAABAAAAHAQAgAAAA4ABgAOAAgA" +
+ "DgAGPGluaXQ+AAdHb29kYnllAAFMABhMYXJ0L1Rlc3QxOTU4JFRyYW5zZm9ybTsADkxhcnQvVGVz" +
+ "dDE5NTg7ACJMZGFsdmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90" +
+ "YXRpb24vSW5uZXJDbGFzczsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7" +
+ "AA1UZXN0MTk1OC5qYXZhAAlUcmFuc2Zvcm0AAVYAC2FjY2Vzc0ZsYWdzAARuYW1lAAVzYXlIaQAF" +
+ "dmFsdWUAdX5+RDh7ImNvbXBpbGF0aW9uLW1vZGUiOiJkZWJ1ZyIsIm1pbi1hcGkiOjEsInNoYS0x" +
+ "IjoiNTFjYWNlMWFiZGQwOGIzMjBmMjVmYjgxMTZjMjQzMmIwMmYwOTI5NSIsInZlcnNpb24iOiIx" +
+ "LjQuNS1kZXYifQACAgEPGAECAwIMBAgNFwoAAAIAAICABLgCAQmgAgAAAAACAAAAtwIAAL0CAADY" +
+ "AgAAAAAAAAAAAAAAAAAADgAAAAAAAAABAAAAAAAAAAEAAAARAAAAcAAAAAIAAAAHAAAAtAAAAAMA" +
+ "AAACAAAA0AAAAAUAAAADAAAA6AAAAAYAAAABAAAAAAEAAAEgAAACAAAAIAEAAAMgAAACAAAAUAEA" +
+ "AAIgAAARAAAAWAEAAAQgAAACAAAAtwIAAAAgAAABAAAAxgIAAAMQAAACAAAA1AIAAAYgAAABAAAA" +
+ "5AIAAAAQAAABAAAA9AIAAA==");
+
+ public static void run() throws Exception {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
+ Method doSayHi = Runner.class.getDeclaredMethod("doSayHi");
+ Method dontSayHi = Runner.class.getDeclaredMethod("dontSayHi");
+ // Run the method enough times that the jit thinks it's interesting (default 10000).
+ for (int i = 0; i < 20000; i++) {
+ doSayHi.invoke(null);
+ dontSayHi.invoke(null);
+ }
+ // Sleep for 10 seconds to let the jit finish any work it's doing.
+ Thread.sleep(10 * 1000);
+ // Check what we get right now.
+ System.out.println("Before redefinition: " + doSayHi.invoke(null));
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ System.out.println("After redefinition: " + doSayHi.invoke(null));
+ }
+}
diff --git a/test/527-checker-array-access-split/src/Main.java b/test/527-checker-array-access-split/src/Main.java
index f83c924de9..f39b5e26a0 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 @@ public class Main {
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 0000000000..e69de29bb2
--- /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 0000000000..24f31e0e1b
--- /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 0000000000..7fc1273600
--- /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 8600a0a065..f8b92759c7 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 3aa6e563fc..f52d81a053 100644
--- a/test/624-checker-stringops/src/Main.java
+++ b/test/624-checker-stringops/src/Main.java
@@ -120,7 +120,7 @@ public class Main {
/// 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 @@ public class Main {
/// 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 b0a400ab75..8dd49aaa9b 100644
--- a/test/911-get-stack-trace/expected.txt
+++ b/test/911-get-stack-trace/expected.txt
@@ -21,7 +21,7 @@ From top
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 @@ From top
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 @@ From bottom
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 @@ Signal Catcher
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 @@ Signal Catcher
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 @@ ThreadListTraces Thread 8
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 @@ ThreadListTraces Thread 8
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 @@ ThreadListTraces Thread 8
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 065b854a6a..1bd56d1a53 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 --(thread)--> 3000@0 [size=132, length=-1]
---
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 @@ root@root --(thread)--> 3000@0 [size=132, length=-1]
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 --(thread)--> 3000@0 [size=132, length=-1]
---
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 @@ root@root --(thread)--> 1@1000 [size=16, length=-1]
---
---
---- 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 --(thread)--> 3000@0 [size=132, length=-1]
---
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 @@ root@root --(thread)--> 3000@0 [size=132, length=-1]
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 @@ root@root --(thread)--> 3000@0 [size=132, length=-1]
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 64c1d4f1b8..148aea48ae 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -59,6 +59,7 @@ ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/conscrypt-
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 900b1d7759..6488d241e8 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -31,6 +31,8 @@ GDB_ARGS=""
GDB_SERVER="gdbserver"
HAVE_IMAGE="y"
HOST="n"
+BIONIC="n"
+CREATE_ANDROID_ROOT="n"
INTERPRETER="n"
JIT="n"
INVOKE_WITH=""
@@ -209,6 +211,13 @@ while true; do
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 @@ if [ "$USE_JVM" = "n" ]; then
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 @@ if [ "$HOST" = "n" ]; then
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 @@ dm_cmdline="true"
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 @@ else
# 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 @@ else
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 229e2019dd..23631527e0 100755
--- a/test/run-test
+++ b/test/run-test
@@ -88,6 +88,8 @@ if [ -z "$ANDROID_HOST_OUT" ]; then
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 @@ while true; do
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 @@ elif [ "$runtime" = "art" ]; then
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 @@ if [ "$usage" = "yes" ]; then
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 0000000000..dba2d50e38
--- /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 0000000000..dfd54421fd
--- /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 0000000000..30e194ceda
--- /dev/null
+++ b/tools/timeout_dumper/timeout_dumper.cc
@@ -0,0 +1,609 @@
+/*
+ * 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 <iostream>
+#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 {
+ os << std::string(tmp, new_line - tmp + 1);
+
+ 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[] = {
+ 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
+
+template <typename T>
+bool WaitLoop(uint32_t max_wait_micros, const T& handler) {
+ constexpr uint32_t kWaitMicros = 10;
+ const size_t kMaxLoopCount = max_wait_micros / kWaitMicros;
+
+ for (size_t loop_count = 1; loop_count <= kMaxLoopCount; ++loop_count) {
+ bool ret;
+ if (handler(&ret)) {
+ return ret;
+ }
+ usleep(kWaitMicros);
+ }
+ return false;
+}
+
+bool WaitForMainSigStop(const std::atomic<bool>& saw_wif_stopped_for_main) {
+ auto handler = [&](bool* res) {
+ if (saw_wif_stopped_for_main) {
+ *res = true;
+ return true;
+ }
+ return false;
+ };
+ constexpr uint32_t kMaxWaitMicros = 30 * 1000 * 1000; // 30s wait.
+ return WaitLoop(kMaxWaitMicros, handler);
+}
+
+bool WaitForSigStopped(pid_t pid, uint32_t max_wait_micros) {
+ auto handler = [&](bool* res) {
+ int status;
+ pid_t rc = TEMP_FAILURE_RETRY(waitpid(pid, &status, WNOHANG));
+ if (rc == -1) {
+ PLOG(ERROR) << "Failed to waitpid for " << pid;
+ *res = false;
+ return true;
+ }
+ if (rc == pid) {
+ if (!(WIFSTOPPED(status))) {
+ LOG(ERROR) << "Did not get expected stopped signal for " << pid;
+ *res = false;
+ } else {
+ *res = true;
+ }
+ return true;
+ }
+ return false;
+ };
+ return WaitLoop(max_wait_micros, handler);
+}
+
+#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) {
+ // Use std::cerr to avoid the LOG prefix.
+ std::cerr << std::endl << "=== pid: " << pid << " tid: " << tid << " ===" << std::endl;
+
+ constexpr uint32_t kMaxWaitMicros = 1000 * 1000; // 1s.
+ if (pid != tid && !WaitForSigStopped(tid, kMaxWaitMicros)) {
+ LOG(ERROR) << "Failed to wait for sigstop on " << tid;
+ }
+
+ 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 << ")";
+ }
+ std::cerr << oss.str() << std::endl;
+ if (try_addr2line && addr2line_path != nullptr) {
+ addr2line::Addr2line(*addr2line_path,
+ it->map.name,
+ it->rel_pc,
+ std::cerr,
+ prefix,
+ &addr2line_state);
+ }
+ }
+
+ if (addr2line_state != nullptr) {
+ addr2line::Drain(0, prefix, &addr2line_state, std::cerr);
+ }
+}
+
+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)) {
+ LOG(ERROR) << "Did not receive SIGSTOP for pid " << forked_pid;
+ }
+
+ 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) {
+ 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();
+}